Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
public class UuidVersion6Strategy implements UUIDGenerationStrategy, UuidValueGenerator {
public static final UuidVersion6Strategy INSTANCE = new UuidVersion6Strategy();

private static class Holder {
@Internal
public static class Holder {
static final SecureRandom numberGenerator = new SecureRandom();
static final long EPOCH_1582_SECONDS = LocalDate.of( 1582, 10, 15 )
.atStartOfDay( ZoneId.of( "UTC" ) )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public class UuidVersion7Strategy implements UUIDGenerationStrategy, UuidValueGe

public static final UuidVersion7Strategy INSTANCE = new UuidVersion7Strategy();

private static class Holder {
@Internal
public static class Holder {
private static final SecureRandom numberGenerator = new SecureRandom();

}
Expand Down Expand Up @@ -82,7 +83,7 @@ private static long randomSequence() {

@Internal
public UuidVersion7Strategy() {
this( Instant.EPOCH, Holder.numberGenerator.nextLong( MAX_RANDOM_SEQUENCE ) );
this( Instant.EPOCH, Long.MIN_VALUE );
}

@Internal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.lang.reflect.Executable;
import java.util.ArrayList;

import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
import org.hibernate.internal.util.ReflectHelper;

import org.graalvm.nativeimage.hosted.Feature;
Expand Down Expand Up @@ -36,6 +37,7 @@ public class GraalVMStaticFeature implements Feature {
public void beforeAnalysis(Feature.BeforeAnalysisAccess before) {
final Class<?>[] needsHavingSimpleConstructors = StaticClassLists.typesNeedingDefaultConstructorAccessible();
final Class<?>[] needingAllConstructorsAccessible = StaticClassLists.typesNeedingAllConstructorsAccessible();
final Class<?>[] typesNeedingRuntimeInitialization = StaticClassLists.typesNeedingRuntimeInitialization();
//Size formula is just a reasonable guess:
ArrayList<Executable> executables = new ArrayList<>( needsHavingSimpleConstructors.length + needingAllConstructorsAccessible.length * 3 );
for ( Class<?> c : needsHavingSimpleConstructors ) {
Expand All @@ -50,6 +52,8 @@ public void beforeAnalysis(Feature.BeforeAnalysisAccess before) {
RuntimeReflection.register( needingAllConstructorsAccessible );
RuntimeReflection.register( StaticClassLists.typesNeedingArrayCopy() );
RuntimeReflection.register( executables.toArray(new Executable[0]) );

RuntimeClassInitialization.initializeAtRunTime( typesNeedingRuntimeInitialization );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,14 @@ public static Class[] typesNeedingArrayCopy() {
};
}

/**
* The classes listed below use a SecureRandom. We need to avoid static initialization at build time of these,
* for it will trigger an error in GraalVM native images.
*/
public static Class<?>[] typesNeedingRuntimeInitialization() {
return new Class[] {
org.hibernate.id.uuid.UuidVersion6Strategy.Holder.class,
org.hibernate.id.uuid.UuidVersion7Strategy.Holder.class,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import org.hibernate.Session;
import org.hibernate.event.spi.EventType;
import org.hibernate.id.uuid.UuidVersion6Strategy;
import org.hibernate.id.uuid.UuidVersion7Strategy;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
Expand All @@ -37,6 +39,38 @@ public static void index() throws IOException {
hibernateIndex = JandexTestUtils.indexJar( Session.class );
}

@Nested
// Related Jira issue: https://hibernate.atlassian.net/browse/HHH-18974
class TypesNeedingRuntimeInitialization {
@ParameterizedTest
@EnumSource(TypesNeedingRuntimeInitialization_Category.class)
void containsAllExpectedClasses(TypesNeedingRuntimeInitialization_Category category) {
assertThat( StaticClassLists.typesNeedingRuntimeInitialization() )
.containsAll( category.classes().collect( Collectors.toSet() ) );
}

@Test
void meta_noMissingTestCategory() {
assertThat( Arrays.stream( TypesNeedingRuntimeInitialization_Category.values() ).flatMap( TypesNeedingRuntimeInitialization_Category::classes ) )
.as( "If this fails, a category is missing in " + TypesNeedingRuntimeInitialization_Category.class )
.contains( StaticClassLists.typesNeedingRuntimeInitialization() );
}
}

enum TypesNeedingRuntimeInitialization_Category {
UUID_STRATGY_HOLDERS_USING_SECURE_RANDOM {
@Override
Stream<Class<?>> classes() {
return Stream.of(
UuidVersion6Strategy.Holder.class,
UuidVersion7Strategy.Holder.class
);
}
};

abstract Stream<Class<?>> classes();
}

@Nested
class TypesNeedingAllConstructorsAccessible {
@ParameterizedTest
Expand Down
Loading