From 5f19f206b1bb630e341c98b79a801bf57381912e Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sat, 27 Sep 2025 21:26:24 +0200 Subject: [PATCH] light code improvements to id.uuid package --- .../id/uuid/CustomVersionOneStrategy.java | 47 +++++++++-------- .../java/org/hibernate/id/uuid/Helper.java | 8 +-- .../org/hibernate/id/uuid/UuidGenerator.java | 52 ++++++++----------- .../id/uuid/UuidVersion6Strategy.java | 24 +++------ .../id/uuid/UuidVersion7Strategy.java | 23 ++++---- 5 files changed, 70 insertions(+), 84 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/uuid/CustomVersionOneStrategy.java b/hibernate-core/src/main/java/org/hibernate/id/uuid/CustomVersionOneStrategy.java index cdfa3cb4675b..00a7b1750547 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/uuid/CustomVersionOneStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/id/uuid/CustomVersionOneStrategy.java @@ -11,6 +11,12 @@ import org.hibernate.internal.build.AllowSysOut; import org.hibernate.internal.util.BytesHelper; +import static java.lang.System.arraycopy; +import static java.lang.System.currentTimeMillis; +import static org.hibernate.id.uuid.Helper.getAddressBytes; +import static org.hibernate.id.uuid.Helper.getCountBytes; +import static org.hibernate.id.uuid.Helper.getJvmIdentifierBytes; + /** * Applies a version 1 (time-based) generation strategy (using ip address rather than mac address) but applies them in a * different layout. The strategy is very similar to the legacy {@link org.hibernate.id.UUIDHexGenerator} id generator @@ -31,22 +37,21 @@ public int getGeneratedVersion() { public CustomVersionOneStrategy() { // generate the "most significant bits" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - byte[] hiBits = new byte[8]; - // use address as first 32 bits (8 * 4 bytes) - System.arraycopy( Helper.getAddressBytes(), 0, hiBits, 0, 4 ); + final byte[] hiBits = new byte[8]; + // use address as the first 32 bits (8 * 4 bytes) + arraycopy( getAddressBytes(), 0, hiBits, 0, 4 ); // use the "jvm identifier" as the next 32 bits - System.arraycopy( Helper.getJvmIdentifierBytes(), 0, hiBits, 4, 4 ); + arraycopy( getJvmIdentifierBytes(), 0, hiBits, 4, 4 ); // set the version (rfc term) appropriately hiBits[6] &= 0x0f; hiBits[6] |= 0x10; - mostSignificantBits = BytesHelper.asLong( hiBits ); } @Override public UUID generateUuid(SharedSessionContractImplementor session) { - long leastSignificantBits = generateLeastSignificantBits( System.currentTimeMillis() ); - return new UUID( mostSignificantBits, leastSignificantBits ); + return new UUID( mostSignificantBits, + generateLeastSignificantBits( currentTimeMillis() ) ); } @Override @@ -59,33 +64,31 @@ public long getMostSignificantBits() { } public static long generateLeastSignificantBits(long seed) { - byte[] loBits = new byte[8]; - - short hiTime = (short) ( seed >>> 32 ); - int loTime = (int) seed; - System.arraycopy( BytesHelper.fromShort( hiTime ), 0, loBits, 0, 2 ); - System.arraycopy( BytesHelper.fromInt( loTime ), 0, loBits, 2, 4 ); - System.arraycopy( Helper.getCountBytes(), 0, loBits, 6, 2 ); + final byte[] loBits = new byte[8]; + final short hiTime = (short) ( seed >>> 32 ); + final int loTime = (int) seed; + arraycopy( BytesHelper.fromShort( hiTime ), 0, loBits, 0, 2 ); + arraycopy( BytesHelper.fromInt( loTime ), 0, loBits, 2, 4 ); + arraycopy( getCountBytes(), 0, loBits, 6, 2 ); loBits[0] &= 0x3f; - loBits[0] |= ((byte)2 << (byte)6 ); - + loBits[0] |= ((byte)2 << (byte)6); return BytesHelper.asLong( loBits ); } @AllowSysOut public static void main(String[] args) { - CustomVersionOneStrategy strategy = new CustomVersionOneStrategy(); + final var strategy = new CustomVersionOneStrategy(); for ( int i = 0; i < 1000; i++ ) { System.out.println( "Generation # " + i + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" ); byte[] loBits = new byte[8]; - long sysTime = System.currentTimeMillis(); - short hiTime = (short) ( System.currentTimeMillis() >>> 32 ); + long sysTime = currentTimeMillis(); + short hiTime = (short) ( currentTimeMillis() >>> 32 ); int loTime = (int) sysTime; - System.arraycopy( BytesHelper.fromShort( hiTime ), 0, loBits, 0, 2 ); - System.arraycopy( BytesHelper.fromInt( loTime ), 0, loBits, 2, 4 ); - System.arraycopy( Helper.getCountBytes(), 0, loBits, 6, 2 ); + arraycopy( BytesHelper.fromShort( hiTime ), 0, loBits, 0, 2 ); + arraycopy( BytesHelper.fromInt( loTime ), 0, loBits, 2, 4 ); + arraycopy( getCountBytes(), 0, loBits, 6, 2 ); System.out.println( " before bit setting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" ); System.out.println( " loBits[0] : " + BytesHelper.toBinaryString( loBits[0] ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/id/uuid/Helper.java b/hibernate-core/src/main/java/org/hibernate/id/uuid/Helper.java index dbf53971ead4..a8ae4f6f9fdf 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/uuid/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/id/uuid/Helper.java @@ -98,15 +98,15 @@ public static byte[] getCountBytes() { // Helper methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public static String format(int value) { - final String formatted = Integer.toHexString( value ); - StringBuilder buf = new StringBuilder( "00000000" ); + final var formatted = Integer.toHexString( value ); + final var buf = new StringBuilder( "00000000" ); buf.replace( 8 - formatted.length(), 8, formatted ); return buf.toString(); } public static String format(short value) { - String formatted = Integer.toHexString( value ); - StringBuilder buf = new StringBuilder( "0000" ); + final var formatted = Integer.toHexString( value ); + final var buf = new StringBuilder( "0000" ); buf.replace( 4 - formatted.length(), 4, formatted ); return buf.toString(); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidGenerator.java index a05a7f5573a0..c6f786a8664e 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidGenerator.java @@ -57,9 +57,7 @@ public UuidGenerator( org.hibernate.annotations.UuidGenerator config, MemberDetails memberDetails) { generator = determineValueGenerator( config, memberDetails.getDeclaringType().getName(), memberDetails.getName() ); - - final Class memberType = memberDetails.getType().determineRawClass().toJavaClass(); - valueTransformer = determineProperTransformer( memberType ); + valueTransformer = determineProperTransformer( memberDetails.getType().determineRawClass().toJavaClass() ); } @Internal @@ -67,9 +65,7 @@ public UuidGenerator( org.hibernate.annotations.UuidGenerator config, Member idMember) { generator = determineValueGenerator( config, idMember.getDeclaringClass().getName(), idMember.getName() ); - - final Class propertyType = getPropertyType( idMember ); - this.valueTransformer = determineProperTransformer( propertyType ); + valueTransformer = determineProperTransformer( getPropertyType( idMember ) ); } public UuidGenerator( @@ -106,16 +102,20 @@ private static UuidValueGenerator determineValueGenerator( org.hibernate.annotations.UuidGenerator config, String memberDeclaringClassName, String memberName) { - if ( config != null ) { + if ( config == null ) { + return StandardRandomStrategy.INSTANCE; + } + else { // there is an annotation + final var style = config.style(); if ( config.algorithm() != UuidValueGenerator.class ) { // the annotation specified a custom algorithm - if ( config.style() != AUTO ) { + if ( style != AUTO ) { throw new MappingException( String.format( Locale.ROOT, - "Style [%s] should not be specified with custom UUID value generator : %s.%s", - config.style().name(), + "Style [%s] should not be specified with custom UUID value generator: %s.%s", + style.name(), memberDeclaringClassName, memberName ) @@ -123,22 +123,13 @@ private static UuidValueGenerator determineValueGenerator( } return instantiateCustomGenerator( config.algorithm() ); } - if ( config.style() == TIME ) { - return new CustomVersionOneStrategy(); - } - if ( config.style() == VERSION_6 ) { - return UuidVersion6Strategy.INSTANCE; - } - if ( config.style() == VERSION_7 ) { - return UuidVersion7Strategy.INSTANCE; - } - // NOTE : AUTO falls through + return switch ( style ) { + case TIME -> new CustomVersionOneStrategy(); + case VERSION_6 -> UuidVersion6Strategy.INSTANCE; + case VERSION_7 -> UuidVersion7Strategy.INSTANCE; + default -> StandardRandomStrategy.INSTANCE; + }; } - - // Either - - // 1. there is no annotation - // 2. the annotation specified AUTO (with no custom algorithm) - return StandardRandomStrategy.INSTANCE; } private static UuidValueGenerator instantiateCustomGenerator(Class algorithmClass) { @@ -154,15 +145,14 @@ private ValueTransformer determineProperTransformer(Class propertyType) { if ( UUID.class.isAssignableFrom( propertyType ) ) { return UUIDJavaType.PassThroughTransformer.INSTANCE; } - - if ( String.class.isAssignableFrom( propertyType ) ) { + else if ( String.class.isAssignableFrom( propertyType ) ) { return UUIDJavaType.ToStringTransformer.INSTANCE; } - - if ( byte[].class.isAssignableFrom( propertyType ) ) { + else if ( byte[].class.isAssignableFrom( propertyType ) ) { return UUIDJavaType.ToBytesTransformer.INSTANCE; } - - throw new HibernateException( "Unanticipated return type [" + propertyType.getName() + "] for UUID conversion" ); + else { + throw new HibernateException( "Unanticipated return type [" + propertyType.getName() + "] for UUID conversion" ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion6Strategy.java b/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion6Strategy.java index fe2f6f697e97..5ce09226778d 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion6Strategy.java +++ b/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion6Strategy.java @@ -40,23 +40,16 @@ public static class Holder { static final long EPOCH_1582_SECONDS = LocalDate.of( 1582, 10, 15 ) .atStartOfDay( ZoneId.of( "UTC" ) ) .toInstant().getEpochSecond(); - } private record State(long lastTimestamp, int lastSequence) { public State getNextState() { final long now = instantToTimestamp(); - if ( this.lastTimestamp < now ) { - return new State( - now, - randomSequence() - ); + if ( lastTimestamp < now ) { + return new State( now, randomSequence() ); } else if ( lastSequence == 0x3FFF ) { - return new State( - this.lastTimestamp + 1, - randomSequence() - ); + return new State( lastTimestamp + 1, randomSequence() ); } else { return new State( lastTimestamp, lastSequence + 1 ); @@ -68,7 +61,7 @@ private static int randomSequence() { } private static long instantToTimestamp() { - final Instant instant = Instant.now(); + final var instant = Instant.now(); final long seconds = instant.getEpochSecond() - Holder.EPOCH_1582_SECONDS; return seconds * 10_000_000 + instant.getNano() / 100; } @@ -101,20 +94,19 @@ public UUID generateUUID(final SharedSessionContractImplementor session) { @Override public UUID generateUuid(final SharedSessionContractImplementor session) { - final State state = lastState.updateAndGet( State::getNextState ); - + final var state = lastState.updateAndGet( State::getNextState ); return new UUID( - // MSB bits 0-47 - most significant 32 bits of the 60-bit starting timestamp + // MSB bits 0-47 - the most significant 32 bits of the 60-bit starting timestamp state.lastTimestamp << 4 & 0xFFFF_FFFF_FFFF_0000L // MSB bits 48-51 - version = 6 | 0x6000L - // MSB bits 52-63 - least significant 12 bits from the 60-bit starting timestamp + // MSB bits 52-63 - the least significant 12 bits from the 60-bit starting timestamp | state.lastTimestamp & 0x0FFFL, // LSB bits 0-1 - variant = 4 0x8000_0000_0000_0000L // LSB bits 2-15 - clock sequence | (long) state.lastSequence << 48 - // LSB bits 16-63 - pseudorandom data, least significant bit of the first octet is set to 1 + // LSB bits 16-63 - pseudorandom data, the least significant bit of the first octet is set to 1 | randomNode() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion7Strategy.java b/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion7Strategy.java index 2f185a03eeda..35ff129960b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion7Strategy.java +++ b/hibernate-core/src/main/java/org/hibernate/id/uuid/UuidVersion7Strategy.java @@ -42,7 +42,6 @@ public class UuidVersion7Strategy implements UUIDGenerationStrategy, UuidValueGe @Internal public static class Holder { private static final SecureRandom numberGenerator = new SecureRandom(); - } public record State(Instant lastTimestamp, long lastSequence, long nanos) { @@ -60,20 +59,23 @@ private static long nanos(Instant timestamp) { } public State getNextState() { - final Instant now = Instant.now(); - if ( lastTimestamp.toEpochMilli() < now.toEpochMilli() || - lastTimestamp.toEpochMilli() == now.toEpochMilli() && nanos < nanos( now ) ) { + final var now = Instant.now(); + if ( lastTimestampEarlierThan( now ) ) { return new State( now, randomSequence() ); } - final long nextSequence = lastSequence + Holder.numberGenerator.nextLong( 0xFFFF_FFFFL ); - if ( nextSequence > MAX_RANDOM_SEQUENCE ) { - return new State( lastTimestamp.plusNanos( 250 ), randomSequence() ); - } else { - return new State( lastTimestamp, nextSequence ); + final long nextSequence = lastSequence + Holder.numberGenerator.nextLong( 0xFFFF_FFFFL ); + return nextSequence > MAX_RANDOM_SEQUENCE + ? new State( lastTimestamp.plusNanos( 250 ), randomSequence() ) + : new State( lastTimestamp, nextSequence ); } } + private boolean lastTimestampEarlierThan(Instant now) { + return lastTimestamp.toEpochMilli() < now.toEpochMilli() + || lastTimestamp.toEpochMilli() == now.toEpochMilli() && nanos < nanos( now ); + } + private static long randomSequence() { return Holder.numberGenerator.nextLong( MAX_RANDOM_SEQUENCE ); } @@ -106,8 +108,7 @@ public UUID generateUUID(final SharedSessionContractImplementor session) { @Override public UUID generateUuid(final SharedSessionContractImplementor session) { - final State state = lastState.updateAndGet( State::getNextState ); - + final var state = lastState.updateAndGet( State::getNextState ); return new UUID( // MSB bits 0-47 - 48-bit big-endian unsigned number of the Unix Epoch timestamp in milliseconds state.millis() << 16 & 0xFFFF_FFFF_FFFF_0000L