HHH-13863 Introduce the hibernate-graalvm module to share some GraalVM native image metadata
This commit is contained in:
parent
760386d2cf
commit
7d37e9f878
|
@ -45,6 +45,9 @@ ext {
|
|||
jaxbApiVersionOsgiRange = "[2.2,3)"
|
||||
jaxbRuntimeVersion = '2.3.1'
|
||||
|
||||
//GraalVM
|
||||
graalvmVersion = '19.3.1'
|
||||
|
||||
libraries = [
|
||||
// Ant
|
||||
ant: 'org.apache.ant:ant:1.8.2',
|
||||
|
@ -167,7 +170,9 @@ ext {
|
|||
wildfly_transaction_client : 'org.wildfly.transaction:wildfly-transaction-client:1.1.7.Final',
|
||||
|
||||
jboss_ejb_spec_jar : 'org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final',
|
||||
jboss_annotation_spec_jar : 'org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:1.0.0.Final'
|
||||
jboss_annotation_spec_jar : 'org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:1.0.0.Final',
|
||||
|
||||
graalvm_nativeimage : "org.graalvm.nativeimage:svm:${graalvmVersion}"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
apply from: rootProject.file( 'gradle/published-java-module.gradle' )
|
||||
|
||||
description = "Experimental extension to make it easier to compile applications into a GraalVM native image"
|
||||
|
||||
dependencies {
|
||||
//No need for transitive dependencies: this is all just metadata to be used as companion jar.
|
||||
compileOnly project( ':hibernate-core' )
|
||||
compileOnly( libraries.graalvm_nativeimage )
|
||||
testCompile( project( ':hibernate-core' ) )
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.graalvm.internal;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
import com.oracle.svm.core.annotate.AutomaticFeature;
|
||||
import org.graalvm.nativeimage.hosted.Feature;
|
||||
import org.graalvm.nativeimage.hosted.RuntimeReflection;
|
||||
|
||||
/**
|
||||
* This is a best effort, untested experimental GraalVM feature to help people getting Hibernate ORM
|
||||
* to work with GraalVM native images.
|
||||
* There are multiple reasons for this to be untested. One is that for tests to be effective they would
|
||||
* need very extensive coverage of all functionality: the point of this class being a list of all things
|
||||
* being initialized reflectively, it's not possible to ensure that the list is comprehensive without the
|
||||
* tests being comprehensive as well.
|
||||
* The other problem is that this is listing just that "static needs" of Hibernate ORM: it will very likely
|
||||
* also need to access reflectively the user's domain model and the various extension points, depending on
|
||||
* configurations. Such configuration - and especially the domain model - is dynamic by its very own nature,
|
||||
* and therefore this list is merely provided as a useful starting point, but it needs to be extended;
|
||||
* such extensions could be automated, or will need to be explicitly passed to the native-image arguments.
|
||||
* <p>
|
||||
* In conclusion, it's not possible to provide a fully comprehensive list: take this as a hopefully
|
||||
* useful building block.
|
||||
* </p>
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
@AutomaticFeature
|
||||
public class GraalVMStaticAutofeature implements Feature {
|
||||
|
||||
public void beforeAnalysis(Feature.BeforeAnalysisAccess before) {
|
||||
final Class<?>[] needsHavingSimpleConstructors = StaticClassLists.typesNeedingDefaultConstructorAccessible();
|
||||
final Class[] neddingAllConstructorsAccessible = StaticClassLists.typesNeedingAllConstructorsAccessible();
|
||||
//Size formula is just a reasonable guess:
|
||||
ArrayList<Executable> executables = new ArrayList<>( needsHavingSimpleConstructors.length + neddingAllConstructorsAccessible.length * 3 );
|
||||
for ( Class c : needsHavingSimpleConstructors ) {
|
||||
executables.add( ReflectHelper.getDefaultConstructor( c ) );
|
||||
}
|
||||
for ( Class c : neddingAllConstructorsAccessible ) {
|
||||
for ( Constructor declaredConstructor : c.getDeclaredConstructors() ) {
|
||||
executables.add( declaredConstructor );
|
||||
}
|
||||
}
|
||||
RuntimeReflection.register( needsHavingSimpleConstructors );
|
||||
RuntimeReflection.register( neddingAllConstructorsAccessible );
|
||||
RuntimeReflection.register( StaticClassLists.typesNeedingArrayCopy() );
|
||||
RuntimeReflection.register( executables.toArray(new Executable[0]) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.graalvm.internal;
|
||||
|
||||
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
|
||||
import org.hibernate.type.EnumType;
|
||||
|
||||
/**
|
||||
* The place to list all "static" types we know of that need to be possible to
|
||||
* construct at runtime via reflection.
|
||||
* This is useful for GraalVM native images - but is not intenteded to be an
|
||||
* exhaustive list: take these as an helpful starting point.
|
||||
*/
|
||||
final class StaticClassLists {
|
||||
|
||||
public static Class[] typesNeedingAllConstructorsAccessible() {
|
||||
return new Class[] {
|
||||
//The CoreMessageLogger is sometimes looked up without it necessarily being a field, so we're
|
||||
//not processing it the same way as other Logger lookups.
|
||||
org.hibernate.internal.CoreMessageLogger_$logger.class,
|
||||
org.hibernate.tuple.component.PojoComponentTuplizer.class,
|
||||
org.hibernate.tuple.component.DynamicMapComponentTuplizer.class,
|
||||
org.hibernate.tuple.entity.DynamicMapEntityTuplizer.class,
|
||||
org.hibernate.persister.collection.OneToManyPersister.class,
|
||||
org.hibernate.persister.collection.BasicCollectionPersister.class,
|
||||
org.hibernate.persister.entity.JoinedSubclassEntityPersister.class,
|
||||
org.hibernate.persister.entity.UnionSubclassEntityPersister.class,
|
||||
org.hibernate.persister.entity.SingleTableEntityPersister.class,
|
||||
org.hibernate.tuple.entity.PojoEntityTuplizer.class,
|
||||
//ANTLR special ones:
|
||||
org.hibernate.hql.internal.ast.tree.EntityJoinFromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapKeyEntityFromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.ComponentJoin.class,
|
||||
};
|
||||
}
|
||||
|
||||
public static Class[] typesNeedingDefaultConstructorAccessible() {
|
||||
return new Class[] {
|
||||
//Support for @OrderBy
|
||||
org.hibernate.sql.ordering.antlr.NodeSupport.class,
|
||||
org.hibernate.sql.ordering.antlr.OrderByFragment.class,
|
||||
org.hibernate.sql.ordering.antlr.SortSpecification.class,
|
||||
org.hibernate.sql.ordering.antlr.OrderingSpecification.class,
|
||||
org.hibernate.sql.ordering.antlr.CollationSpecification.class,
|
||||
org.hibernate.sql.ordering.antlr.SortKey.class,
|
||||
|
||||
//ANTLR tokens:
|
||||
org.hibernate.hql.internal.ast.tree.SelectClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.HqlSqlWalkerNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.MethodNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.UnaryLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.NullNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IntoClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.UpdateStatement.class,
|
||||
org.hibernate.hql.internal.ast.tree.SelectExpressionImpl.class,
|
||||
org.hibernate.hql.internal.ast.tree.CastFunctionNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.DeleteStatement.class,
|
||||
org.hibernate.hql.internal.ast.tree.SqlNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.SearchedCaseNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.FromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.JavaConstantNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.SqlFragment.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapKeyNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.ImpliedFromElement.class,
|
||||
org.hibernate.hql.internal.ast.tree.IsNotNullLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.InsertStatement.class,
|
||||
org.hibernate.hql.internal.ast.tree.UnaryArithmeticNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.CollectionFunction.class,
|
||||
org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.CountNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IsNullLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IdentNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.ParameterNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapEntryNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.MapValueNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.IndexNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.DotNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.ResultVariableRefNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.BetweenOperatorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.AggregateNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.QueryNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.BooleanLiteralNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.SimpleCaseNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.OrderByClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.FromClause.class,
|
||||
org.hibernate.hql.internal.ast.tree.ConstructorNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.LiteralNode.class,
|
||||
org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode.class,
|
||||
|
||||
//Various well known needs:
|
||||
|
||||
org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl.class,
|
||||
org.hibernate.id.enhanced.SequenceStyleGenerator.class,
|
||||
org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl.class,
|
||||
org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl.class,
|
||||
EnumType.class,
|
||||
MultipleLinesSqlCommandExtractor.class,
|
||||
org.hibernate.hql.internal.ast.HqlToken.class,
|
||||
org.hibernate.hql.internal.ast.tree.Node.class,
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static Class[] typesNeedingArrayCopy() {
|
||||
return new Class[] {
|
||||
//Eventlisteners need to be registered for reflection to allow creation via Array#newInstance ;
|
||||
// types need to be in synch with those declared in org.hibernate.event.spi.EventType
|
||||
org.hibernate.event.spi.LoadEventListener[].class,
|
||||
org.hibernate.event.spi.ResolveNaturalIdEventListener[].class,
|
||||
org.hibernate.event.spi.InitializeCollectionEventListener[].class,
|
||||
org.hibernate.event.spi.SaveOrUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PersistEventListener[].class,
|
||||
org.hibernate.event.spi.MergeEventListener[].class,
|
||||
org.hibernate.event.spi.DeleteEventListener[].class,
|
||||
org.hibernate.event.spi.ReplicateEventListener[].class,
|
||||
org.hibernate.event.spi.FlushEventListener[].class,
|
||||
org.hibernate.event.spi.AutoFlushEventListener[].class,
|
||||
org.hibernate.event.spi.DirtyCheckEventListener[].class,
|
||||
org.hibernate.event.spi.FlushEntityEventListener[].class,
|
||||
org.hibernate.event.spi.ClearEventListener[].class,
|
||||
org.hibernate.event.spi.EvictEventListener[].class,
|
||||
org.hibernate.event.spi.LockEventListener[].class,
|
||||
org.hibernate.event.spi.RefreshEventListener[].class,
|
||||
org.hibernate.event.spi.PreLoadEventListener[].class,
|
||||
org.hibernate.event.spi.PreDeleteEventListener[].class,
|
||||
org.hibernate.event.spi.PreUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PreInsertEventListener[].class,
|
||||
org.hibernate.event.spi.PostLoadEventListener[].class,
|
||||
org.hibernate.event.spi.PostDeleteEventListener[].class,
|
||||
org.hibernate.event.spi.PostUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PostInsertEventListener[].class,
|
||||
org.hibernate.event.spi.PreCollectionRecreateEventListener[].class,
|
||||
org.hibernate.event.spi.PreCollectionRemoveEventListener[].class,
|
||||
org.hibernate.event.spi.PreCollectionUpdateEventListener[].class,
|
||||
org.hibernate.event.spi.PostCollectionRecreateEventListener[].class,
|
||||
org.hibernate.event.spi.PostCollectionRemoveEventListener[].class,
|
||||
org.hibernate.event.spi.PostCollectionUpdateEventListener[].class
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.graalvm.internal;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BasicConstructorsAvailableTest {
|
||||
|
||||
@Test
|
||||
public void checkNonDefaultConstructorsCanBeLoaded() {
|
||||
Class[] classes = StaticClassLists.typesNeedingAllConstructorsAccessible();
|
||||
for ( Class c : classes ) {
|
||||
Constructor[] declaredConstructors = c.getDeclaredConstructors();
|
||||
Assert.assertTrue( declaredConstructors.length > 0 );
|
||||
if ( declaredConstructors.length == 1 ) {
|
||||
//If there's only one, let's check that this class wasn't placed in the wrong cathegory:
|
||||
Assert.assertTrue( declaredConstructors[0].getParameterCount() > 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDefaultConstructorsAreAvailable() {
|
||||
Class[] classes = StaticClassLists.typesNeedingDefaultConstructorAccessible();
|
||||
for ( Class c : classes ) {
|
||||
Constructor constructor = ReflectHelper.getDefaultConstructor( c );
|
||||
Assert.assertNotNull( "Failed for class: " + c.getName(), constructor );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkArraysAreArrays() {
|
||||
Class[] classes = StaticClassLists.typesNeedingArrayCopy();
|
||||
for ( Class c : classes ) {
|
||||
Assert.assertTrue( "Wrong category for type: " + c.getName(), c.isArray() );
|
||||
Constructor[] constructors = c.getConstructors();
|
||||
Assert.assertEquals( 0, constructors.length );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,7 @@ include 'hibernate-infinispan'
|
|||
include 'hibernate-jipijapa'
|
||||
|
||||
include 'hibernate-orm-modules'
|
||||
include 'hibernate-graalvm'
|
||||
|
||||
if ( JavaVersion.current().isJava11Compatible() ) {
|
||||
include 'hibernate-integrationtest-java-modules'
|
||||
|
|
Loading…
Reference in New Issue