HHH-17460 - Ongoing JPA 32 work

This commit is contained in:
Andrea Boriero 2024-04-02 13:40:41 +02:00 committed by Steve Ebersole
parent ff640b23e9
commit 3465ab7c97
1 changed files with 58 additions and 178 deletions

View File

@ -15,16 +15,13 @@ import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.Remove;
import org.hibernate.annotations.CacheModeType; import org.hibernate.annotations.CacheModeType;
import org.hibernate.annotations.FlushModeType; import org.hibernate.annotations.FlushModeType;
import org.hibernate.annotations.HQLSelect; import org.hibernate.annotations.HQLSelect;
import org.hibernate.annotations.SQLSelect; import org.hibernate.annotations.SQLSelect;
import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor;
import org.hibernate.annotations.common.annotationfactory.AnnotationFactory;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.boot.internal.NamedHqlQueryDefinitionImpl; import org.hibernate.boot.internal.NamedHqlQueryDefinitionImpl;
import org.hibernate.boot.internal.NamedProcedureCallDefinitionImpl; import org.hibernate.boot.internal.NamedProcedureCallDefinitionImpl;
import org.hibernate.boot.models.JpaAnnotations;
import org.hibernate.boot.query.NamedHqlQueryDefinition; import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition; import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinitionBuilder; import org.hibernate.boot.query.NamedNativeQueryDefinitionBuilder;
@ -34,23 +31,23 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jpa.HibernateHints; import org.hibernate.jpa.HibernateHints;
import org.hibernate.models.internal.util.StringHelper;
import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.AnnotationUsage;
import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetails;
import org.hibernate.models.spi.MutableAnnotationUsage;
import org.hibernate.models.spi.SourceModelBuildingContext;
import org.hibernate.query.sql.internal.ParameterParser; import org.hibernate.query.sql.internal.ParameterParser;
import org.hibernate.query.sql.spi.ParameterRecognizer; import org.hibernate.query.sql.spi.ParameterRecognizer;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import jakarta.persistence.NamedNativeQueries;
import jakarta.persistence.NamedNativeQuery; import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery; import jakarta.persistence.NamedQuery;
import jakarta.persistence.NamedStoredProcedureQuery; import jakarta.persistence.NamedStoredProcedureQuery;
import jakarta.persistence.ParameterMode; import jakarta.persistence.ParameterMode;
import jakarta.persistence.QueryHint; import jakarta.persistence.QueryHint;
import jakarta.persistence.SqlResultSetMapping; import jakarta.persistence.SqlResultSetMapping;
import jakarta.persistence.SqlResultSetMappings;
import jakarta.persistence.StoredProcedureParameter; import jakarta.persistence.StoredProcedureParameter;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
@ -111,7 +108,6 @@ public abstract class QueryBinder {
} }
} }
public static void bindNativeQuery( public static void bindNativeQuery(
AnnotationUsage<NamedNativeQuery> namedNativeQuery, AnnotationUsage<NamedNativeQuery> namedNativeQuery,
MetadataBuildingContext context, MetadataBuildingContext context,
@ -150,7 +146,6 @@ public abstract class QueryBinder {
.setComment( hints.getString( HibernateHints.HINT_COMMENT ) ) .setComment( hints.getString( HibernateHints.HINT_COMMENT ) )
.addHints( hints.getHintsMap() ); .addHints( hints.getHintsMap() );
final NamedNativeQueryDefinition queryDefinition = builder.build(); final NamedNativeQueryDefinition queryDefinition = builder.build();
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
@ -252,123 +247,97 @@ public abstract class QueryBinder {
context.getMetadataCollector().addNamedNativeQuery( queryDefinition ); context.getMetadataCollector().addNamedNativeQuery( queryDefinition );
} }
} }
public static NamedProcedureCallDefinition createStoredProcedure( public static NamedProcedureCallDefinition createStoredProcedure(
NamedNativeQueryDefinitionBuilder builder, NamedNativeQueryDefinitionBuilder builder,
MetadataBuildingContext context, MetadataBuildingContext context,
Supplier<RuntimeException> exceptionProducer) { Supplier<RuntimeException> exceptionProducer) {
List<StoredProcedureParameter> storedProcedureParameters = new ArrayList<>();
List<QueryHint> queryHints = new ArrayList<>();
final String sqlString = builder.getSqlString().trim(); final String sqlString = builder.getSqlString().trim();
if ( !sqlString.startsWith( "{" ) || !sqlString.endsWith( "}" ) ) { if ( !sqlString.startsWith( "{" ) || !sqlString.endsWith( "}" ) ) {
throw exceptionProducer.get(); throw exceptionProducer.get();
} }
final JdbcCall jdbcCall = parseJdbcCall( sqlString, exceptionProducer ); final JdbcCall jdbcCall = parseJdbcCall( sqlString, exceptionProducer );
AnnotationDescriptor descriptor = new AnnotationDescriptor( NamedStoredProcedureQuery.class ); final SourceModelBuildingContext sourceModelBuildingContext = context.getMetadataCollector()
descriptor.setValue( "name", builder.getName() ); .getSourceModelBuildingContext();
descriptor.setValue( "procedureName", jdbcCall.callableName ); final MutableAnnotationUsage<NamedStoredProcedureQuery> nameStoredProcedureQueryAnn = JpaAnnotations.NAMED_STORED_PROCEDURE_QUERY.createUsage(
null,
sourceModelBuildingContext
);
nameStoredProcedureQueryAnn.setAttributeValue( "name", builder.getName() );
nameStoredProcedureQueryAnn.setAttributeValue( "procedureName", jdbcCall.callableName );
final List<AnnotationUsage<StoredProcedureParameter>> storedProcedureParameters = new ArrayList<>();
for ( String parameterName : jdbcCall.parameters ) { for ( String parameterName : jdbcCall.parameters ) {
AnnotationDescriptor parameterDescriptor = new AnnotationDescriptor( StoredProcedureParameter.class ); final MutableAnnotationUsage<StoredProcedureParameter> storedProcedureParameterAnn = JpaAnnotations.STORED_PROCEDURE_PARAMETER
parameterDescriptor.setValue( "name", parameterName ); .createUsage( null, sourceModelBuildingContext );
parameterDescriptor.setValue( "mode", ParameterMode.IN ); storedProcedureParameterAnn.setAttributeValue( "name", parameterName );
storedProcedureParameterAnn.setAttributeValue( "mode", ParameterMode.IN );
final String typeName = builder.getParameterTypes().get( parameterName ); final String typeName = builder.getParameterTypes().get( parameterName );
if ( typeName == null ) { final ClassDetails classDetails;
parameterDescriptor.setValue( "type", Object.class ); if ( StringHelper.isEmpty( typeName ) ) {
classDetails = ClassDetails.VOID_CLASS_DETAILS;
} }
else { else {
final BasicType<Object> registeredType = context.getBootstrapContext() final BasicType<Object> registeredType = context.getBootstrapContext()
.getTypeConfiguration() .getTypeConfiguration()
.getBasicTypeRegistry() .getBasicTypeRegistry()
.getRegisteredType( typeName ); .getRegisteredType( typeName );
parameterDescriptor.setValue( "type", registeredType.getJavaType() ); classDetails = storedProcedureParameterAnn.getClassDetails( registeredType.getJavaType().getName() );
} }
storedProcedureParameters.add( AnnotationFactory.create( parameterDescriptor ) ); storedProcedureParameterAnn.setAttributeValue( "type", classDetails );
storedProcedureParameters.add( storedProcedureParameterAnn );
} }
descriptor.setValue( nameStoredProcedureQueryAnn.setAttributeValue( "parameters", storedProcedureParameters );
"parameters",
storedProcedureParameters.toArray( new StoredProcedureParameter[storedProcedureParameters.size()] )
);
if ( builder.getResultSetMappingName() != null ) { if ( builder.getResultSetMappingName() != null ) {
descriptor.setValue( "resultSetMappings", new String[]{ builder.getResultSetMappingName() } ); final List<String> resultSetMappings = new ArrayList<>( 1 );
} resultSetMappings.add( builder.getResultSetMappingName() );
else { nameStoredProcedureQueryAnn.setAttributeValue( "resultSetMappings", resultSetMappings );
descriptor.setValue( "resultSetMappings", new String[0] );
} }
if ( builder.getResultSetMappingClassName() != null ) { final String resultSetMappingClassName = builder.getResultSetMappingClassName();
descriptor.setValue( if ( resultSetMappingClassName != null ) {
"resultClasses", final List<ClassDetails> resultClasses = new ArrayList<>( 1 );
new Class[] { final ClassDetails classDetails;
context.getBootstrapContext() if ( StringHelper.isEmpty( resultSetMappingClassName ) ) {
.getClassLoaderAccess().classForName( builder.getResultSetMappingClassName() ) classDetails = ClassDetails.VOID_CLASS_DETAILS;
} }
); else {
} classDetails = nameStoredProcedureQueryAnn.getClassDetails( resultSetMappingClassName );
else { }
descriptor.setValue( "resultClasses", new Class[0] );
resultClasses.add( classDetails );
nameStoredProcedureQueryAnn.setAttributeValue( "resultClasses", resultClasses );
} }
final List<AnnotationUsage<QueryHint>> queryHints = new ArrayList<>();
if ( builder.getQuerySpaces() != null ) { if ( builder.getQuerySpaces() != null ) {
AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class ); final MutableAnnotationUsage<QueryHint> queryHintAnn = JpaAnnotations.QUERY_HINT.createUsage(
hintDescriptor.setValue( "name", HibernateHints.HINT_NATIVE_SPACES ); null,
hintDescriptor.setValue( "value", String.join( " ", builder.getQuerySpaces() ) ); sourceModelBuildingContext
queryHints.add( AnnotationFactory.create( hintDescriptor ) ); );
queryHintAnn.setAttributeValue( "name", HibernateHints.HINT_NATIVE_SPACES );
queryHintAnn.setAttributeValue( "value", String.join( " ", builder.getQuerySpaces() ) );
queryHints.add( queryHintAnn );
} }
if ( jdbcCall.resultParameter ) { if ( jdbcCall.resultParameter ) {
// Mark native queries that have a result parameter as callable functions // Mark native queries that have a result parameter as callable functions
AnnotationDescriptor hintDescriptor2 = new AnnotationDescriptor( QueryHint.class ); final MutableAnnotationUsage<QueryHint> queryHintAnn = JpaAnnotations.QUERY_HINT.createUsage(
hintDescriptor2.setValue( "name", HibernateHints.HINT_CALLABLE_FUNCTION ); null,
hintDescriptor2.setValue( "value", "true" ); sourceModelBuildingContext
queryHints.add( AnnotationFactory.create( hintDescriptor2 ) ); );
queryHintAnn.setAttributeValue( "name", HibernateHints.HINT_CALLABLE_FUNCTION );
queryHintAnn.setAttributeValue( "value", "true" );
queryHints.add( queryHintAnn );
} }
descriptor.setValue( "hints", queryHints.toArray( new QueryHint[queryHints.size()] ) ); nameStoredProcedureQueryAnn.setAttributeValue( "hints", queryHints );
return new NamedProcedureCallDefinitionImpl( AnnotationFactory.create( descriptor ) ); return new NamedProcedureCallDefinitionImpl( nameStoredProcedureQueryAnn );
}
public static void bindQueries(AnnotationUsage<NamedQueries> namedQueries, MetadataBuildingContext context, boolean isDefault) {
if ( namedQueries == null ) {
return;
}
final List<AnnotationUsage<NamedQuery>> nestedValues = namedQueries.getList( "value" );
for ( AnnotationUsage<NamedQuery> nestedValue : nestedValues ) {
bindQuery( nestedValue, context, isDefault );
}
}
public static void bindNativeQueries(
AnnotationUsage<NamedNativeQueries> namedNativeQueries,
MetadataBuildingContext context,
boolean isDefault) {
if ( namedNativeQueries == null ) {
return;
}
final List<AnnotationUsage<NamedNativeQuery>> nestedValues = namedNativeQueries.getList( "value" );
for ( AnnotationUsage<NamedNativeQuery> nestedValue : nestedValues ) {
bindNativeQuery( nestedValue, context, isDefault );
}
}
public static void bindNativeQueries(
AnnotationUsage<org.hibernate.annotations.NamedNativeQueries> namedNativeQueries,
MetadataBuildingContext context) {
if ( namedNativeQueries == null ) {
return;
}
final List<AnnotationUsage<org.hibernate.annotations.NamedNativeQuery>> nestedValues = namedNativeQueries.getList( "value" );
for ( AnnotationUsage<org.hibernate.annotations.NamedNativeQuery> nestedValue : nestedValues ) {
bindNativeQuery( nestedValue, context );
}
} }
public static void bindQuery( public static void bindQuery(
@ -464,20 +433,6 @@ public abstract class QueryBinder {
} }
} }
public static void bindQueries(
AnnotationUsage<org.hibernate.annotations.NamedQueries> namedQueries,
MetadataBuildingContext context) {
if ( namedQueries == null ) {
return;
}
final List<AnnotationUsage<org.hibernate.annotations.NamedQuery>> nestedValues = namedQueries.getList( "value" );
for ( AnnotationUsage<org.hibernate.annotations.NamedQuery> nestedValue : nestedValues ) {
bindQuery( nestedValue, context );
}
}
public static void bindNamedStoredProcedureQuery( public static void bindNamedStoredProcedureQuery(
AnnotationUsage<NamedStoredProcedureQuery> namedStoredProcedureQuery, AnnotationUsage<NamedStoredProcedureQuery> namedStoredProcedureQuery,
MetadataBuildingContext context, MetadataBuildingContext context,
@ -498,20 +453,6 @@ public abstract class QueryBinder {
} }
} }
public static void bindSqlResultSetMappings(
AnnotationUsage<SqlResultSetMappings> resultSetMappings,
MetadataBuildingContext context,
boolean isDefault) {
if ( resultSetMappings == null ) {
return;
}
final List<AnnotationUsage<SqlResultSetMapping>> mappings = resultSetMappings.getList( "value" );
for ( AnnotationUsage<SqlResultSetMapping> mapping : mappings ) {
bindSqlResultSetMapping( mapping, context, isDefault );
}
}
public static void bindSqlResultSetMapping( public static void bindSqlResultSetMapping(
AnnotationUsage<SqlResultSetMapping> resultSetMappingAnn, AnnotationUsage<SqlResultSetMapping> resultSetMappingAnn,
MetadataBuildingContext context, MetadataBuildingContext context,
@ -591,67 +532,6 @@ public abstract class QueryBinder {
return new JdbcCall( callableName, resultParameter, parameters ); return new JdbcCall( callableName, resultParameter, parameters );
} }
@Remove
@Deprecated(since = "6.2")
public static String parseJdbcCall(
String sqlString,
List<String> parameterNames,
Supplier<RuntimeException> exceptionProducer) {
String procedureName = null;
int index = skipWhitespace( sqlString, 1 );
// Parse the out param `?=` part
if ( sqlString.charAt( index ) == '?' ) {
index++;
index = skipWhitespace( sqlString, index );
if ( sqlString.charAt( index ) != '=' ) {
throw exceptionProducer.get();
}
index++;
index = skipWhitespace( sqlString, index );
}
// Parse the call keyword
if ( !sqlString.regionMatches( true, index, "call", 0, 4 ) ) {
throw exceptionProducer.get();
}
index += 4;
index = skipWhitespace( sqlString, index );
// Parse the procedure name
final int procedureStart = index;
for ( ; index < sqlString.length(); index++ ) {
final char c = sqlString.charAt( index );
if ( c == '(' || Character.isWhitespace( c ) ) {
procedureName = sqlString.substring( procedureStart, index );
break;
}
}
index = skipWhitespace( sqlString, index );
ParameterParser.parse(
sqlString.substring( index, sqlString.length() - 1 ),
new ParameterRecognizer() {
@Override
public void ordinalParameter(int sourcePosition) {
parameterNames.add( "" );
}
@Override
public void namedParameter(String name, int sourcePosition) {
parameterNames.add( name );
}
@Override
public void jpaPositionalParameter(int label, int sourcePosition) {
parameterNames.add( "" );
}
@Override
public void other(char character) {
}
}
);
return procedureName;
}
private static int skipWhitespace(String sqlString, int i) { private static int skipWhitespace(String sqlString, int i) {
while ( i < sqlString.length() ) { while ( i < sqlString.length() ) {
if ( !Character.isWhitespace( sqlString.charAt( i ) ) ) { if ( !Character.isWhitespace( sqlString.charAt( i ) ) ) {