HHH-16190 Update the GraalVM module to match the reflective needs of StandardStack
This commit is contained in:
parent
f2deb8f58e
commit
f16a28b95a
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import org.hibernate.internal.build.AllowSysOut;
|
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
|
||||||
|
|
||||||
import org.graalvm.nativeimage.hosted.Feature;
|
|
||||||
import org.graalvm.nativeimage.hosted.RuntimeReflection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This registers all ANTLR parser nodes for reflection, something that is necessary
|
|
||||||
* as the HQL parser's inner workings are based on reflection.
|
|
||||||
* This is different than the "static" registrations of {@link GraalVMStaticFeature}
|
|
||||||
* as we only register these if the HQL parser is actually reachable: some particularly
|
|
||||||
* simple applications might not need dynamic queries being expressed in string form,
|
|
||||||
* and for such cases the reflective registrations can be skipped.
|
|
||||||
*
|
|
||||||
* At time of writing, this is particularly unlikely to be effective as Hibernate ORM
|
|
||||||
* requires the parsers during bootstrap, but there is reasonable hope that this might
|
|
||||||
* be improved on, and can already be used by framework integrations which are able
|
|
||||||
* to bypass the traditional boot sequence.
|
|
||||||
*
|
|
||||||
* @author Sanne Grinovero
|
|
||||||
*/
|
|
||||||
public final class QueryParsingSupport implements Feature {
|
|
||||||
|
|
||||||
private final AtomicBoolean triggered = new AtomicBoolean( false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To set this, add `-J-Dorg.hibernate.graalvm.diagnostics=true` to the native-image parameters
|
|
||||||
*/
|
|
||||||
private static final boolean log = Boolean.getBoolean( "org.hibernate.graalvm.diagnostics" );
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeAnalysis(BeforeAnalysisAccess access) {
|
|
||||||
Class<?> lexerClazz = access.findClassByName("org.hibernate.grammars.hql.HqlLexer");
|
|
||||||
Class<?> parserClazz = access.findClassByName("org.hibernate.grammars.hql.HqlParser");
|
|
||||||
access.registerReachabilityHandler(this::enableHQLSupport, lexerClazz);
|
|
||||||
access.registerReachabilityHandler(this::enableHQLSupport, parserClazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Hibernate ORM's support for HQL Parser in GraalVM";
|
|
||||||
}
|
|
||||||
|
|
||||||
@AllowSysOut
|
|
||||||
private void enableHQLSupport(DuringAnalysisAccess duringAnalysisAccess) {
|
|
||||||
final boolean needsEnablingYet = triggered.compareAndSet( false, true );
|
|
||||||
if ( needsEnablingYet ) {
|
|
||||||
if ( log ) {
|
|
||||||
System.out.println( "Hibernate ORM 's automatic feature for GraalVM native images: enabling support for HQL query parsing" );
|
|
||||||
}
|
|
||||||
enableAntlrParsersSupport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableAntlrParsersSupport() {
|
|
||||||
final Class<?>[] needsHavingSimpleConstructors = typesNeedingDefaultConstructorAccessible();
|
|
||||||
final Class[] neddingAllConstructorsAccessible = 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( executables.toArray(new Executable[0]) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Class[] typesNeedingAllConstructorsAccessible() {
|
|
||||||
return new 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:
|
|
||||||
// antlr.CommonToken.class,
|
|
||||||
// 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,
|
|
||||||
|
|
||||||
//Special tokens:
|
|
||||||
// org.hibernate.hql.internal.ast.HqlToken.class,
|
|
||||||
// org.hibernate.hql.internal.ast.tree.Node.class,
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -6,6 +6,24 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.graalvm.internal;
|
package org.hibernate.graalvm.internal;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.hibernate.graph.internal.parse.SubGraphGenerator;
|
||||||
|
import org.hibernate.graph.spi.AttributeNodeImplementor;
|
||||||
|
import org.hibernate.graph.spi.GraphImplementor;
|
||||||
|
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
|
||||||
|
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
|
||||||
|
import org.hibernate.query.sqm.spi.ParameterDeclarationContext;
|
||||||
|
import org.hibernate.query.sqm.sql.FromClauseIndex;
|
||||||
|
import org.hibernate.sql.ast.Clause;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
|
||||||
|
import org.hibernate.sql.ast.tree.Statement;
|
||||||
|
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||||
import org.hibernate.tool.schema.internal.script.MultiLineSqlScriptExtractor;
|
import org.hibernate.tool.schema.internal.script.MultiLineSqlScriptExtractor;
|
||||||
import org.hibernate.type.EnumType;
|
import org.hibernate.type.EnumType;
|
||||||
|
|
||||||
|
@ -76,7 +94,26 @@ final class StaticClassLists {
|
||||||
org.hibernate.event.spi.PreCollectionUpdateEventListener[].class,
|
org.hibernate.event.spi.PreCollectionUpdateEventListener[].class,
|
||||||
org.hibernate.event.spi.PostCollectionRecreateEventListener[].class,
|
org.hibernate.event.spi.PostCollectionRecreateEventListener[].class,
|
||||||
org.hibernate.event.spi.PostCollectionRemoveEventListener[].class,
|
org.hibernate.event.spi.PostCollectionRemoveEventListener[].class,
|
||||||
org.hibernate.event.spi.PostCollectionUpdateEventListener[].class
|
org.hibernate.event.spi.PostCollectionUpdateEventListener[].class,
|
||||||
|
//And other array types, necessary for allocation of generified instances of org.hibernate.internal.util.collections.StandardStack:
|
||||||
|
//TODO can this list be tested for consistency with the core module? Or generated? e.g. could use Jandex?
|
||||||
|
AttributeNodeImplementor[].class,
|
||||||
|
Clause[].class,
|
||||||
|
DotIdentifierConsumer[].class,
|
||||||
|
FetchParent[].class,
|
||||||
|
FromClauseIndex[].class,
|
||||||
|
Function[].class,
|
||||||
|
GraphImplementor[].class,
|
||||||
|
JdbcValuesSourceProcessingState[].class,
|
||||||
|
List[].class,
|
||||||
|
Map.Entry[].class,
|
||||||
|
ParameterDeclarationContext[].class,
|
||||||
|
QueryPart[].class,
|
||||||
|
SqlAstProcessingState[].class,
|
||||||
|
SqmCreationProcessingState[].class,
|
||||||
|
Statement[].class,
|
||||||
|
SubGraphGenerator[].class,
|
||||||
|
Supplier[].class,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue