diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 3770dcae7d..9d861ab5c7 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -126,7 +126,7 @@ xjc { xjcExtensions += ['inheritance', 'simplify'] } mapping { - xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-3.2.0.xsd' ) + xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-7.0.xsd' ) xjcBindingFile = file( 'src/main/xjb/mapping-bindings.xjb' ) xjcExtensions += ['inheritance', 'simplify'] } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/GenerationStrategyInterpreter.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/GenerationStrategyInterpreter.java index 667d8c015d..c6da710287 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/GenerationStrategyInterpreter.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/GenerationStrategyInterpreter.java @@ -6,6 +6,7 @@ */ package org.hibernate.boot.internal; +import java.util.List; import java.util.UUID; import org.hibernate.boot.model.IdentifierGeneratorDefinition; @@ -15,11 +16,15 @@ import org.hibernate.id.UUIDGenerator; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.models.spi.AnnotationUsage; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.TableGenerator; +import jakarta.persistence.UniqueConstraint; /** * Interpretations related to value generators based on the {@linkplain GenerationType strategy/type} @@ -81,91 +86,97 @@ public class GenerationStrategyInterpreter { } public void interpretTableGenerator( - TableGenerator tableGeneratorAnnotation, + AnnotationUsage tableGeneratorAnnotation, IdentifierGeneratorDefinition.Builder definitionBuilder) { - definitionBuilder.setName( tableGeneratorAnnotation.name() ); + definitionBuilder.setName( tableGeneratorAnnotation.getString( "name" ) ); definitionBuilder.setStrategy( org.hibernate.id.enhanced.TableGenerator.class.getName() ); definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, "true" ); - if ( !tableGeneratorAnnotation.catalog().isEmpty()) { - definitionBuilder.addParam( PersistentIdentifierGenerator.CATALOG, tableGeneratorAnnotation.catalog() ); + final String catalog = tableGeneratorAnnotation.getString( "catalog" ); + if ( StringHelper.isNotEmpty( catalog ) ) { + definitionBuilder.addParam( PersistentIdentifierGenerator.CATALOG, catalog ); } - if ( !tableGeneratorAnnotation.schema().isEmpty()) { - definitionBuilder.addParam( PersistentIdentifierGenerator.SCHEMA, tableGeneratorAnnotation.schema() ); + + final String schema = tableGeneratorAnnotation.getString( "schema" ); + if ( StringHelper.isNotEmpty( schema ) ) { + definitionBuilder.addParam( PersistentIdentifierGenerator.SCHEMA, schema ); } - if ( !tableGeneratorAnnotation.table().isEmpty()) { - definitionBuilder.addParam( - org.hibernate.id.enhanced.TableGenerator.TABLE_PARAM, - tableGeneratorAnnotation.table() - ); + + final String table = tableGeneratorAnnotation.getString( "table" ); + if ( StringHelper.isNotEmpty( table ) ) { + definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.TABLE_PARAM, table ); } - if ( !tableGeneratorAnnotation.pkColumnName().isEmpty()) { + + final String pkColumnName = tableGeneratorAnnotation.getString( "pkColumnName" ); + if ( StringHelper.isNotEmpty( pkColumnName ) ) { definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.SEGMENT_COLUMN_PARAM, - tableGeneratorAnnotation.pkColumnName() + pkColumnName ); } - if ( !tableGeneratorAnnotation.pkColumnValue().isEmpty()) { + + final String pkColumnValue = tableGeneratorAnnotation.getString( "pkColumnValue" ); + if ( StringHelper.isNotEmpty( pkColumnValue ) ) { definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.SEGMENT_VALUE_PARAM, - tableGeneratorAnnotation.pkColumnValue() + pkColumnValue ); } - if ( !tableGeneratorAnnotation.valueColumnName().isEmpty()) { + + final String valueColumnName = tableGeneratorAnnotation.getString( "valueColumnName" ); + if ( StringHelper.isNotEmpty( valueColumnName ) ) { definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.VALUE_COLUMN_PARAM, - tableGeneratorAnnotation.valueColumnName() + valueColumnName ); } + definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.INCREMENT_PARAM, - String.valueOf( tableGeneratorAnnotation.allocationSize() ) + String.valueOf( tableGeneratorAnnotation.getInteger( "allocationSize" ) ) ); + // See comment on HHH-4884 wrt initialValue. Basically initialValue is really the stated value + 1 definitionBuilder.addParam( org.hibernate.id.enhanced.TableGenerator.INITIAL_PARAM, - String.valueOf( tableGeneratorAnnotation.initialValue() + 1 ) + String.valueOf( tableGeneratorAnnotation.getInteger( "initialValue" ) + 1 ) ); // TODO : implement unique-constraint support - if ( tableGeneratorAnnotation.uniqueConstraints() != null - && tableGeneratorAnnotation.uniqueConstraints().length > 0 ) { - LOG.ignoringTableGeneratorConstraints( tableGeneratorAnnotation.name() ); + final List> uniqueConstraints = tableGeneratorAnnotation.getList( "uniqueConstraints" ); + if ( CollectionHelper.isNotEmpty( uniqueConstraints ) ) { + LOG.ignoringTableGeneratorConstraints( tableGeneratorAnnotation.getString( "name" ) ); } } public void interpretSequenceGenerator( - SequenceGenerator sequenceGeneratorAnnotation, + AnnotationUsage sequenceGeneratorAnnotation, IdentifierGeneratorDefinition.Builder definitionBuilder) { - definitionBuilder.setName( sequenceGeneratorAnnotation.name() ); + definitionBuilder.setName( sequenceGeneratorAnnotation.getString( "name" ) ); definitionBuilder.setStrategy( SequenceStyleGenerator.class.getName() ); - if ( !sequenceGeneratorAnnotation.catalog().isEmpty()) { - definitionBuilder.addParam( - PersistentIdentifierGenerator.CATALOG, - sequenceGeneratorAnnotation.catalog() - ); + final String catalog = sequenceGeneratorAnnotation.getString( "catalog" ); + if ( StringHelper.isNotEmpty( catalog ) ) { + definitionBuilder.addParam( PersistentIdentifierGenerator.CATALOG, catalog ); } - if ( !sequenceGeneratorAnnotation.schema().isEmpty()) { - definitionBuilder.addParam( - PersistentIdentifierGenerator.SCHEMA, - sequenceGeneratorAnnotation.schema() - ); + + final String schema = sequenceGeneratorAnnotation.getString( "schema" ); + if ( StringHelper.isNotEmpty( schema ) ) { + definitionBuilder.addParam( PersistentIdentifierGenerator.SCHEMA, schema ); } - if ( !sequenceGeneratorAnnotation.sequenceName().isEmpty()) { - definitionBuilder.addParam( - SequenceStyleGenerator.SEQUENCE_PARAM, - sequenceGeneratorAnnotation.sequenceName() - ); + + final String sequenceName = sequenceGeneratorAnnotation.getString( "sequenceName" ); + if ( StringHelper.isNotEmpty( sequenceName ) ) { + definitionBuilder.addParam( SequenceStyleGenerator.SEQUENCE_PARAM, sequenceName ); } definitionBuilder.addParam( SequenceStyleGenerator.INCREMENT_PARAM, - String.valueOf( sequenceGeneratorAnnotation.allocationSize() ) + String.valueOf( sequenceGeneratorAnnotation.getInteger( "allocationSize" ) ) ); definitionBuilder.addParam( SequenceStyleGenerator.INITIAL_PARAM, - String.valueOf( sequenceGeneratorAnnotation.initialValue() ) + String.valueOf( sequenceGeneratorAnnotation.getInteger( "initialValue" ) ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index 8295c558ad..df092f80d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -62,10 +62,17 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass; import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext; +import org.hibernate.boot.models.categorize.internal.ClassLoaderServiceLoading; +import org.hibernate.boot.models.categorize.internal.GlobalRegistrationsImpl; +import org.hibernate.boot.models.categorize.spi.GlobalRegistrations; +import org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor; +import org.hibernate.boot.models.xml.internal.PersistenceUnitMetadataImpl; +import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.boot.query.NamedHqlQueryDefinition; import org.hibernate.boot.query.NamedNativeQueryDefinition; import org.hibernate.boot.query.NamedProcedureCallDefinition; import org.hibernate.boot.query.NamedResultSetMappingDescriptor; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -81,6 +88,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.generator.Generator; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; @@ -99,6 +107,10 @@ import org.hibernate.mapping.Table; import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.mapping.DiscriminatorType; import org.hibernate.metamodel.spi.EmbeddableInstantiator; +import org.hibernate.models.internal.SourceModelBuildingContextImpl; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionRegistry; @@ -114,6 +126,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.MapsId; import static org.hibernate.boot.model.naming.Identifier.toIdentifier; +import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize; /** * The implementation of the {@linkplain InFlightMetadataCollector in-flight @@ -131,6 +144,9 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, private final BootstrapContext bootstrapContext; private final MetadataBuildingOptions options; + private final GlobalRegistrations globalRegistrations; + private final PersistenceUnitMetadata persistenceUnitMetadata; + private final AttributeConverterManager attributeConverterManager = new AttributeConverterManager(); private final UUID uuid; @@ -138,7 +154,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, private final Map entityBindingMap = new HashMap<>(); private final List composites = new ArrayList<>(); private final Map, Component> genericComponentsMap = new HashMap<>(); - private final Map> embeddableSubtypes = new HashMap<>(); + private final Map> embeddableSubtypes = new HashMap<>(); private final Map, DiscriminatorType> embeddableDiscriminatorTypesMap = new HashMap<>(); private final Map collectionBindingMap = new HashMap<>(); @@ -168,20 +184,28 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, private final Set defaultSqlResultSetMappingNames = new HashSet<>(); private final Set defaultNamedProcedureNames = new HashSet<>(); private Map, MappedSuperclass> mappedSuperClasses; - private Map> propertiesAnnotatedWithMapsId; - private Map> propertiesAnnotatedWithIdAndToOne; + private Map> propertiesAnnotatedWithMapsId; + private Map> propertiesAnnotatedWithIdAndToOne; private Map mappedByResolver; private Map propertyRefResolver; private Set delayedPropertyReferenceHandlers; private List> valueResolvers; + private final SourceModelBuildingContext sourceModelBuildingContext; + public InFlightMetadataCollectorImpl( BootstrapContext bootstrapContext, + SourceModelBuildingContext sourceModelBuildingContext, MetadataBuildingOptions options) { this.bootstrapContext = bootstrapContext; - this.uuid = UUID.randomUUID(); + this.sourceModelBuildingContext = sourceModelBuildingContext; this.options = options; + this.uuid = UUID.randomUUID(); + + this.globalRegistrations = new GlobalRegistrationsImpl( sourceModelBuildingContext ); + this.persistenceUnitMetadata = new PersistenceUnitMetadataImpl(); + for ( Map.Entry sqlFunctionEntry : bootstrapContext.getSqlFunctions().entrySet() ) { if ( sqlFunctionMap == null ) { // we need this to be a ConcurrentHashMap for the one we ultimately pass along to the SF @@ -194,6 +218,26 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, bootstrapContext.getAuxiliaryDatabaseObjectList().forEach( getDatabase()::addAuxiliaryDatabaseObject ); } + public InFlightMetadataCollectorImpl( + BootstrapContext bootstrapContext, + MetadataBuildingOptions options) { + this( + bootstrapContext, + buildContext( bootstrapContext ), + options + ); + } + + private static SourceModelBuildingContext buildContext(BootstrapContext bootstrapContext) { + final ClassLoaderService classLoaderService = bootstrapContext.getServiceRegistry().getService( ClassLoaderService.class ); + final ClassLoaderServiceLoading classLoading = new ClassLoaderServiceLoading( classLoaderService ); + return new SourceModelBuildingContextImpl( + classLoading, + bootstrapContext.getJandexView(), + ManagedResourcesProcessor::preFillRegistries + ); + } + @Override public UUID getUUID() { return null; @@ -209,6 +253,21 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, return bootstrapContext; } + @Override + public SourceModelBuildingContext getSourceModelBuildingContext() { + return sourceModelBuildingContext; + } + + @Override + public GlobalRegistrations getGlobalRegistrations() { + return globalRegistrations; + } + + @Override + public PersistenceUnitMetadata getPersistenceUnitMetadata() { + return persistenceUnitMetadata; + } + @Override public TypeConfiguration getTypeConfiguration() { return bootstrapContext.getTypeConfiguration(); @@ -290,13 +349,13 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, } @Override - public void registerEmbeddableSubclass(XClass superclass, XClass subclass) { + public void registerEmbeddableSubclass(ClassDetails superclass, ClassDetails subclass) { embeddableSubtypes.computeIfAbsent( superclass, c -> new ArrayList<>() ).add( subclass ); } @Override - public List getEmbeddableSubclasses(XClass superclass) { - final List subclasses = embeddableSubtypes.get( superclass ); + public List getEmbeddableSubclasses(ClassDetails superclass) { + final List subclasses = embeddableSubtypes.get( superclass ); return subclasses != null ? subclasses : List.of(); } @@ -490,9 +549,9 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, private Map collectionTypeRegistrations; @Override - public void addCollectionTypeRegistration(CollectionTypeRegistration registrationAnnotation) { + public void addCollectionTypeRegistration(AnnotationUsage registrationAnnotation) { addCollectionTypeRegistration( - registrationAnnotation.classification(), + registrationAnnotation.getEnum( "classification" ), toDescriptor( registrationAnnotation ) ); } @@ -514,20 +573,26 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, return collectionTypeRegistrations.get( classification ); } - private CollectionTypeRegistrationDescriptor toDescriptor(CollectionTypeRegistration registrationAnnotation) { - final Map parameters; - if ( registrationAnnotation.parameters().length > 0 ) { - parameters = new HashMap<>(); - for ( Parameter parameter : registrationAnnotation.parameters() ) { - parameters.put( parameter.name(), parameter.value() ); - } - } - else { - parameters = null; - } - return new CollectionTypeRegistrationDescriptor( registrationAnnotation.type(), parameters ); + private CollectionTypeRegistrationDescriptor toDescriptor(AnnotationUsage registrationAnnotation) { + return new CollectionTypeRegistrationDescriptor( + registrationAnnotation.getClassDetails( "type" ).toJavaClass(), + extractParameters( registrationAnnotation.getList( "parameters" ) ) + ); } + private Map extractParameters(List> annotationUsages) { + if ( CollectionHelper.isEmpty( annotationUsages ) ) { + return null; + } + + final Map result = mapOfSize( annotationUsages.size() ); + for ( AnnotationUsage parameter : annotationUsages ) { + result.put( parameter.getString( "name" ), parameter.getString( "value" ) ); + } + return result; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // attribute converters @@ -1297,6 +1362,43 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, } } + @Override + public AnnotatedClassType addClassType(ClassDetails classDetails) { + final AnnotatedClassType type = getAnnotatedClassType2( classDetails ); + annotatedClassTypeMap.put( classDetails.getName(), type ); + return type; + } + + private static AnnotatedClassType getAnnotatedClassType2(ClassDetails classDetails) { + if ( classDetails.hasAnnotationUsage( Entity.class ) ) { + return AnnotatedClassType.ENTITY; + } + else if ( classDetails.hasAnnotationUsage( Embeddable.class ) ) { + return AnnotatedClassType.EMBEDDABLE; + } + else if ( classDetails.hasAnnotationUsage( jakarta.persistence.MappedSuperclass.class ) ) { + return AnnotatedClassType.MAPPED_SUPERCLASS; + } + else if ( classDetails.hasAnnotationUsage( Imported.class ) ) { + return AnnotatedClassType.IMPORTED; + } + else { + return AnnotatedClassType.NONE; + } + } + + @Override + public AnnotatedClassType getClassType(ClassDetails classDetails) { + final AnnotatedClassType type = annotatedClassTypeMap.get( classDetails.getName() ); + if ( type == null ) { + return addClassType( classDetails ); + } + else { + return type; + } + } + + @Override public void addMappedSuperclass(Class type, MappedSuperclass mappedSuperclass) { if ( mappedSuperClasses == null ) { @@ -1314,7 +1416,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, } @Override - public PropertyData getPropertyAnnotatedWithMapsId(XClass entityType, String propertyName) { + public PropertyData getPropertyAnnotatedWithMapsId(ClassDetails entityType, String propertyName) { if ( propertiesAnnotatedWithMapsId == null ) { return null; } @@ -1324,35 +1426,36 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, } @Override - public void addPropertyAnnotatedWithMapsId(XClass entityType, PropertyData property) { + public void addPropertyAnnotatedWithMapsId(ClassDetails entityType, PropertyData property) { if ( propertiesAnnotatedWithMapsId == null ) { propertiesAnnotatedWithMapsId = new HashMap<>(); } - Map map = propertiesAnnotatedWithMapsId.get( entityType ); - if ( map == null ) { - map = new HashMap<>(); - propertiesAnnotatedWithMapsId.put( entityType, map ); - } - map.put( property.getProperty().getAnnotation( MapsId.class ).value(), property ); + final Map map = propertiesAnnotatedWithMapsId.computeIfAbsent( + entityType, + k -> new HashMap<>() + ); + map.put( + property.getAttributeMember().getAnnotationUsage( MapsId.class ).getString( "value" ), + property + ); } @Override - public void addPropertyAnnotatedWithMapsIdSpecj(XClass entityType, PropertyData property, String mapsIdValue) { + public void addPropertyAnnotatedWithMapsIdSpecj(ClassDetails entityType, PropertyData property, String mapsIdValue) { if ( propertiesAnnotatedWithMapsId == null ) { propertiesAnnotatedWithMapsId = new HashMap<>(); } - Map map = propertiesAnnotatedWithMapsId.get( entityType ); - if ( map == null ) { - map = new HashMap<>(); - propertiesAnnotatedWithMapsId.put( entityType, map ); - } + final Map map = propertiesAnnotatedWithMapsId.computeIfAbsent( + entityType, + k -> new HashMap<>() + ); map.put( mapsIdValue, property ); } @Override - public PropertyData getPropertyAnnotatedWithIdAndToOne(XClass entityType, String propertyName) { + public PropertyData getPropertyAnnotatedWithIdAndToOne(ClassDetails entityType, String propertyName) { if ( propertiesAnnotatedWithIdAndToOne == null ) { return null; } @@ -1362,16 +1465,15 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, } @Override - public void addToOneAndIdProperty(XClass entityType, PropertyData property) { + public void addToOneAndIdProperty(ClassDetails entityType, PropertyData property) { if ( propertiesAnnotatedWithIdAndToOne == null ) { propertiesAnnotatedWithIdAndToOne = new HashMap<>(); } - Map map = propertiesAnnotatedWithIdAndToOne.get( entityType ); - if ( map == null ) { - map = new HashMap<>(); - propertiesAnnotatedWithIdAndToOne.put( entityType, map ); - } + final Map map = propertiesAnnotatedWithIdAndToOne.computeIfAbsent( + entityType, + k -> new HashMap<>() + ); map.put( property.getPropertyName(), property ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java index 3718beb46a..16f516da74 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java @@ -42,6 +42,7 @@ import org.hibernate.boot.model.process.spi.MetadataBuildingProcess; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.ColumnOrderingStrategy; import org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard; +import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -94,6 +95,7 @@ import jakarta.persistence.SharedCacheMode; import static org.hibernate.cfg.AvailableSettings.JPA_COMPLIANCE; import static org.hibernate.cfg.AvailableSettings.WRAPPER_ARRAY_HANDLING; import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN; +import static org.hibernate.internal.util.StringHelper.nullIfEmpty; /** * @author Steve Ebersole @@ -983,18 +985,33 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont } if ( mappingDefaults.getImplicitCatalogName() == null ) { - mappingDefaults.implicitCatalogName = StringHelper.nullIfEmpty( + mappingDefaults.implicitCatalogName = nullIfEmpty( jpaOrmXmlPersistenceUnitDefaults.getDefaultCatalogName() ); } if ( mappingDefaults.getImplicitSchemaName() == null ) { - mappingDefaults.implicitSchemaName = StringHelper.nullIfEmpty( + mappingDefaults.implicitSchemaName = nullIfEmpty( jpaOrmXmlPersistenceUnitDefaults.getDefaultSchemaName() ); } } + @Override + public void apply(PersistenceUnitMetadata persistenceUnitMetadata) { + if ( !mappingDefaults.implicitlyQuoteIdentifiers ) { + mappingDefaults.implicitlyQuoteIdentifiers = persistenceUnitMetadata.useQuotedIdentifiers(); + } + + if ( mappingDefaults.getImplicitCatalogName() == null ) { + mappingDefaults.implicitCatalogName = nullIfEmpty( persistenceUnitMetadata.getDefaultCatalog() ); + } + + if ( mappingDefaults.getImplicitSchemaName() == null ) { + mappingDefaults.implicitSchemaName = nullIfEmpty( persistenceUnitMetadata.getDefaultSchema() ); + } + } + public void setBootstrapContext(BootstrapContext bootstrapContext) { this.bootstrapContext = bootstrapContext; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java index 9974cc274c..6e89ee41a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java @@ -19,6 +19,9 @@ import org.hibernate.boot.model.internal.QueryHintDefinition; import org.hibernate.boot.query.NamedProcedureCallDefinition; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.procedure.internal.NamedCallableQueryMementoImpl; import org.hibernate.procedure.internal.Util; import org.hibernate.procedure.spi.NamedCallableQueryMemento; @@ -47,14 +50,15 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin private final ParameterDefinitions parameterDefinitions; private final Map hints; - public NamedProcedureCallDefinitionImpl(NamedStoredProcedureQuery annotation) { - this.registeredName = annotation.name(); - this.procedureName = annotation.procedureName(); - this.hints = new QueryHintDefinition( registeredName, annotation.hints() ).getHintsMap(); - this.resultClasses = annotation.resultClasses(); - this.resultSetMappings = annotation.resultSetMappings(); + public NamedProcedureCallDefinitionImpl(AnnotationUsage annotation) { + this.registeredName = annotation.getString( "name" ); + this.procedureName = annotation.getString( "procedureName" ); + this.hints = new QueryHintDefinition( registeredName, annotation.getList( "hints" ) ).getHintsMap(); - this.parameterDefinitions = new ParameterDefinitions( annotation.parameters() ); + this.resultClasses = interpretResultClasses( annotation ); + this.resultSetMappings = interpretResultMappings( annotation ); + + this.parameterDefinitions = new ParameterDefinitions( annotation.getList( "parameters" ) ); final boolean specifiesResultClasses = resultClasses != null && resultClasses.length > 0; final boolean specifiesResultSetMappings = resultSetMappings != null && resultSetMappings.length > 0; @@ -69,6 +73,30 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin } } + private Class[] interpretResultClasses(AnnotationUsage annotation) { + final List resultClassDetails = annotation.getList( "resultClasses" ); + if ( resultClassDetails == null ) { + return null; + } + final Class[] resultClasses = new Class[resultClassDetails.size()]; + for ( int i = 0; i < resultClassDetails.size(); i++ ) { + resultClasses[i] = resultClassDetails.get( i ).toJavaClass(); + } + return resultClasses; + } + + private String[] interpretResultMappings(AnnotationUsage annotation) { + final List list = annotation.getList( "resultSetMappings" ); + if ( list == null ) { + return null; + } + final String[] strings = new String[list.size()]; + for ( int i = 0; i < list.size(); i++ ) { + strings[i] = list.get( i ); + } + return strings; + } + @Override public String getRegistrationName() { return registeredName; @@ -136,20 +164,22 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin private final ParameterStrategy parameterStrategy; private final ParameterDefinition[] parameterDefinitions; - ParameterDefinitions(StoredProcedureParameter[] parameters) { - if ( parameters == null || parameters.length == 0 ) { + ParameterDefinitions(List> parameters) { + if ( CollectionHelper.isEmpty( parameters ) ) { parameterStrategy = ParameterStrategy.POSITIONAL; parameterDefinitions = new ParameterDefinition[0]; } else { - parameterStrategy = StringHelper.isNotEmpty( parameters[0].name() ) + final AnnotationUsage parameterAnn = parameters.get( 0 ); + final boolean firstParameterHasName = StringHelper.isNotEmpty( parameterAnn.findAttributeValue( "name" ) ); + parameterStrategy = firstParameterHasName ? ParameterStrategy.NAMED : ParameterStrategy.POSITIONAL; - parameterDefinitions = new ParameterDefinition[ parameters.length ]; + parameterDefinitions = new ParameterDefinition[ parameters.size() ]; - for ( int i = 0; i < parameters.length; i++ ) { + for ( int i = 0; i < parameters.size(); i++ ) { // i+1 for the position because the apis say the numbers are 1-based, not zero - parameterDefinitions[i] = new ParameterDefinition<>(i + 1, parameters[i]); + parameterDefinitions[i] = new ParameterDefinition<>(i + 1, parameters.get( i )); } } } @@ -173,12 +203,11 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin private final ParameterMode parameterMode; private final Class type; - @SuppressWarnings("unchecked") - ParameterDefinition(int position, StoredProcedureParameter annotation) { + ParameterDefinition(int position, AnnotationUsage annotation) { this.position = position; - this.name = normalize( annotation.name() ); - this.parameterMode = annotation.mode(); - this.type = (Class) annotation.type(); + this.name = normalize( annotation.getString( "name" ) ); + this.parameterMode = annotation.getEnum( "mode" ); + this.type = annotation.getClassDetails( "type" ).toJavaClass(); } public ParameterMemento toMemento(SessionFactoryImplementor sessionFactory) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java index 6488b6b765..114ac02cb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java @@ -102,6 +102,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbCustomSqlImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbDatabaseObjectImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbDatabaseObjectScopeImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorColumnImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorFormulaImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollectionImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddableAttributesContainerImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddableImpl; @@ -1207,10 +1208,14 @@ public class HbmXmlTransformer { entity.getDiscriminatorColumn().setName( hbmClass.getDiscriminator().getColumnAttribute() ); } else if ( StringHelper.isEmpty( hbmClass.getDiscriminator().getFormulaAttribute() ) ) { - entity.setDiscriminatorFormula( hbmClass.getDiscriminator().getFormulaAttribute() ); + final JaxbDiscriminatorFormulaImpl formula = new JaxbDiscriminatorFormulaImpl(); + formula.setFragment( hbmClass.getDiscriminator().getFormulaAttribute() ); + entity.setDiscriminatorFormula( formula ); } else if ( StringHelper.isEmpty( hbmClass.getDiscriminator().getFormula() ) ) { - entity.setDiscriminatorFormula( hbmClass.getDiscriminator().getFormulaAttribute().trim() ); + final JaxbDiscriminatorFormulaImpl formula = new JaxbDiscriminatorFormulaImpl(); + formula.setFragment( hbmClass.getDiscriminator().getFormula().trim() ); + entity.setDiscriminatorFormula( formula ); } else { entity.setDiscriminatorColumn( new JaxbDiscriminatorColumnImpl() ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java index 35d131e99b..7eee2aa918 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java @@ -89,8 +89,8 @@ public interface JaxbEntity extends JaxbEntityOrMappedSuperclass { JaxbDiscriminatorColumnImpl getDiscriminatorColumn(); void setDiscriminatorColumn(JaxbDiscriminatorColumnImpl value); - String getDiscriminatorFormula(); - void setDiscriminatorFormula(String value); + JaxbDiscriminatorFormulaImpl getDiscriminatorFormula(); + void setDiscriminatorFormula(JaxbDiscriminatorFormulaImpl value); JaxbSequenceGeneratorImpl getSequenceGenerators(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQueryBase.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQueryBase.java new file mode 100644 index 0000000000..ea391d037c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQueryBase.java @@ -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. + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import java.util.List; + +/** + * @author Steve Ebersole + */ +public interface JaxbNamedQueryBase { + String getName(); + List getHints(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbQueryHint.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbQueryHint.java new file mode 100644 index 0000000000..92d97c9cbd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbQueryHint.java @@ -0,0 +1,26 @@ +/* + * 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.boot.jaxb.mapping.spi; + +/** + * Models a named query hint in the JAXB model + * + * @author Steve Ebersole + */ +public interface JaxbQueryHint { + /** + * The hint name. + * + * @see org.hibernate.jpa.AvailableHints + */ + String getName(); + + /** + * The hint value. + */ + String getValue(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/IdentifierGeneratorDefinition.java b/hibernate-core/src/main/java/org/hibernate/boot/model/IdentifierGeneratorDefinition.java index 76392b1cd7..232f93e016 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/IdentifierGeneratorDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/IdentifierGeneratorDefinition.java @@ -7,7 +7,6 @@ package org.hibernate.boot.model; import java.io.Serializable; -import java.lang.annotation.Annotation; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -17,16 +16,17 @@ import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.Internal; import org.hibernate.boot.internal.GenerationStrategyInterpreter; +import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.id.IdentifierGenerator; +import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.GenerationType; -import jakarta.persistence.Index; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.TableGenerator; -import jakarta.persistence.UniqueConstraint; import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableMap; +import static org.hibernate.boot.models.JpaAnnotations.TABLE_GENERATOR; import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; /** @@ -150,126 +150,19 @@ public class IdentifierGeneratorDefinition implements Serializable { private static IdentifierGeneratorDefinition buildTableGeneratorDefinition(String name) { final Builder builder = new Builder(); - GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretTableGenerator( - new TableGenerator() { - @Override - public String name() { - return name; - } - - @Override - public String table() { - return ""; - } - - @Override - public int initialValue() { - return 0; - } - - @Override - public int allocationSize() { - return 50; - } - - @Override - public String catalog() { - return ""; - } - - @Override - public String schema() { - return ""; - } - - @Override - public String pkColumnName() { - return ""; - } - - @Override - public String valueColumnName() { - return ""; - } - - @Override - public String pkColumnValue() { - return ""; - } - - @Override - public UniqueConstraint[] uniqueConstraints() { - return new UniqueConstraint[0]; - } - - @Override - public Index[] indexes() { - return new Index[0]; - } - - @Override - public String options() { - return ""; - } - - @Override - public Class annotationType() { - return TableGenerator.class; - } - }, - builder - ); - + final MutableAnnotationUsage tableGeneratorUsage = TABLE_GENERATOR.createUsage( null, null ); + GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretTableGenerator( tableGeneratorUsage, builder ); return builder.build(); } private static IdentifierGeneratorDefinition buildSequenceGeneratorDefinition(String name) { final Builder builder = new Builder(); - GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretSequenceGenerator( - new SequenceGenerator() { - @Override - public String name() { - return name; - } - - @Override - public String sequenceName() { - return ""; - } - - @Override - public String catalog() { - return ""; - } - - @Override - public String schema() { - return ""; - } - - @Override - public int initialValue() { - return 1; - } - - @Override - public int allocationSize() { - return 50; - } - - @Override - public String options() { - return ""; - } - - @Override - public Class annotationType() { - return SequenceGenerator.class; - } - }, - builder + final MutableAnnotationUsage sequenceGeneratorUsage = JpaAnnotations.SEQUENCE_GENERATOR.createUsage( + null, + null ); - + sequenceGeneratorUsage.setAttributeValue( "name", name ); + GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretSequenceGenerator( sequenceGeneratorUsage, builder ); return builder.build(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AttributeConverterManager.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AttributeConverterManager.java index 6ed149248d..b607e62fa3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AttributeConverterManager.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AttributeConverterManager.java @@ -17,7 +17,6 @@ import java.util.function.Function; import org.hibernate.AnnotationException; import org.hibernate.HibernateException; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.spi.AutoApplicableConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterAutoApplyHandler; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; @@ -25,6 +24,7 @@ import org.hibernate.boot.model.convert.spi.RegisteredConversion; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.util.StringHelper; +import org.hibernate.models.spi.MemberDetails; import org.jboss.logging.Logger; @@ -161,12 +161,13 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler { @Override public ConverterDescriptor findAutoApplyConverterForAttribute( - XProperty property, + MemberDetails attributeMember, MetadataBuildingContext context) { return locateMatchingConverter( - property, + attributeMember, ConversionSite.ATTRIBUTE, - (autoApplyDescriptor) -> autoApplyDescriptor.getAutoAppliedConverterDescriptorForAttribute( property, context ), + (autoApplyDescriptor) -> autoApplyDescriptor.getAutoAppliedConverterDescriptorForAttribute( + attributeMember, context ), context ); } @@ -174,13 +175,13 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler { private static final StringHelper.Renderer RENDERER = value -> value.getAttributeConverterClass().getName(); private ConverterDescriptor locateMatchingConverter( - XProperty xProperty, + MemberDetails memberDetails, ConversionSite conversionSite, Function matcher, MetadataBuildingContext context) { if ( registeredConversionsByDomainType != null ) { // we had registered conversions - see if any of them match and, if so, use that conversion - final ResolvedType resolveAttributeType = resolveAttributeType( xProperty, context ); + final ResolvedType resolveAttributeType = resolveAttributeType( memberDetails, context ); final RegisteredConversion registrationForDomainType = registeredConversionsByDomainType.get( resolveAttributeType.getErasedType() ); if ( registrationForDomainType != null ) { @@ -197,9 +198,9 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler { descriptor.getAttributeConverterClass().getName(), descriptor.getDomainValueResolvedType().getSignature(), conversionSite.getSiteDescriptor(), - xProperty.getDeclaringClass().getName(), - xProperty.getName(), - xProperty.getType().getName() + memberDetails.getDeclaringType().getName(), + memberDetails.getName(), + memberDetails.getType().getName() ); } @@ -229,8 +230,8 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler { Locale.ROOT, "Multiple auto-apply converters matched %s [%s.%s] : %s", conversionSite.getSiteDescriptor(), - xProperty.getDeclaringClass().getName(), - xProperty.getName(), + memberDetails.getDeclaringType().getName(), + memberDetails.getName(), StringHelper.join( matches, RENDERER ) ) ); @@ -238,24 +239,25 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler { @Override public ConverterDescriptor findAutoApplyConverterForCollectionElement( - XProperty property, + MemberDetails attributeMember, MetadataBuildingContext context) { return locateMatchingConverter( - property, + attributeMember, ConversionSite.COLLECTION_ELEMENT, - (autoApplyDescriptor) -> autoApplyDescriptor.getAutoAppliedConverterDescriptorForCollectionElement( property, context ), + (autoApplyDescriptor) -> autoApplyDescriptor.getAutoAppliedConverterDescriptorForCollectionElement( + attributeMember, context ), context ); } @Override public ConverterDescriptor findAutoApplyConverterForMapKey( - XProperty property, + MemberDetails attributeMember, MetadataBuildingContext context) { return locateMatchingConverter( - property, + attributeMember, ConversionSite.MAP_KEY, - (autoApplyDescriptor) -> autoApplyDescriptor.getAutoAppliedConverterDescriptorForMapKey( property, context ), + (autoApplyDescriptor) -> autoApplyDescriptor.getAutoAppliedConverterDescriptorForMapKey( attributeMember, context ), context ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorBypassedImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorBypassedImpl.java index 24b889f043..52d59433e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorBypassedImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorBypassedImpl.java @@ -6,10 +6,10 @@ */ package org.hibernate.boot.model.convert.internal; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.spi.AutoApplicableConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.MemberDetails; /** * An implementation of AutoApplicableConverterDescriptor that always reports @@ -28,21 +28,21 @@ public class AutoApplicableConverterDescriptorBypassedImpl implements AutoApplic @Override public ConverterDescriptor getAutoAppliedConverterDescriptorForAttribute( - XProperty xProperty, + MemberDetails memberDetails, MetadataBuildingContext context) { return null; } @Override public ConverterDescriptor getAutoAppliedConverterDescriptorForCollectionElement( - XProperty xProperty, + MemberDetails memberDetails, MetadataBuildingContext context) { return null; } @Override public ConverterDescriptor getAutoAppliedConverterDescriptorForMapKey( - XProperty xProperty, + MemberDetails memberDetails, MetadataBuildingContext context) { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorStandardImpl.java index fa0a86da6c..02cc553534 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorStandardImpl.java @@ -15,6 +15,7 @@ import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.spi.AutoApplicableConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.MemberDetails; import com.fasterxml.classmate.ResolvedType; import com.fasterxml.classmate.members.ResolvedMember; @@ -37,9 +38,9 @@ public class AutoApplicableConverterDescriptorStandardImpl implements AutoApplic @Override public ConverterDescriptor getAutoAppliedConverterDescriptorForAttribute( - XProperty xProperty, + MemberDetails memberDetails, MetadataBuildingContext context) { - final ResolvedType attributeType = resolveAttributeType( xProperty, context ); + final ResolvedType attributeType = resolveAttributeType( memberDetails, context ); return typesMatch( linkedConverterDescriptor.getDomainValueResolvedType(), attributeType ) ? linkedConverterDescriptor @@ -48,9 +49,9 @@ public class AutoApplicableConverterDescriptorStandardImpl implements AutoApplic @Override public ConverterDescriptor getAutoAppliedConverterDescriptorForCollectionElement( - XProperty xProperty, + MemberDetails memberDetails, MetadataBuildingContext context) { - final ResolvedMember collectionMember = resolveMember( xProperty, context ); + final ResolvedMember collectionMember = resolveMember( memberDetails, context ); final ResolvedType elementType; Class erasedType = collectionMember.getType().getErasedType(); @@ -82,10 +83,10 @@ public class AutoApplicableConverterDescriptorStandardImpl implements AutoApplic @Override public ConverterDescriptor getAutoAppliedConverterDescriptorForMapKey( - XProperty xProperty, + MemberDetails memberDetails, MetadataBuildingContext context) { - final ResolvedMember collectionMember = resolveMember( xProperty, context ); + final ResolvedMember collectionMember = resolveMember( memberDetails, context ); final ResolvedType keyType; if ( Map.class.isAssignableFrom( collectionMember.getType().getErasedType() ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/ConverterHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/ConverterHelper.java index ce7bc0d011..b143c2b236 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/ConverterHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/ConverterHelper.java @@ -14,13 +14,11 @@ import java.util.List; import org.hibernate.AnnotationException; import org.hibernate.HibernateException; -import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.internal.ClassmateContext; -import org.hibernate.boot.model.internal.HCANNHelper; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.util.GenericsHelper; import org.hibernate.internal.util.type.PrimitiveWrapperHelper; +import org.hibernate.models.spi.MemberDetails; import com.fasterxml.classmate.ResolvedType; import com.fasterxml.classmate.ResolvedTypeWithMembers; @@ -37,24 +35,21 @@ public class ConverterHelper { return GenericsHelper.extractParameterizedType( base ); } - public static ResolvedType resolveAttributeType(XProperty xProperty, MetadataBuildingContext context) { - return resolveMember( xProperty, context ).getType(); + public static ResolvedType resolveAttributeType(MemberDetails memberDetails, MetadataBuildingContext context) { + return resolveMember( memberDetails, context ).getType(); } - public static ResolvedMember resolveMember(XProperty xProperty, MetadataBuildingContext buildingContext) { + public static ResolvedMember resolveMember(MemberDetails memberDetails, MetadataBuildingContext buildingContext) { final ClassmateContext classmateContext = buildingContext.getBootstrapContext().getClassmateContext(); - final ReflectionManager reflectionManager = buildingContext.getBootstrapContext().getReflectionManager(); - final ResolvedType declaringClassType = classmateContext.getTypeResolver().resolve( - reflectionManager.toClass( xProperty.getDeclaringClass() ) - ); + final ResolvedType declaringClassType = classmateContext.getTypeResolver().resolve( memberDetails.getDeclaringType().toJavaClass() ); final ResolvedTypeWithMembers declaringClassWithMembers = classmateContext.getMemberResolver().resolve( declaringClassType, null, null ); - final Member member = toMember( xProperty ); + final Member member = memberDetails.toJavaMember(); if ( member instanceof Method ) { for ( ResolvedMethod resolvedMember : declaringClassWithMembers.getMemberMethods() ) { if ( resolvedMember.getName().equals( member.getName() ) ) { @@ -78,18 +73,6 @@ public class ConverterHelper { ); } - public static Member toMember(XProperty xProperty) { - try { - return HCANNHelper.getUnderlyingMember( xProperty ); - } - catch (Exception e) { - throw new HibernateException( - "Could not resolve member signature from XProperty reference", - e - ); - } - } - public static List resolveConverterClassParamTypes( Class> converterClass, ClassmateContext context) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/AutoApplicableConverterDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/AutoApplicableConverterDescriptor.java index 7e3346824a..2b15e7df80 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/AutoApplicableConverterDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/AutoApplicableConverterDescriptor.java @@ -6,8 +6,8 @@ */ package org.hibernate.boot.model.convert.spi; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.MemberDetails; /** * Contract for handling auto-apply checks for JPA AttributeConverters @@ -15,7 +15,7 @@ import org.hibernate.boot.spi.MetadataBuildingContext; * @author Steve Ebersole */ public interface AutoApplicableConverterDescriptor { - ConverterDescriptor getAutoAppliedConverterDescriptorForAttribute(XProperty xProperty, MetadataBuildingContext context); - ConverterDescriptor getAutoAppliedConverterDescriptorForCollectionElement(XProperty xProperty, MetadataBuildingContext context); - ConverterDescriptor getAutoAppliedConverterDescriptorForMapKey(XProperty xProperty, MetadataBuildingContext context); + ConverterDescriptor getAutoAppliedConverterDescriptorForAttribute(MemberDetails memberDetails, MetadataBuildingContext context); + ConverterDescriptor getAutoAppliedConverterDescriptorForCollectionElement(MemberDetails memberDetails, MetadataBuildingContext context); + ConverterDescriptor getAutoAppliedConverterDescriptorForMapKey(MemberDetails memberDetails, MetadataBuildingContext context); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/ConverterAutoApplyHandler.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/ConverterAutoApplyHandler.java index b04b8d8455..e3f034f4bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/ConverterAutoApplyHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/ConverterAutoApplyHandler.java @@ -7,8 +7,8 @@ package org.hibernate.boot.model.convert.spi; import org.hibernate.Incubating; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.MemberDetails; import jakarta.persistence.Converter; @@ -27,25 +27,25 @@ public interface ConverterAutoApplyHandler { * by the passed property descriptor. {@code null} indicates that no auto-applied * converter matched * - * @param property The HCANN descriptor for the basic attribute + * @param attributeMember The HCANN descriptor for the basic attribute */ - ConverterDescriptor findAutoApplyConverterForAttribute(XProperty property, MetadataBuildingContext context); + ConverterDescriptor findAutoApplyConverterForAttribute(MemberDetails attributeMember, MetadataBuildingContext context); /** * Resolve the auto-applied converter to be applied to the elements of a plural attribute * described by the passed property descriptor. {@code null} indicates that no auto-applied * converter matched * - * @param property The HCANN descriptor for the plural attribute + * @param attributeMember The HCANN descriptor for the plural attribute */ - ConverterDescriptor findAutoApplyConverterForCollectionElement(XProperty property, MetadataBuildingContext context); + ConverterDescriptor findAutoApplyConverterForCollectionElement(MemberDetails attributeMember, MetadataBuildingContext context); /** * Resolve the auto-applied converter to be applied to the keys of a plural Map attribute * described by the passed property descriptor. {@code null} indicates that no auto-applied * converter matched * - * @param property The HCANN descriptor for the Map-typed plural attribute + * @param attributeMember The HCANN descriptor for the Map-typed plural attribute */ - ConverterDescriptor findAutoApplyConverterForMapKey(XProperty property, MetadataBuildingContext context); + ConverterDescriptor findAutoApplyConverterForMapKey(MemberDetails attributeMember, MetadataBuildingContext context); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AbstractPropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AbstractPropertyHolder.java index eb75d88c37..ca04b05790 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AbstractPropertyHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AbstractPropertyHolder.java @@ -15,27 +15,28 @@ import java.util.Map; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.annotations.ColumnTransformer; -import org.hibernate.annotations.ColumnTransformers; import org.hibernate.annotations.TimeZoneColumn; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.ImplicitBasicColumnNameSource; import org.hibernate.boot.model.source.spi.AttributePath; +import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType; import org.hibernate.usertype.internal.OffsetTimeCompositeUserType; import org.jboss.logging.Logger; import jakarta.persistence.AssociationOverride; -import jakarta.persistence.AssociationOverrides; import jakarta.persistence.AttributeOverride; -import jakarta.persistence.AttributeOverrides; import jakarta.persistence.CheckConstraint; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; @@ -55,25 +56,27 @@ import static org.hibernate.internal.util.StringHelper.qualify; public abstract class AbstractPropertyHolder implements PropertyHolder { private static final Logger log = CoreLogging.logger( AbstractPropertyHolder.class ); - protected AbstractPropertyHolder parent; - private Map holderColumnOverride; - private Map currentPropertyColumnOverride; - private Map holderColumnTransformerOverride; - private Map currentPropertyColumnTransformerOverride; - private Map holderJoinColumnOverride; - private Map currentPropertyJoinColumnOverride; - private Map holderJoinTableOverride; - private Map currentPropertyJoinTableOverride; - private Map holderForeignKeyOverride; - private Map currentPropertyForeignKeyOverride; private final String path; + protected final AbstractPropertyHolder parent; private final MetadataBuildingContext context; + private Boolean isInIdClass; + private Map>> holderColumnOverride; + private Map>> currentPropertyColumnOverride; + private Map> holderColumnTransformerOverride; + private Map> currentPropertyColumnTransformerOverride; + private Map>> holderJoinColumnOverride; + private Map>> currentPropertyJoinColumnOverride; + private Map> holderJoinTableOverride; + private Map> currentPropertyJoinTableOverride; + private Map> holderForeignKeyOverride; + private Map> currentPropertyForeignKeyOverride; + AbstractPropertyHolder( String path, PropertyHolder parent, - XClass clazzToProcess, + ClassDetails clazzToProcess, MetadataBuildingContext context) { this.path = path; this.parent = (AbstractPropertyHolder) parent; @@ -84,12 +87,12 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { protected abstract String normalizeCompositePathForLogging(String attributeName); protected abstract String normalizeCompositePath(String attributeName); - protected abstract AttributeConversionInfo locateAttributeConversionInfo(XProperty property); + protected abstract AttributeConversionInfo locateAttributeConversionInfo(MemberDetails attributeMember); protected abstract AttributeConversionInfo locateAttributeConversionInfo(String path); @Override - public ConverterDescriptor resolveAttributeConverterDescriptor(XProperty property) { - AttributeConversionInfo info = locateAttributeConversionInfo( property ); + public ConverterDescriptor resolveAttributeConverterDescriptor(MemberDetails attributeMember) { + AttributeConversionInfo info = locateAttributeConversionInfo( attributeMember ); if ( info != null ) { if ( info.isConversionDisabled() ) { return null; @@ -104,12 +107,12 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { } } - log.debugf( "Attempting to locate auto-apply AttributeConverter for property [%s:%s]", path, property.getName() ); + log.debugf( "Attempting to locate auto-apply AttributeConverter for attributeMember [%s:%s]", path, attributeMember.getName() ); return context.getMetadataCollector() .getConverterRegistry() .getAttributeConverterAutoApplyHandler() - .findAutoApplyConverterForAttribute( property, context ); + .findAutoApplyConverterForAttribute( attributeMember, context ); } protected IllegalStateException buildExceptionFromInstantiationError(AttributeConversionInfo info, Exception e) { @@ -179,10 +182,12 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { /** * Set the property to be processed. property can be null * - * @param property The property + * @param attributeMember The property */ - protected void setCurrentProperty(XProperty property) { - if ( property == null ) { + protected void setCurrentProperty(MemberDetails attributeMember) { + // todo (jpa32) : some of this (association override handling esp) does the same work multiple times - consolidate + + if ( attributeMember == null ) { this.currentPropertyColumnOverride = null; this.currentPropertyColumnTransformerOverride = null; this.currentPropertyJoinColumnOverride = null; @@ -190,27 +195,27 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { this.currentPropertyForeignKeyOverride = null; } else { - this.currentPropertyColumnOverride = buildColumnOverride( property, getPath(), context ); + this.currentPropertyColumnOverride = buildColumnOverride( attributeMember, getPath(), context ); if ( this.currentPropertyColumnOverride.isEmpty() ) { this.currentPropertyColumnOverride = null; } - this.currentPropertyColumnTransformerOverride = buildColumnTransformerOverride( property ); + this.currentPropertyColumnTransformerOverride = buildColumnTransformerOverride( attributeMember ); if ( this.currentPropertyColumnTransformerOverride.isEmpty() ) { this.currentPropertyColumnTransformerOverride = null; } - this.currentPropertyJoinColumnOverride = buildJoinColumnOverride( property, getPath() ); + this.currentPropertyJoinColumnOverride = buildJoinColumnOverride( attributeMember, getPath() ); if ( this.currentPropertyJoinColumnOverride.isEmpty() ) { this.currentPropertyJoinColumnOverride = null; } - this.currentPropertyJoinTableOverride = buildJoinTableOverride( property, getPath() ); + this.currentPropertyJoinTableOverride = buildJoinTableOverride( attributeMember, getPath() ); if ( this.currentPropertyJoinTableOverride.isEmpty() ) { this.currentPropertyJoinTableOverride = null; } - this.currentPropertyForeignKeyOverride = buildForeignKeyOverride( property, getPath() ); + this.currentPropertyForeignKeyOverride = buildForeignKeyOverride( attributeMember, getPath() ); if ( this.currentPropertyForeignKeyOverride.isEmpty() ) { this.currentPropertyForeignKeyOverride = null; } @@ -224,46 +229,55 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { * These rules are here to support both JPA 2 and legacy overriding rules. */ @Override - public Column[] getOverriddenColumn(String propertyName) { - Column[] result = getExactOverriddenColumn( propertyName ); - if ( result == null && propertyName.contains(".collection&&element.") ) { - //support for non map collections where no prefix is needed - result = getExactOverriddenColumn( propertyName.replace(".collection&&element.", ".") ); + public List> getOverriddenColumn(String propertyName) { + final List> result = getExactOverriddenColumn( propertyName ); + if ( result == null ) { + if ( propertyName.contains( ".collection&&element." ) ) { + //support for non map collections where no prefix is needed + //TODO cache the underlying regexp + return getExactOverriddenColumn( propertyName.replace( ".collection&&element.", "." ) ); + } } return result; } @Override - public ColumnTransformer getOverriddenColumnTransformer(String logicalColumnName) { - ColumnTransformer override = null; + public AnnotationUsage getOverriddenColumnTransformer(String logicalColumnName) { + AnnotationUsage result = null; if ( parent != null ) { - override = parent.getOverriddenColumnTransformer( logicalColumnName ); + result = parent.getOverriddenColumnTransformer( logicalColumnName ); } - if ( override == null && currentPropertyColumnTransformerOverride != null ) { - override = currentPropertyColumnTransformerOverride.get( logicalColumnName ); + + if ( result == null && currentPropertyColumnTransformerOverride != null ) { + result = currentPropertyColumnTransformerOverride.get( logicalColumnName ); } - if ( override == null && holderColumnTransformerOverride != null ) { - override = holderColumnTransformerOverride.get( logicalColumnName ); + + if ( result == null && holderColumnTransformerOverride != null ) { + result = holderColumnTransformerOverride.get( logicalColumnName ); } - return override; + + return result; } /** * Get column overriding, property first, then parent, then holder * find the overridden rules from the exact property name. */ - private Column[] getExactOverriddenColumn(String propertyName) { - Column[] override = null; + private List> getExactOverriddenColumn(String propertyName) { + List> result = null; if ( parent != null ) { - override = parent.getExactOverriddenColumn( propertyName ); + result = parent.getExactOverriddenColumn( propertyName ); } - if ( override == null && currentPropertyColumnOverride != null ) { - override = currentPropertyColumnOverride.get( propertyName ); + + if ( result == null && currentPropertyColumnOverride != null ) { + result = currentPropertyColumnOverride.get( propertyName ); } - if ( override == null && holderColumnOverride != null ) { - override = holderColumnOverride.get( propertyName ); + + if ( result == null && holderColumnOverride != null ) { + result = holderColumnOverride.get( propertyName ); } - return override; + + return result; } /** @@ -273,12 +287,12 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { * These rules are here to support both JPA 2 and legacy overriding rules. */ @Override - public JoinColumn[] getOverriddenJoinColumn(String propertyName) { - JoinColumn[] result = getExactOverriddenJoinColumn( propertyName ); + public List> getOverriddenJoinColumn(String propertyName) { + final List> result = getExactOverriddenJoinColumn( propertyName ); if ( result == null && propertyName.contains( ".collection&&element." ) ) { //support for non map collections where no prefix is needed //TODO cache the underlying regexp - result = getExactOverriddenJoinColumn( propertyName.replace( ".collection&&element.", "." ) ); + return getExactOverriddenJoinColumn( propertyName.replace( ".collection&&element.", "." ) ); } return result; } @@ -286,57 +300,60 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { /** * Get column overriding, property first, then parent, then holder */ - private JoinColumn[] getExactOverriddenJoinColumn(String propertyName) { - JoinColumn[] override = null; + private List> getExactOverriddenJoinColumn(String propertyName) { + List> result = null; if ( parent != null ) { - override = parent.getExactOverriddenJoinColumn( propertyName ); + result = parent.getExactOverriddenJoinColumn( propertyName ); } - if ( override == null && currentPropertyJoinColumnOverride != null ) { - override = currentPropertyJoinColumnOverride.get( propertyName ); + + if ( result == null && currentPropertyJoinColumnOverride != null ) { + result = currentPropertyJoinColumnOverride.get( propertyName ); } - if ( override == null && holderJoinColumnOverride != null ) { - override = holderJoinColumnOverride.get( propertyName ); + + if ( result == null && holderJoinColumnOverride != null ) { + result = holderJoinColumnOverride.get( propertyName ); } - return override; + + return result; } @Override - public ForeignKey getOverriddenForeignKey(String propertyName) { - ForeignKey result = getExactOverriddenForeignKey( propertyName ); + public AnnotationUsage getOverriddenForeignKey(String propertyName) { + final AnnotationUsage result = getExactOverriddenForeignKey( propertyName ); if ( result == null && propertyName.contains( ".collection&&element." ) ) { //support for non map collections where no prefix is needed //TODO cache the underlying regexp - result = getExactOverriddenForeignKey( propertyName.replace( ".collection&&element.", "." ) ); + return getExactOverriddenForeignKey( propertyName.replace( ".collection&&element.", "." ) ); } return result; } - private ForeignKey getExactOverriddenForeignKey(String propertyName) { - ForeignKey override = null; + private AnnotationUsage getExactOverriddenForeignKey(String propertyName) { + AnnotationUsage result = null; if ( parent != null ) { - override = parent.getExactOverriddenForeignKey( propertyName ); + result = parent.getExactOverriddenForeignKey( propertyName ); } - if ( override == null && currentPropertyForeignKeyOverride != null ) { - override = currentPropertyForeignKeyOverride.get( propertyName ); + if ( result == null && currentPropertyForeignKeyOverride != null ) { + result = currentPropertyForeignKeyOverride.get( propertyName ); } - if ( override == null && holderForeignKeyOverride != null ) { - override = holderForeignKeyOverride.get( propertyName ); + if ( result == null && holderForeignKeyOverride != null ) { + result = holderForeignKeyOverride.get( propertyName ); } - return override; + return result; } /** * Get column overriding, property first, then parent, then holder * replace the placeholder 'collection&&element' with nothing - * + *

* These rules are here to support both JPA 2 and legacy overriding rules. */ @Override - public JoinTable getJoinTable(XProperty property) { - final String propertyName = qualify( getPath(), property.getName() ); - JoinTable result = getOverriddenJoinTable( propertyName ); - if (result == null) { - result = property.getAnnotation( JoinTable.class ); + public AnnotationUsage getJoinTable(MemberDetails attributeMember) { + final String propertyName = qualify( getPath(), attributeMember.getName() ); + final AnnotationUsage result = getOverriddenJoinTable( propertyName ); + if ( result == null ) { + return attributeMember.getAnnotationUsage( JoinTable.class ); } return result; } @@ -347,12 +364,12 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { * * These rules are here to support both JPA 2 and legacy overriding rules. */ - public JoinTable getOverriddenJoinTable(String propertyName) { - JoinTable result = getExactOverriddenJoinTable( propertyName ); + public AnnotationUsage getOverriddenJoinTable(String propertyName) { + final AnnotationUsage result = getExactOverriddenJoinTable( propertyName ); if ( result == null && propertyName.contains( ".collection&&element." ) ) { //support for non map collections where no prefix is needed //TODO cache the underlying regexp - result = getExactOverriddenJoinTable( propertyName.replace( ".collection&&element.", "." ) ); + return getExactOverriddenJoinTable( propertyName.replace( ".collection&&element.", "." ) ); } return result; } @@ -360,8 +377,8 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { /** * Get column overriding, property first, then parent, then holder */ - private JoinTable getExactOverriddenJoinTable(String propertyName) { - JoinTable override = null; + private AnnotationUsage getExactOverriddenJoinTable(String propertyName) { + AnnotationUsage override = null; if ( parent != null ) { override = parent.getExactOverriddenJoinTable( propertyName ); } @@ -374,24 +391,23 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { return override; } - private void buildHierarchyColumnOverride(XClass element) { - XClass current = element; - Map columnOverride = new HashMap<>(); - Map columnTransformerOverride = new HashMap<>(); - Map joinColumnOverride = new HashMap<>(); - Map joinTableOverride = new HashMap<>(); - Map foreignKeyOverride = new HashMap<>(); - XClass objectClass = context.getBootstrapContext().getReflectionManager().toXClass(Object.class); - while ( current != null && !objectClass.equals( current ) ) { - if ( current.isAnnotationPresent( Entity.class ) - || current.isAnnotationPresent( MappedSuperclass.class ) - || current.isAnnotationPresent( Embeddable.class ) ) { + private void buildHierarchyColumnOverride(ClassDetails element) { + ClassDetails current = element; + Map>> columnOverride = new HashMap<>(); + Map> columnTransformerOverride = new HashMap<>(); + Map>> joinColumnOverride = new HashMap<>(); + Map> joinTableOverride = new HashMap<>(); + Map> foreignKeyOverride = new HashMap<>(); + while ( current != null && !ClassDetails.OBJECT_CLASS_DETAILS.equals( current ) ) { + if ( current.hasAnnotationUsage( Entity.class ) + || current.hasAnnotationUsage( MappedSuperclass.class ) + || current.hasAnnotationUsage( Embeddable.class ) ) { //FIXME is embeddable override? - Map currentOverride = buildColumnOverride( current, getPath(), context ); - Map currentTransformerOverride = buildColumnTransformerOverride( current ); - Map currentJoinOverride = buildJoinColumnOverride( current, getPath() ); - Map currentJoinTableOverride = buildJoinTableOverride( current, getPath() ); - Map currentForeignKeyOverride = buildForeignKeyOverride( current, getPath() ); + Map>> currentOverride = buildColumnOverride( current, getPath(), context ); + Map> currentTransformerOverride = buildColumnTransformerOverride( current ); + Map>> currentJoinOverride = buildJoinColumnOverride( current, getPath() ); + Map> currentJoinTableOverride = buildJoinTableOverride( current, getPath() ); + Map> currentForeignKeyOverride = buildForeignKeyOverride( current, getPath() ); currentOverride.putAll( columnOverride ); //subclasses have precedence over superclasses currentTransformerOverride.putAll( columnTransformerOverride ); //subclasses have precedence over superclasses currentJoinOverride.putAll( joinColumnOverride ); //subclasses have precedence over superclasses @@ -403,7 +419,7 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { joinTableOverride = currentJoinTableOverride; foreignKeyOverride = currentForeignKeyOverride; } - current = current.getSuperclass(); + current = current.getSuperClass(); } holderColumnOverride = !columnOverride.isEmpty() ? columnOverride : null; @@ -413,109 +429,102 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { holderForeignKeyOverride = !foreignKeyOverride.isEmpty() ? foreignKeyOverride : null; } - private static Map buildColumnOverride( - XAnnotatedElement element, + private static Map>> buildColumnOverride( + AnnotationTarget element, String path, MetadataBuildingContext context) { - final Map columnOverride = new HashMap<>(); - if ( element != null ) { - AttributeOverride singleOverride = element.getAnnotation( AttributeOverride.class ); - AttributeOverrides multipleOverrides = element.getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides; - if ( singleOverride != null ) { - overrides = new AttributeOverride[]{ singleOverride }; - } - else if ( multipleOverrides != null ) { - overrides = multipleOverrides.value(); - } - else { - overrides = null; - } + final Map>> columnOverrideMap = new HashMap<>(); + if ( element == null ) { + return columnOverrideMap; + } - if ( overrides != null ) { - final Map> columnOverrideList = new HashMap<>(); + final List> overrides = element.getRepeatedAnnotationUsages( AttributeOverride.class ); + if ( CollectionHelper.isNotEmpty( overrides ) ) { + final Map>> columnOverrideList = new HashMap<>(); + for ( AnnotationUsage depAttr : overrides ) { + final String qualifiedName = StringHelper.qualify( path, depAttr.getString( "name" ) ); + final AnnotationUsage column = depAttr.getNestedUsage( "column" ); - for ( AttributeOverride depAttr : overrides ) { - final String qualifiedName = qualify( path, depAttr.name() ); - - if ( columnOverrideList.containsKey( qualifiedName ) ) { - columnOverrideList.get( qualifiedName ).add( depAttr.column() ); - } - else { - List list = new ArrayList<>(); - list.add( depAttr.column() ); - columnOverrideList.put( qualifiedName, list ); - } - } - - for ( Map.Entry> entry : columnOverrideList.entrySet() ) { - columnOverride.put( entry.getKey(), entry.getValue().toArray( new Column[0] ) ); - } - } - else if ( useColumnForTimeZoneStorage( element, context ) ) { - final Column column = createTemporalColumn( element, path, context ); - if ( isOffsetTimeClass( element ) ) { - columnOverride.put( - path + "." + OffsetTimeCompositeUserType.LOCAL_TIME_NAME, - new Column[] { column } - ); + if ( columnOverrideList.containsKey( qualifiedName ) ) { + // already an entry, just add to that List + columnOverrideList.get( qualifiedName ).add( column ); } else { - columnOverride.put( - path + "." + AbstractTimeZoneStorageCompositeUserType.INSTANT_NAME, - new Column[] { column } - ); + // not yet an entry, create the list and add + final List> list = new ArrayList<>(); + list.add( column ); + columnOverrideList.put( qualifiedName, list ); } - final Column offsetColumn = createTimeZoneColumn( element, column ); - columnOverride.put( - path + "." + AbstractTimeZoneStorageCompositeUserType.ZONE_OFFSET_NAME, - new Column[]{ offsetColumn } + } + } + else if ( useColumnForTimeZoneStorage( element, context ) ) { + final AnnotationUsage column = createTemporalColumn( element, path, context ); + if ( isOffsetTimeClass( element ) ) { + columnOverrideMap.put( + path + "." + OffsetTimeCompositeUserType.LOCAL_TIME_NAME, + List.of( column ) ); } - } - return columnOverride; - } - - private static Column createTimeZoneColumn(XAnnotatedElement element, Column column) { - final TimeZoneColumn timeZoneColumn = element.getAnnotation( TimeZoneColumn.class ); - if ( timeZoneColumn != null ) { - return new ColumnImpl( - timeZoneColumn.name(), - false, - column.nullable(), - timeZoneColumn.insertable(), - timeZoneColumn.updatable(), - timeZoneColumn.columnDefinition(), - timeZoneColumn.table(), - 0 - ); - } - else { - return new ColumnImpl( - column.name() + "_tz", - false, - column.nullable(), - column.insertable(), - column.updatable(), - "", - column.table(), - 0 + else { + columnOverrideMap.put( + path + "." + AbstractTimeZoneStorageCompositeUserType.INSTANT_NAME, + List.of( column ) + ); + } + final AnnotationUsage offsetColumn = createTimeZoneColumn( element, column, context ); + columnOverrideMap.put( + path + "." + AbstractTimeZoneStorageCompositeUserType.ZONE_OFFSET_NAME, + List.of( offsetColumn ) ); } + return columnOverrideMap; } - private static Column createTemporalColumn(XAnnotatedElement element, String path, MetadataBuildingContext context) { + private static AnnotationUsage createTimeZoneColumn( + AnnotationTarget element, + AnnotationUsage column, + MetadataBuildingContext context) { + final AnnotationUsage timeZoneColumn = element.getAnnotationUsage( TimeZoneColumn.class ); + return JpaAnnotations.COLUMN.createUsage( + element, + (created) -> { + final String columnName = timeZoneColumn != null + ? timeZoneColumn.getString( "name" ) + : column.getString( "name" ) + "_tz"; + created.setAttributeValue( "name", columnName ); + created.setAttributeValue( "nullable", column.getBoolean( "nullable" ) ); + + final AnnotationUsage source = timeZoneColumn != null + ? timeZoneColumn + : column; + created.setAttributeValue( "table", source.getAttributeValue( "table" ) ); + created.setAttributeValue( "insertable", source.getAttributeValue( "insertable" ) ); + created.setAttributeValue( "updatable", source.getAttributeValue( "updatable" ) ); + + if ( timeZoneColumn != null ) { + created.setAttributeValue( "columnDefinition", timeZoneColumn.getAttributeValue( "columnDefinition" ) ); + } + }, + context.getMetadataCollector().getSourceModelBuildingContext() + ); + } + + private static AnnotationUsage createTemporalColumn( + AnnotationTarget element, + String path, + MetadataBuildingContext context) { int precision; - final Column annotatedColumn = element.getAnnotation( Column.class ); + final AnnotationUsage annotatedColumn = element.getAnnotationUsage( Column.class ); if ( annotatedColumn != null ) { - if ( !annotatedColumn.name().isEmpty() ) { + if ( StringHelper.isNotEmpty( annotatedColumn.getString( "name" ) ) ) { return annotatedColumn; } - precision = annotatedColumn.precision(); + precision = annotatedColumn.getInteger( "precision" ); } else { precision = 0; } + // Base the name of the synthetic dateTime field on the name of the original attribute final Identifier implicitName = context.getObjectNameNormalizer().normalizeIdentifierQuoting( context.getBuildingOptions().getImplicitNamingStrategy().determineBasicColumnName( @@ -539,108 +548,76 @@ public abstract class AbstractPropertyHolder implements PropertyHolder { } ) ); - return new ColumnImpl( - implicitName.getText(), - false, - true, - true, - true, - "", - "", - precision + + return JpaAnnotations.COLUMN.createUsage( + element, + (created) -> { + created.setAttributeValue( "name", implicitName.getText() ); + created.setAttributeValue( "precision", precision ); + }, + context.getMetadataCollector().getSourceModelBuildingContext() ); } - private static Map buildColumnTransformerOverride(XAnnotatedElement element) { - Map columnOverride = new HashMap<>(); + private static Map> buildColumnTransformerOverride(AnnotationTarget element) { + final Map> columnOverride = new HashMap<>(); if ( element != null ) { - ColumnTransformer singleOverride = element.getAnnotation( ColumnTransformer.class ); - ColumnTransformers multipleOverrides = element.getAnnotation( ColumnTransformers.class ); - ColumnTransformer[] overrides; - if ( singleOverride != null ) { - overrides = new ColumnTransformer[]{ singleOverride }; - } - else if ( multipleOverrides != null ) { - overrides = multipleOverrides.value(); - } - else { - overrides = null; - } + element.forEachAnnotationUsage( ColumnTransformer.class, (usage) -> { + columnOverride.put( usage.getString( "forColumn" ), usage ); + } ); + } + return columnOverride; + } - if ( overrides != null ) { - for ( ColumnTransformer depAttr : overrides ) { - columnOverride.put( - depAttr.forColumn(), - depAttr - ); - } + private static Map>> buildJoinColumnOverride(AnnotationTarget element, String path) { + final Map>> columnOverride = new HashMap<>(); + if ( element != null ) { + final List> overrides = buildAssociationOverrides( element, path ); + for ( AnnotationUsage override : overrides ) { + columnOverride.put( + qualify( path, override.getString( "name" ) ), + override.getList( "joinColumns" ) + ); } } return columnOverride; } - private static Map buildJoinColumnOverride(XAnnotatedElement element, String path) { - Map columnOverride = new HashMap<>(); + private static Map> buildForeignKeyOverride(AnnotationTarget element, String path) { + final Map> foreignKeyOverride = new HashMap<>(); if ( element != null ) { - AssociationOverride[] overrides = buildAssociationOverrides( element, path ); - if ( overrides != null ) { - for ( AssociationOverride depAttr : overrides ) { - columnOverride.put( - qualify( path, depAttr.name() ), - depAttr.joinColumns() - ); - } - } - } - return columnOverride; - } - - private static Map buildForeignKeyOverride(XAnnotatedElement element, String path) { - Map foreignKeyOverride = new HashMap<>(); - if ( element != null ) { - AssociationOverride[] overrides = buildAssociationOverrides( element, path ); - if ( overrides != null ) { - for ( AssociationOverride depAttr : overrides ) { - foreignKeyOverride.put( qualify( path, depAttr.name() ), depAttr.foreignKey() ); - } + final List> overrides = buildAssociationOverrides( element, path ); + for ( AnnotationUsage override : overrides ) { + foreignKeyOverride.put( + qualify( path, override.getString( "name" ) ), + override.getNestedUsage( "foreignKey" ) + ); } } return foreignKeyOverride; } - private static AssociationOverride[] buildAssociationOverrides(XAnnotatedElement element, String path) { - AssociationOverride singleOverride = element.getAnnotation( AssociationOverride.class ); - AssociationOverrides pluralOverrides = element.getAnnotation( AssociationOverrides.class ); - - AssociationOverride[] overrides; - if ( singleOverride != null ) { - overrides = new AssociationOverride[] { singleOverride }; - } - else if ( pluralOverrides != null ) { - overrides = pluralOverrides.value(); - } - else { - overrides = null; - } + private static List> buildAssociationOverrides(AnnotationTarget element, String path) { + final List> overrides = new ArrayList<>(); + element.forEachAnnotationUsage( AssociationOverride.class, overrides::add ); return overrides; } - private static Map buildJoinTableOverride(XAnnotatedElement element, String path) { - Map tableOverride = new HashMap<>(); + private static Map> buildJoinTableOverride(AnnotationTarget element, String path) { + final Map> result = new HashMap<>(); if ( element != null ) { - AssociationOverride[] overrides = buildAssociationOverrides( element, path ); - if ( overrides != null ) { - for ( AssociationOverride depAttr : overrides ) { - if ( depAttr.joinColumns().length == 0 ) { - tableOverride.put( - qualify( path, depAttr.name() ), - depAttr.joinTable() - ); - } + final List> overrides = buildAssociationOverrides( element, path ); + for ( AnnotationUsage override : overrides ) { + final List> joinColumns = override.getList( "joinColumns" ); + if ( CollectionHelper.isNotEmpty( joinColumns ) ) { + result.put( + qualify( path, override.getString( "name" ) ), + override.getNestedUsage( "joinTable" ) + ); } } } - return tableOverride; + return result; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java index 1e0c388cdb..43e384fb49 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java @@ -10,8 +10,6 @@ import java.util.List; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.annotations.Struct; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameImpl; @@ -22,6 +20,10 @@ import org.hibernate.boot.spi.PropertyData; import org.hibernate.mapping.AggregateColumn; import org.hibernate.mapping.BasicValue; import org.hibernate.mapping.Component; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.java.spi.EmbeddableAggregateJavaType; import org.hibernate.type.spi.TypeConfiguration; @@ -38,14 +40,14 @@ public final class AggregateComponentBinder { Component component, PropertyHolder propertyHolder, PropertyData inferredData, - XClass componentXClass, + ClassDetails returnedClassOrElement, AnnotatedColumns columns, MetadataBuildingContext context) { - if ( isAggregate( inferredData.getProperty(), componentXClass ) ) { + if ( isAggregate( inferredData.getAttributeMember(), inferredData.getClassOrElementType(), context ) ) { final InFlightMetadataCollector metadataCollector = context.getMetadataCollector(); final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration(); // Determine a struct name if this is a struct through some means - final QualifiedName structQualifiedName = determineStructName( columns, inferredData, componentXClass, context ); + final QualifiedName structQualifiedName = determineStructName( columns, inferredData, returnedClassOrElement, context ); final String structName = structQualifiedName == null ? null : structQualifiedName.render(); // We must register a special JavaType for the embeddable which can provide a recommended JdbcType @@ -54,24 +56,24 @@ public final class AggregateComponentBinder { () -> new EmbeddableAggregateJavaType<>( component.getComponentClass(), structName ) ); component.setStructName( structQualifiedName ); - component.setStructColumnNames( determineStructAttributeNames( inferredData, componentXClass ) ); + component.setStructColumnNames( determineStructAttributeNames( inferredData, returnedClassOrElement ) ); // Determine the aggregate column BasicValueBinder basicValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ATTRIBUTE, component, context ); basicValueBinder.setPropertyName( inferredData.getPropertyName() ); - basicValueBinder.setReturnedClassName( inferredData.getPropertyClass().getName() ); + basicValueBinder.setReturnedClassName( inferredData.getClassOrElementType().getName() ); basicValueBinder.setColumns( columns ); basicValueBinder.setPersistentClassName( propertyHolder.getClassName() ); basicValueBinder.setType( - inferredData.getProperty(), - inferredData.getPropertyClass(), + inferredData.getAttributeMember(), + inferredData.getPropertyType(), inferredData.getDeclaringClass().getName(), null ); final BasicValue propertyValue = basicValueBinder.make(); final AggregateColumn aggregateColumn = (AggregateColumn) propertyValue.getColumn(); if ( structName != null && aggregateColumn.getSqlType() == null ) { - if ( inferredData.getProperty().isArray() || inferredData.getProperty().isCollection() ) { + if ( inferredData.getAttributeMember().isArray() || inferredData.getAttributeMember().isPlural() ) { aggregateColumn.setSqlTypeCode( getStructPluralSqlTypeCode( context ) ); aggregateColumn.setSqlType( context.getMetadataCollector() @@ -95,7 +97,7 @@ public final class AggregateComponentBinder { new AggregateComponentSecondPass( propertyHolder, component, - componentXClass, + returnedClassOrElement, inferredData.getPropertyName(), context ) @@ -122,17 +124,19 @@ public final class AggregateComponentBinder { private static QualifiedName determineStructName( AnnotatedColumns columns, PropertyData inferredData, - XClass returnedClassOrElement, + ClassDetails returnedClassOrElement, MetadataBuildingContext context) { - final XProperty property = inferredData.getProperty(); + final MemberDetails property = inferredData.getAttributeMember(); if ( property != null ) { - final Struct struct = property.getAnnotation( Struct.class ); + final AnnotationUsage struct = property.getAnnotationUsage( Struct.class ); if ( struct != null ) { return toQualifiedName( struct, context ); } - final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class ); + final AnnotationUsage jdbcTypeCode = property.getAnnotationUsage( JdbcTypeCode.class ); if ( jdbcTypeCode != null - && ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE ) + && ( jdbcTypeCode.getInteger( "value" ) == SqlTypes.STRUCT + || jdbcTypeCode.getInteger( "value" ) == SqlTypes.STRUCT_ARRAY + || jdbcTypeCode.getInteger( "value" ) == SqlTypes.STRUCT_TABLE ) && columns != null ) { final List columnList = columns.getColumns(); final String sqlType; @@ -148,60 +152,72 @@ public final class AggregateComponentBinder { } } } - final Struct struct = returnedClassOrElement.getAnnotation( Struct.class ); + + final AnnotationUsage struct = returnedClassOrElement.getAnnotationUsage( Struct.class ); if ( struct != null ) { return toQualifiedName( struct, context ); } + return null; } - private static QualifiedName toQualifiedName(Struct struct, MetadataBuildingContext context) { + private static QualifiedName toQualifiedName(AnnotationUsage struct, MetadataBuildingContext context) { final Database database = context.getMetadataCollector().getDatabase(); return new QualifiedNameImpl( - database.toIdentifier( struct.catalog() ), - database.toIdentifier( struct.schema() ), - database.toIdentifier( struct.name() ) + database.toIdentifier( struct.getString( "catalog" ) ), + database.toIdentifier( struct.getString( "schema" ) ), + database.toIdentifier( struct.getString( "name" ) ) ); } - private static String[] determineStructAttributeNames(PropertyData inferredData, XClass returnedClassOrElement) { - final XProperty property = inferredData.getProperty(); + private static String[] determineStructAttributeNames(PropertyData inferredData, ClassDetails returnedClassOrElement) { + final MemberDetails property = inferredData.getAttributeMember(); if ( property != null ) { - final Struct struct = property.getAnnotation( Struct.class ); + final AnnotationUsage struct = property.getAnnotationUsage( Struct.class ); if ( struct != null ) { - return struct.attributes(); + final List attributes = struct.getList( "attributes" ); + return attributes.toArray( new String[0] ); } } - final Struct struct = returnedClassOrElement.getAnnotation( Struct.class ); + + final AnnotationUsage struct = returnedClassOrElement.getAnnotationUsage( Struct.class ); if ( struct != null ) { - return struct.attributes(); + final List attributes = struct.getList( "attributes" ); + return attributes.toArray( new String[0] ); } + return null; } - private static boolean isAggregate(XProperty property, XClass returnedClass) { + private static boolean isAggregate( + MemberDetails property, + TypeDetails returnedClass, + MetadataBuildingContext context) { if ( property != null ) { - final Struct struct = property.getAnnotation( Struct.class ); - if ( struct != null ) { + if ( property.hasAnnotationUsage( Struct.class ) ) { return true; } - final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class ); + + final AnnotationUsage jdbcTypeCode = property.getAnnotationUsage( JdbcTypeCode.class ); if ( jdbcTypeCode != null ) { - switch ( jdbcTypeCode.value() ) { + switch ( jdbcTypeCode.getInteger( "value" ) ) { case SqlTypes.STRUCT: case SqlTypes.JSON: case SqlTypes.SQLXML: case SqlTypes.STRUCT_ARRAY: case SqlTypes.STRUCT_TABLE: case SqlTypes.JSON_ARRAY: - case SqlTypes.XML_ARRAY: + case SqlTypes.XML_ARRAY: { return true; + } } } } + if ( returnedClass != null ) { - return returnedClass.isAnnotationPresent( Struct.class ); + return returnedClass.determineRawClass().hasAnnotationUsage( Struct.class ); } + return false; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java index 8872cfb80a..40e397c823 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java @@ -14,7 +14,7 @@ import java.util.TreeSet; import org.hibernate.AnnotationException; import org.hibernate.MappingException; import org.hibernate.annotations.Comment; -import org.hibernate.annotations.common.reflection.XClass; +import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; @@ -35,6 +35,8 @@ import org.hibernate.mapping.ToOne; import org.hibernate.mapping.UserDefinedObjectType; import org.hibernate.mapping.Value; import org.hibernate.metamodel.internal.EmbeddableHelper; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.sql.Template; import org.hibernate.type.SqlTypes; import org.hibernate.type.spi.TypeConfiguration; @@ -48,19 +50,19 @@ public class AggregateComponentSecondPass implements SecondPass { private final PropertyHolder propertyHolder; private final Component component; - private final XClass componentXClass; + private final ClassDetails returnedClassOrElement; private final String propertyName; private final MetadataBuildingContext context; public AggregateComponentSecondPass( PropertyHolder propertyHolder, Component component, - XClass componentXClass, + ClassDetails returnedClassOrElement, String propertyName, MetadataBuildingContext context) { this.propertyHolder = propertyHolder; this.component = component; - this.componentXClass = componentXClass; + this.returnedClassOrElement = returnedClassOrElement; this.propertyName = propertyName; this.context = context; } @@ -93,9 +95,9 @@ public class AggregateComponentSecondPass implements SecondPass { structName.getSchemaName() ); final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", namespace, structName.getObjectName() ); - final Comment comment = componentXClass.getAnnotation( Comment.class ); + final AnnotationUsage comment = returnedClassOrElement.getAnnotationUsage( Comment.class ); if ( comment != null ) { - udt.setComment( comment.value() ); + udt.setComment( comment.getString( "value" ) ); } for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) { udt.addColumn( aggregatedColumn ); @@ -196,8 +198,7 @@ public class AggregateComponentSecondPass implements SecondPass { private static void validateComponent(Component component, String basePath, boolean inArray) { for ( Property property : component.getProperties() ) { final Value value = property.getValue(); - if ( value instanceof Component ) { - final Component c = (Component) value; + if ( value instanceof Component c ) { validateComponent( c, qualify( basePath, property.getName() ), inArray ); } else if ( value instanceof ToOne ) { @@ -433,7 +434,7 @@ public class AggregateComponentSecondPass implements SecondPass { String.format( "Struct [%s] of class [%s] is defined by multiple components with different mappings [%s] and [%s] for column [%s]", udt1.getName(), - componentXClass.getName(), + returnedClassOrElement.getName(), column1.getSqlType(), column2.getSqlType(), column1.getCanonicalName() @@ -448,7 +449,7 @@ public class AggregateComponentSecondPass implements SecondPass { "Struct [%s] is defined by multiple components %s but some columns are missing in [%s]: %s", udt1.getName(), findComponentClasses(), - componentXClass.getName(), + returnedClassOrElement.getName(), missingColumns ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java index 8ebc322c63..be5311f816 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java @@ -16,11 +16,9 @@ import org.hibernate.annotations.Check; import org.hibernate.annotations.Checks; import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnTransformer; -import org.hibernate.annotations.ColumnTransformers; import org.hibernate.annotations.FractionalSeconds; import org.hibernate.annotations.GeneratedColumn; import org.hibernate.annotations.Index; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.ImplicitBasicColumnNameSource; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; @@ -40,6 +38,8 @@ import org.hibernate.mapping.Formula; import org.hibernate.mapping.Join; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.MemberDetails; import org.jboss.logging.Logger; @@ -491,7 +491,7 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildFormulaFromAnnotation( - org.hibernate.annotations.Formula formulaAnn, + AnnotationUsage formulaAnn, // Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, @@ -512,7 +512,7 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildColumnFromNoAnnotation( - FractionalSeconds fractionalSeconds, + AnnotationUsage fractionalSeconds, // Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, @@ -532,8 +532,8 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildColumnFromAnnotation( - jakarta.persistence.Column column, - org.hibernate.annotations.FractionalSeconds fractionalSeconds, + AnnotationUsage column, + AnnotationUsage fractionalSeconds, // Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, @@ -554,8 +554,8 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildColumnsFromAnnotations( - jakarta.persistence.Column[] columns, - FractionalSeconds fractionalSeconds, + List> columns, + AnnotationUsage fractionalSeconds, // Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, @@ -577,7 +577,7 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildColumnsFromAnnotations( - jakarta.persistence.Column[] columns, + List> columns, // Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, @@ -600,9 +600,9 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildColumnOrFormulaFromAnnotation( - jakarta.persistence.Column column, - org.hibernate.annotations.Formula formulaAnn, - org.hibernate.annotations.FractionalSeconds fractionalSeconds, + AnnotationUsage column, + AnnotationUsage formulaAnn, + AnnotationUsage fractionalSeconds, // Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, @@ -610,7 +610,7 @@ public class AnnotatedColumn { Map secondaryTables, MetadataBuildingContext context) { return buildColumnsOrFormulaFromAnnotation( - column==null ? null : new jakarta.persistence.Column[] { column }, + column==null ? null : List.of( column ), formulaAnn, fractionalSeconds, // commentAnn, @@ -624,9 +624,9 @@ public class AnnotatedColumn { } public static AnnotatedColumns buildColumnsOrFormulaFromAnnotation( - jakarta.persistence.Column[] columns, - org.hibernate.annotations.Formula formulaAnn, - org.hibernate.annotations.FractionalSeconds fractionalSeconds, + List> columns, + AnnotationUsage formulaAnn, + AnnotationUsage fractionalSeconds, // Comment comment, Nullability nullability, PropertyHolder propertyHolder, @@ -642,7 +642,7 @@ public class AnnotatedColumn { parent.setBuildingContext( context ); parent.setJoins( secondaryTables ); //unnecessary final AnnotatedColumn formulaColumn = new AnnotatedColumn(); - formulaColumn.setFormula( formulaAnn.value() ); + formulaColumn.setFormula( formulaAnn.getString( "value" ) ); formulaColumn.setImplicit( false ); // formulaColumn.setBuildingContext( context ); // formulaColumn.setPropertyHolder( propertyHolder ); @@ -651,7 +651,7 @@ public class AnnotatedColumn { return parent; } else { - final jakarta.persistence.Column[] actualColumns = overrideColumns( columns, propertyHolder, inferredData ); + final List> actualColumns = overrideColumns( columns, propertyHolder, inferredData ); if ( actualColumns == null ) { return buildImplicitColumn( fractionalSeconds, @@ -679,24 +679,24 @@ public class AnnotatedColumn { } } - private static jakarta.persistence.Column[] overrideColumns( - jakarta.persistence.Column[] columns, + private static List> overrideColumns( + List> columns, PropertyHolder propertyHolder, PropertyData inferredData ) { final String path = getPath( propertyHolder, inferredData ); - final jakarta.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn( path ); + final List> overriddenCols = propertyHolder.getOverriddenColumn( path ); if ( overriddenCols != null ) { //check for overridden first - if ( columns != null && overriddenCols.length != columns.length ) { + if ( columns != null && overriddenCols.size() != columns.size() ) { //TODO: unfortunately, we never actually see this nice error message, since // PersistentClass.validate() gets called first and produces a worse message throw new AnnotationException( "Property '" + path - + "' specifies " + columns.length - + " '@AttributeOverride's but the overridden property has " + overriddenCols.length + + "' specifies " + columns.size() + + " '@AttributeOverride's but the overridden property has " + overriddenCols.size() + " columns (every column must have exactly one '@AttributeOverride')" ); } LOG.debugf( "Column(s) overridden for property %s", inferredData.getPropertyName() ); - return overriddenCols.length == 0 ? null : overriddenCols; + return overriddenCols.isEmpty() ? null : overriddenCols; } else { return columns; @@ -710,14 +710,14 @@ public class AnnotatedColumn { String suffixForDefaultColumnName, Map secondaryTables, MetadataBuildingContext context, - jakarta.persistence.Column[] actualCols, - FractionalSeconds fractionalSeconds) { + List> actualCols, + AnnotationUsage fractionalSeconds) { final AnnotatedColumns parent = new AnnotatedColumns(); parent.setPropertyHolder( propertyHolder ); parent.setPropertyName( getRelativePath( propertyHolder, inferredData.getPropertyName() ) ); parent.setJoins( secondaryTables ); parent.setBuildingContext( context ); - for ( jakarta.persistence.Column column : actualCols ) { + for ( AnnotationUsage column : actualCols ) { final Database database = context.getMetadataCollector().getDatabase(); final String sqlType = getSqlType( context, column ); final String tableName = getTableName( column, database ); @@ -732,7 +732,7 @@ public class AnnotatedColumn { inferredData, suffixForDefaultColumnName, parent, - actualCols.length, + actualCols.size(), database, column, fractionalSeconds, @@ -743,14 +743,22 @@ public class AnnotatedColumn { return parent; } - private static String getTableName(jakarta.persistence.Column column, Database database) { - return column.table().isEmpty() ? "" - : database.getJdbcEnvironment().getIdentifierHelper().toIdentifier( column.table() ).render(); + private static String getTableName( + AnnotationUsage column, + Database database) { + final String table = column.getString( "table" ); + return table.isEmpty() + ? "" + : database.getJdbcEnvironment().getIdentifierHelper().toIdentifier( table ).render(); } - private static String getSqlType(MetadataBuildingContext context, jakarta.persistence.Column column) { - return column.columnDefinition().isEmpty() ? null - : context.getObjectNameNormalizer().applyGlobalQuoting( column.columnDefinition() ); + private static String getSqlType( + MetadataBuildingContext context, + AnnotationUsage column) { + final String columnDefinition = column.getString( "columnDefinition" ); + return columnDefinition.isEmpty() + ? null + : context.getObjectNameNormalizer().applyGlobalQuoting( columnDefinition ); } private static AnnotatedColumn buildColumn( @@ -761,8 +769,8 @@ public class AnnotatedColumn { AnnotatedColumns parent, int numberOfColumns, Database database, - jakarta.persistence.Column column, - FractionalSeconds fractionalSeconds, + AnnotationUsage column, + AnnotationUsage fractionalSeconds, String sqlType, String tableName) { final String columnName = logicalColumnName( inferredData, suffixForDefaultColumnName, database, column ); @@ -770,27 +778,20 @@ public class AnnotatedColumn { annotatedColumn.setLogicalColumnName( columnName ); annotatedColumn.setImplicit( false ); annotatedColumn.setSqlType( sqlType ); - annotatedColumn.setLength( (long) column.length() ); + annotatedColumn.setLength( (long) column.getInteger( "length" ) ); if ( fractionalSeconds != null ) { - annotatedColumn.setTemporalPrecision( fractionalSeconds.value() ); + annotatedColumn.setTemporalPrecision( fractionalSeconds.getInteger( "value" ) ); } else { - annotatedColumn.setPrecision( column.precision() ); + annotatedColumn.setPrecision( column.getInteger( "precision" ) ); } - annotatedColumn.setScale( column.scale() ); + annotatedColumn.setScale( column.getInteger( "scale" ) ); annotatedColumn.handleArrayLength( inferredData ); -// annotatedColumn.setPropertyHolder( propertyHolder ); -// annotatedColumn.setPropertyName( getRelativePath( propertyHolder, inferredData.getPropertyName() ) ); - annotatedColumn.setNullable( column.nullable() ); //TODO force to not null if available? This is a (bad) user choice. -// if ( comment != null ) { -// annotatedColumn.setComment( comment.value() ); -// } - annotatedColumn.setUnique( column.unique() ); - annotatedColumn.setInsertable( column.insertable() ); - annotatedColumn.setUpdatable( column.updatable() ); + annotatedColumn.setNullable( column.getBoolean( "nullable" ) ); + annotatedColumn.setUnique( column.getBoolean( "unique" ) ); + annotatedColumn.setInsertable( column.getBoolean( "insertable" ) ); + annotatedColumn.setUpdatable( column.getBoolean( "updatable" ) ); annotatedColumn.setExplicitTableName( tableName ); -// annotatedColumn.setJoins( secondaryTables ); -// annotatedColumn.setBuildingContext( context ); annotatedColumn.setParent( parent ); annotatedColumn.applyColumnDefault( inferredData, numberOfColumns ); annotatedColumn.applyGeneratedAs( inferredData, numberOfColumns ); @@ -801,8 +802,8 @@ public class AnnotatedColumn { } private void handleArrayLength(PropertyData inferredData) { - if ( inferredData.getProperty().isAnnotationPresent(Array.class) ) { - setArrayLength( inferredData.getProperty().getAnnotation(Array.class).length() ); + if ( inferredData.getAttributeMember().hasAnnotationUsage( Array.class) ) { + setArrayLength( inferredData.getAttributeMember().getAnnotationUsage( Array.class).getInteger( "length" ) ); } } @@ -810,7 +811,7 @@ public class AnnotatedColumn { PropertyData inferredData, String suffixForDefaultColumnName, Database database, - jakarta.persistence.Column column) { + AnnotationUsage column) { final String columnName = getColumnName( database, column ); // NOTE : this is the logical column name, not the physical! return isEmpty( columnName ) && isNotEmpty( suffixForDefaultColumnName ) @@ -818,22 +819,27 @@ public class AnnotatedColumn { : columnName; } - private static String getColumnName(Database database, jakarta.persistence.Column column) { - return column.name().isEmpty() ? null - : database.getJdbcEnvironment().getIdentifierHelper().toIdentifier( column.name() ).render(); + private static String getColumnName(Database database, AnnotationUsage column) { + final String name = column.getString( "name" ); + return name.isEmpty() + ? null + : database.getJdbcEnvironment().getIdentifierHelper().toIdentifier( name ).render(); } void applyColumnDefault(PropertyData inferredData, int length) { - final XProperty property = inferredData.getProperty(); - if ( property != null ) { - final ColumnDefault columnDefault = - getOverridableAnnotation( property, ColumnDefault.class, getBuildingContext() ); + final MemberDetails attributeMember = inferredData.getAttributeMember(); + if ( attributeMember != null ) { + final AnnotationUsage columnDefault = getOverridableAnnotation( + attributeMember, + ColumnDefault.class, + getBuildingContext() + ); if ( columnDefault != null ) { if ( length != 1 ) { throw new AnnotationException( "'@ColumnDefault' may only be applied to single-column mappings but '" - + property.getName() + "' maps to " + length + " columns" ); + + attributeMember.getName() + "' maps to " + length + " columns" ); } - setDefaultValue( columnDefault.value() ); + setDefaultValue( columnDefault.getString( "value" ) ); } } else { @@ -842,16 +848,19 @@ public class AnnotatedColumn { } void applyGeneratedAs(PropertyData inferredData, int length) { - final XProperty property = inferredData.getProperty(); - if ( property != null ) { - final GeneratedColumn generatedColumn = - getOverridableAnnotation( property, GeneratedColumn.class, getBuildingContext() ); + final MemberDetails attributeMember = inferredData.getAttributeMember(); + if ( attributeMember != null ) { + final AnnotationUsage generatedColumn = getOverridableAnnotation( + attributeMember, + GeneratedColumn.class, + getBuildingContext() + ); if ( generatedColumn != null ) { if (length!=1) { throw new AnnotationException("'@GeneratedColumn' may only be applied to single-column mappings but '" - + property.getName() + "' maps to " + length + " columns" ); + + attributeMember.getName() + "' maps to " + length + " columns" ); } - setGeneratedAs( generatedColumn.value() ); + setGeneratedAs( generatedColumn.getString( "value" ) ); } } else { @@ -860,22 +869,30 @@ public class AnnotatedColumn { } private void applyCheckConstraint(PropertyData inferredData, int length) { - final XProperty property = inferredData.getProperty(); - if ( property != null ) { - if ( property.isAnnotationPresent( Checks.class ) ) { - // if there are multiple annotations, they're not overrideable - for ( Check check : property.getAnnotation( Checks.class ).value() ) { - addCheckConstraint( check.name().isEmpty() ? null : check.name(), check.constraints() ); + final MemberDetails attributeMember = inferredData.getAttributeMember(); + if ( attributeMember != null ) { + // if there are multiple annotations, they're not overrideable + final AnnotationUsage checksAnn = attributeMember.getAnnotationUsage( Checks.class ); + if ( checksAnn != null ) { + final List> checkAnns = checksAnn.getList( "value" ); + for ( AnnotationUsage checkAnn : checkAnns ) { + addCheckConstraint( + checkAnn.getString( "name", (String) null ), + checkAnn.getString( "constraints" ) + ); } } else { - final Check check = getOverridableAnnotation( property, Check.class, getBuildingContext() ); - if ( check != null ) { + final AnnotationUsage checkAnn = getOverridableAnnotation( attributeMember, Check.class, getBuildingContext() ); + if ( checkAnn != null ) { if ( length != 1 ) { throw new AnnotationException("'@Check' may only be applied to single-column mappings but '" - + property.getName() + "' maps to " + length + " columns (use a table-level '@Check')" ); + + attributeMember.getName() + "' maps to " + length + " columns (use a table-level '@Check')" ); } - addCheckConstraint( check.name().isEmpty() ? null : check.name(), check.constraints() ); + addCheckConstraint( + checkAnn.getString( "name", (String) null ), + checkAnn.getString( "constraints" ) + ); } } } @@ -887,35 +904,31 @@ public class AnnotatedColumn { //must only be called after all setters are defined and before binding private void extractDataFromPropertyData(PropertyHolder propertyHolder, PropertyData inferredData) { if ( inferredData != null ) { - final XProperty property = inferredData.getProperty(); - if ( property != null ) { + final MemberDetails attributeMember = inferredData.getAttributeMember(); + if ( attributeMember != null ) { if ( propertyHolder.isComponent() ) { processColumnTransformerExpressions( propertyHolder.getOverriddenColumnTransformer( logicalColumnName ) ); } - processColumnTransformerExpressions( property.getAnnotation( ColumnTransformer.class ) ); - final ColumnTransformers annotations = property.getAnnotation( ColumnTransformers.class ); - if ( annotations != null ) { - for ( ColumnTransformer annotation : annotations.value() ) { - processColumnTransformerExpressions( annotation ); - } - } + + attributeMember.forEachAnnotationUsage( ColumnTransformer.class, this::processColumnTransformerExpressions ); } } } - private void processColumnTransformerExpressions(ColumnTransformer annotation) { - if ( annotation != null ) { - if ( isEmpty( annotation.forColumn() ) - // "" is the default value for annotations - || annotation.forColumn().equals( logicalColumnName != null ? logicalColumnName : "" ) ) { - readExpression = nullIfEmpty( annotation.read() ); - writeExpression = nullIfEmpty( annotation.write() ); - } + private void processColumnTransformerExpressions(AnnotationUsage annotation) { + if ( annotation == null + // "" is the default value for annotations + || isEmpty( annotation.getString( "forColumn" ) ) + || annotation.getString( "forColumn" ).equals( logicalColumnName != null ? logicalColumnName : "" ) ) { + return; } + + readExpression = nullIfEmpty( annotation.getString( "read" ) ); + writeExpression = nullIfEmpty( annotation.getString( "write" ) ); } private static AnnotatedColumns buildImplicitColumn( - FractionalSeconds fractionalSeconds, + AnnotationUsage fractionalSeconds, PropertyData inferredData, String suffixForDefaultColumnName, Map secondaryTables, @@ -935,7 +948,7 @@ public class AnnotatedColumn { // } //not following the spec but more clean if ( nullability != Nullability.FORCED_NULL - && !PropertyBinder.isOptional( inferredData.getProperty(), propertyHolder ) ) { + && !PropertyBinder.isOptional( inferredData.getAttributeMember(), propertyHolder ) ) { column.setNullable( false ); } final String propertyName = inferredData.getPropertyName(); @@ -956,15 +969,15 @@ public class AnnotatedColumn { column.extractDataFromPropertyData( propertyHolder, inferredData ); column.handleArrayLength( inferredData ); if ( fractionalSeconds != null ) { - column.setTemporalPrecision( fractionalSeconds.value() ); + column.setTemporalPrecision( fractionalSeconds.getInteger( "value" ) ); } column.bind(); return columns; } - public void addIndex(Index index, boolean inSecondPass) { + public void addIndex(AnnotationUsage index, boolean inSecondPass) { if ( index != null ) { - addIndex( index.name(), inSecondPass ); + addIndex( index.getString( "name" ), inSecondPass ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java index 69cd7260ce..96bd3a6058 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java @@ -9,8 +9,8 @@ package org.hibernate.boot.model.internal; import org.hibernate.AssertionFailure; import org.hibernate.annotations.DiscriminatorFormula; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.AnnotationUsage; -import jakarta.persistence.AttributeOverride; import jakarta.persistence.Column; import jakarta.persistence.DiscriminatorColumn; import jakarta.persistence.DiscriminatorType; @@ -45,9 +45,9 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { } public static AnnotatedDiscriminatorColumn buildDiscriminatorColumn( - DiscriminatorColumn discriminatorColumn, - DiscriminatorFormula discriminatorFormula, - Column columnOverride, + AnnotationUsage discriminatorColumn, + AnnotationUsage discriminatorFormula, + AnnotationUsage columnOverride, String defaultColumnName, MetadataBuildingContext context) { final AnnotatedColumns parent = new AnnotatedColumns(); @@ -55,24 +55,24 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { final AnnotatedDiscriminatorColumn column = new AnnotatedDiscriminatorColumn( defaultColumnName ); final DiscriminatorType discriminatorType; if ( discriminatorFormula != null ) { - final DiscriminatorType type = discriminatorFormula.discriminatorType(); + final DiscriminatorType type = discriminatorFormula.getEnum( "discriminatorType" ); if ( type == DiscriminatorType.STRING ) { - discriminatorType = discriminatorColumn == null ? type : discriminatorColumn.discriminatorType(); + discriminatorType = discriminatorColumn == null ? type : discriminatorColumn.getEnum( "discriminatorType" ); } else { discriminatorType = type; } column.setImplicit( false ); - column.setFormula( discriminatorFormula.value() ); + column.setFormula( discriminatorFormula.getString( "value" ) ); } else if ( discriminatorColumn != null ) { - discriminatorType = discriminatorColumn.discriminatorType(); + discriminatorType = discriminatorColumn.getEnum( "discriminatorType" ); column.setImplicit( false ); - if ( !discriminatorColumn.columnDefinition().isEmpty() ) { - column.setSqlType( discriminatorColumn.columnDefinition() ); + if ( !discriminatorColumn.getString( "columnDefinition" ).isEmpty() ) { + column.setSqlType( discriminatorColumn.getString( "columnDefinition" ) ); } - if ( !discriminatorColumn.name().isEmpty() ) { - column.setLogicalColumnName( discriminatorColumn.name() ); + if ( !discriminatorColumn.getString( "name" ).isEmpty() ) { + column.setLogicalColumnName( discriminatorColumn.getString( "name" ) ); } column.setNullable( false ); } @@ -81,9 +81,11 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { column.setImplicit( true ); } if ( columnOverride != null ) { - column.setLogicalColumnName( columnOverride.name() ); - if ( !columnOverride.columnDefinition().isEmpty() ) { - column.setSqlType( columnOverride.columnDefinition() ); + column.setLogicalColumnName( columnOverride.getString( "name" ) ); + + final String columnDefinition = columnOverride.getString( "columnDefinition" ); + if ( !columnDefinition.isEmpty() ) { + column.setSqlType( columnDefinition ); } } setDiscriminatorType( discriminatorType, discriminatorColumn, columnOverride, column ); @@ -94,8 +96,8 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { private static void setDiscriminatorType( DiscriminatorType type, - DiscriminatorColumn discriminatorColumn, - Column columnOverride, + AnnotationUsage discriminatorColumn, + AnnotationUsage columnOverride, AnnotatedDiscriminatorColumn column) { if ( type == null ) { column.setDiscriminatorTypeName( "string" ); @@ -114,10 +116,10 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { case STRING: column.setDiscriminatorTypeName( "string" ); if ( columnOverride != null ) { - column.setLength( (long) columnOverride.length() ); + column.setLength( (long) columnOverride.getInteger( "length" ) ); } else if ( discriminatorColumn != null ) { - column.setLength( (long) discriminatorColumn.length() ); + column.setLength( (long) discriminatorColumn.getInteger( "length" ) ); } break; default: diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java index 8b689e9161..58b0d9ed83 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java @@ -6,6 +6,8 @@ */ package org.hibernate.boot.model.internal; +import java.util.List; + import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.annotations.JoinFormula; @@ -19,6 +21,7 @@ import org.hibernate.mapping.Column; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Value; +import org.hibernate.models.spi.AnnotationUsage; import jakarta.persistence.JoinColumn; import jakarta.persistence.PrimaryKeyJoinColumn; @@ -71,13 +74,13 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { } static AnnotatedJoinColumn buildJoinColumn( - JoinColumn joinColumn, + AnnotationUsage joinColumn, String mappedBy, AnnotatedJoinColumns parent, PropertyHolder propertyHolder, PropertyData inferredData) { final String path = qualify( propertyHolder.getPath(), inferredData.getPropertyName() ); - final JoinColumn[] overrides = propertyHolder.getOverriddenJoinColumn( path ); + final List> overrides = propertyHolder.getOverriddenJoinColumn( path ); if ( overrides != null ) { //TODO: relax this restriction throw new AnnotationException( "Property '" + path @@ -87,11 +90,11 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { } public static AnnotatedJoinColumn buildJoinFormula( - JoinFormula joinFormula, + AnnotationUsage joinFormula, AnnotatedJoinColumns parent) { final AnnotatedJoinColumn formulaColumn = new AnnotatedJoinColumn(); - formulaColumn.setFormula( joinFormula.value() ); - formulaColumn.setReferencedColumn( joinFormula.referencedColumnName() ); + formulaColumn.setFormula( joinFormula.getString( "value" ) ); + formulaColumn.setReferencedColumn( joinFormula.getString( "referencedColumnName" ) ); // formulaColumn.setContext( buildingContext ); // formulaColumn.setPropertyHolder( propertyHolder ); // formulaColumn.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); @@ -102,7 +105,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { } static AnnotatedJoinColumn buildJoinColumn( - JoinColumn joinColumn, + AnnotationUsage joinColumn, // Comment comment, String mappedBy, AnnotatedJoinColumns parent, @@ -123,7 +126,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { } private static AnnotatedJoinColumn explicitJoinColumn( - JoinColumn joinColumn, + AnnotationUsage joinColumn, // Comment comment, AnnotatedJoinColumns parent, PropertyData inferredData, @@ -170,31 +173,36 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { // TODO default name still useful in association table - public void applyJoinAnnotation(JoinColumn joinColumn, String defaultName) { + public void applyJoinAnnotation(AnnotationUsage joinColumn, String defaultName) { if ( joinColumn == null ) { setImplicit( true ); } else { setImplicit( false ); - if ( !joinColumn.columnDefinition().isEmpty() ) { - setSqlType( getBuildingContext().getObjectNameNormalizer() - .applyGlobalQuoting( joinColumn.columnDefinition() ) ); - } - if ( !joinColumn.name().isEmpty() ) { - setLogicalColumnName( joinColumn.name() ); - } - setNullable( joinColumn.nullable() ); - setUnique( joinColumn.unique() ); - setInsertable( joinColumn.insertable() ); - setUpdatable( joinColumn.updatable() ); - setReferencedColumn( joinColumn.referencedColumnName() ); - if ( joinColumn.table().isEmpty() ) { + final String name = joinColumn.getString( "name" ); + if ( !name.isEmpty() ) { + setLogicalColumnName( name ); + } + + final String columnDefinition = joinColumn.getString( "columnDefinition" ); + if ( !columnDefinition.isEmpty() ) { + setSqlType( getBuildingContext().getObjectNameNormalizer().applyGlobalQuoting( columnDefinition ) ); + } + + setNullable( joinColumn.getBoolean( "nullable" ) ); + setUnique( joinColumn.getBoolean( "unique" ) ); + setInsertable( joinColumn.getBoolean( "insertable" ) ); + setUpdatable( joinColumn.getBoolean( "updatable" ) ); + setReferencedColumn( joinColumn.getString( "referencedColumnName" ) ); + + final String table = joinColumn.getString( "table" ); + if ( table.isEmpty() ) { setExplicitTableName( "" ); } else { final Database database = getBuildingContext().getMetadataCollector().getDatabase(); - final Identifier logicalIdentifier = database.toIdentifier( joinColumn.table() ); + final Identifier logicalIdentifier = database.toIdentifier( table ); final Identifier physicalIdentifier = getBuildingContext().getBuildingOptions() .getPhysicalNamingStrategy() .toPhysicalTableName( logicalIdentifier, database.getJdbcEnvironment() ); @@ -207,8 +215,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { * Called for {@link jakarta.persistence.InheritanceType#JOINED} entities. */ public static AnnotatedJoinColumn buildInheritanceJoinColumn( - PrimaryKeyJoinColumn primaryKeyJoinColumn, - JoinColumn joinColumn, + AnnotationUsage primaryKeyJoinColumn, + AnnotationUsage joinColumn, Value identifier, AnnotatedJoinColumns parent, MetadataBuildingContext context) { @@ -220,8 +228,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { } private static AnnotatedJoinColumn buildExplicitInheritanceJoinColumn( - PrimaryKeyJoinColumn primaryKeyJoinColumn, - JoinColumn joinColumn, + AnnotationUsage primaryKeyJoinColumn, + AnnotationUsage joinColumn, AnnotatedJoinColumns parent, MetadataBuildingContext context, String defaultColumnName) { @@ -229,15 +237,16 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { final String columnDefinition; final String referencedColumnName; if ( primaryKeyJoinColumn != null ) { - columnName = primaryKeyJoinColumn.name(); - columnDefinition = primaryKeyJoinColumn.columnDefinition(); - referencedColumnName = primaryKeyJoinColumn.referencedColumnName(); + columnName = primaryKeyJoinColumn.getString( "name" ); + columnDefinition = primaryKeyJoinColumn.getString( "columnDefinition" ); + referencedColumnName = primaryKeyJoinColumn.getString( "referencedColumnName" ); } else { - columnName = joinColumn.name(); - columnDefinition = joinColumn.columnDefinition(); - referencedColumnName = joinColumn.referencedColumnName(); + columnName = joinColumn.getString( "name" ); + columnDefinition = joinColumn.getString( "columnDefinition" ); + referencedColumnName = joinColumn.getString( "referencedColumnName" ); } + final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer(); final String columnDef = columnDefinition.isEmpty() ? null : normalizer.toDatabaseIdentifierText( columnDefinition ); @@ -459,7 +468,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { AnnotatedJoinColumns parent, PropertyHolder propertyHolder, PropertyData inferredData, - JoinColumn joinColumn) { + AnnotationUsage joinColumn) { final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); column.setImplicit( true ); // column.setPropertyHolder( propertyHolder ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java index 95b1cd485a..50d29b1f62 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java @@ -29,6 +29,7 @@ import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.PropertyData; import org.hibernate.cfg.RecoverableException; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Column; import org.hibernate.mapping.Component; import org.hibernate.mapping.Join; @@ -38,6 +39,7 @@ import org.hibernate.mapping.Property; import org.hibernate.mapping.Selectable; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; import jakarta.persistence.JoinColumn; @@ -75,7 +77,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { private String manyToManyOwnerSideEntityName; public static AnnotatedJoinColumns buildJoinColumnsOrFormulas( - JoinColumnOrFormula[] joinColumnOrFormulas, + List> joinColumnOrFormulas, String mappedBy, Map joins, PropertyHolder propertyHolder, @@ -87,10 +89,10 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { parent.setPropertyHolder( propertyHolder ); parent.setPropertyName( getRelativePath( propertyHolder, inferredData.getPropertyName() ) ); parent.setMappedBy( mappedBy ); - for ( JoinColumnOrFormula columnOrFormula : joinColumnOrFormulas ) { - final JoinFormula formula = columnOrFormula.formula(); - final JoinColumn column = columnOrFormula.column(); - final String annotationString = formula.value(); + for ( AnnotationUsage columnOrFormula : joinColumnOrFormulas ) { + final AnnotationUsage formula = columnOrFormula.getNestedUsage( "formula" ); + final AnnotationUsage column = columnOrFormula.getNestedUsage( "column" ); + final String annotationString = formula.getString( "value" ); if ( isNotEmpty( annotationString ) ) { AnnotatedJoinColumn.buildJoinFormula( formula, parent ); } @@ -102,7 +104,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { } static AnnotatedJoinColumns buildJoinColumnsWithFormula( - JoinFormula joinFormula, + AnnotationUsage joinFormula, Map secondaryTables, PropertyHolder propertyHolder, PropertyData inferredData, @@ -117,7 +119,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { } public static AnnotatedJoinColumns buildJoinColumns( - JoinColumn[] joinColumns, + List> joinColumns, // Comment comment, String mappedBy, Map joins, @@ -137,7 +139,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { } public static AnnotatedJoinColumns buildJoinColumnsWithDefaultColumnSuffix( - JoinColumn[] joinColumns, + List> joinColumns, // Comment comment, String mappedBy, Map joins, @@ -148,15 +150,15 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { assert mappedBy == null || !mappedBy.isEmpty(); final String propertyName = inferredData.getPropertyName(); final String path = qualify( propertyHolder.getPath(), propertyName ); - final JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( path ); - final JoinColumn[] actualColumns = overriddes == null ? joinColumns : overriddes; + final List> overrides = propertyHolder.getOverriddenJoinColumn( path ); + final List> actualColumns = overrides == null ? joinColumns : overrides; final AnnotatedJoinColumns parent = new AnnotatedJoinColumns(); parent.setBuildingContext( context ); parent.setJoins( joins ); parent.setPropertyHolder( propertyHolder ); parent.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); parent.setMappedBy( mappedBy ); - if ( actualColumns == null || actualColumns.length == 0 ) { + if ( CollectionHelper.isEmpty( actualColumns ) ) { AnnotatedJoinColumn.buildJoinColumn( null, // comment, @@ -169,7 +171,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { } else { parent.setMappedBy( mappedBy ); - for ( JoinColumn actualColumn : actualColumns ) { + for ( AnnotationUsage actualColumn : actualColumns ) { AnnotatedJoinColumn.buildJoinColumn( actualColumn, // comment, @@ -188,7 +190,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { * Called for join tables in {@link jakarta.persistence.ManyToMany} associations. */ public static AnnotatedJoinColumns buildJoinTableJoinColumns( - JoinColumn[] joinColumns, + List> joinColumns, Map secondaryTables, PropertyHolder propertyHolder, PropertyData inferredData, @@ -204,7 +206,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { AnnotatedJoinColumn.buildImplicitJoinTableJoinColumn( parent, propertyHolder, inferredData ); } else { - for ( JoinColumn joinColumn : joinColumns ) { + for ( AnnotationUsage joinColumn : joinColumns ) { AnnotatedJoinColumn.buildExplicitJoinTableJoinColumn( parent, propertyHolder, inferredData, joinColumn ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java index 44aaffdec9..08c7a5cc53 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java @@ -11,39 +11,30 @@ import java.util.List; import java.util.Map; import org.hibernate.AnnotationException; -import org.hibernate.Internal; import org.hibernate.MappingException; import org.hibernate.annotations.CollectionTypeRegistration; -import org.hibernate.annotations.CollectionTypeRegistrations; import org.hibernate.annotations.CompositeTypeRegistration; -import org.hibernate.annotations.CompositeTypeRegistrations; import org.hibernate.annotations.ConverterRegistration; -import org.hibernate.annotations.ConverterRegistrations; import org.hibernate.annotations.EmbeddableInstantiatorRegistration; -import org.hibernate.annotations.EmbeddableInstantiatorRegistrations; import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.FetchProfile; import org.hibernate.annotations.FetchProfile.FetchOverride; -import org.hibernate.annotations.FetchProfiles; import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.GenericGenerators; import org.hibernate.annotations.Imported; import org.hibernate.annotations.JavaTypeRegistration; -import org.hibernate.annotations.JavaTypeRegistrations; import org.hibernate.annotations.JdbcTypeRegistration; -import org.hibernate.annotations.JdbcTypeRegistrations; import org.hibernate.annotations.TypeRegistration; -import org.hibernate.annotations.TypeRegistrations; -import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XPackage; +import org.hibernate.boot.internal.GenerationStrategyInterpreter; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.convert.spi.RegisteredConversion; +import org.hibernate.boot.models.categorize.spi.GlobalRegistrations; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.type.descriptor.java.BasicJavaType; @@ -54,19 +45,13 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Inheritance; import jakarta.persistence.InheritanceType; import jakarta.persistence.MappedSuperclass; -import jakarta.persistence.NamedNativeQueries; import jakarta.persistence.NamedNativeQuery; -import jakarta.persistence.NamedQueries; import jakarta.persistence.NamedQuery; -import jakarta.persistence.NamedStoredProcedureQueries; import jakarta.persistence.NamedStoredProcedureQuery; import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.SequenceGenerators; import jakarta.persistence.SqlResultSetMapping; -import jakarta.persistence.SqlResultSetMappings; import jakarta.persistence.Table; import jakarta.persistence.TableGenerator; -import jakarta.persistence.TableGenerators; import static org.hibernate.boot.model.internal.AnnotatedClassType.EMBEDDABLE; import static org.hibernate.boot.model.internal.AnnotatedClassType.ENTITY; @@ -94,120 +79,58 @@ public final class AnnotationBinder { private AnnotationBinder() {} public static void bindDefaults(MetadataBuildingContext context) { + // todo (jpa32) - remove this. left for now for easy debugging final Map defaults = context.getBootstrapContext().getReflectionManager().getDefaults(); + final GlobalRegistrations globalRegistrations = context.getMetadataCollector().getGlobalRegistrations(); // id generators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - { - @SuppressWarnings("unchecked") - List generators = ( List ) defaults.get( SequenceGenerator.class ); - if ( generators != null ) { - for ( SequenceGenerator sequenceGenerator : generators ) { - final IdentifierGeneratorDefinition idGen = buildIdGenerator( sequenceGenerator, context ); - if ( idGen != null ) { - context.getMetadataCollector().addDefaultIdentifierGenerator( idGen ); - } - } + globalRegistrations.getSequenceGeneratorRegistrations().forEach( (name, generatorRegistration) -> { + final IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder(); + GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretSequenceGenerator( + generatorRegistration.configuration(), + definitionBuilder + ); + final IdentifierGeneratorDefinition idGenDef = definitionBuilder.build(); + if ( LOG.isTraceEnabled() ) { + LOG.tracef( "Adding global sequence generator with name: %s", name ); } - } - { - @SuppressWarnings("unchecked") - List generators = ( List ) defaults.get( TableGenerator.class ); - if ( generators != null ) { - for ( TableGenerator tableGenerator : generators ) { - final IdentifierGeneratorDefinition idGen = buildIdGenerator( tableGenerator, context ); - if ( idGen != null ) { - context.getMetadataCollector().addDefaultIdentifierGenerator( idGen ); - } - } - } - } + context.getMetadataCollector().addDefaultIdentifierGenerator( idGenDef ); + } ); - { - @SuppressWarnings("unchecked") - List generators = (List) defaults.get( TableGenerators.class ); - if ( generators != null ) { - generators.forEach( tableGenerators -> { - for ( TableGenerator tableGenerator : tableGenerators.value() ) { - final IdentifierGeneratorDefinition idGen = buildIdGenerator( tableGenerator, context ); - if ( idGen != null ) { - context.getMetadataCollector().addDefaultIdentifierGenerator( idGen ); - } - } - } ); + globalRegistrations.getTableGeneratorRegistrations().forEach( (name, generatorRegistration) -> { + final IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder(); + GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretTableGenerator( + generatorRegistration.configuration(), + definitionBuilder + ); + final IdentifierGeneratorDefinition idGenDef = definitionBuilder.build(); + if ( LOG.isTraceEnabled() ) { + LOG.tracef( "Adding global table generator with name: %s", name ); } - } - - { - @SuppressWarnings("unchecked") - List generators = (List) defaults.get( SequenceGenerators.class ); - if ( generators != null ) { - generators.forEach( sequenceGenerators -> { - for ( SequenceGenerator sequenceGenerator : sequenceGenerators.value() ) { - final IdentifierGeneratorDefinition idGen = buildIdGenerator( sequenceGenerator, context ); - if ( idGen != null ) { - context.getMetadataCollector().addDefaultIdentifierGenerator( idGen ); - } - } - } ); - } - } - - // queries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - { - @SuppressWarnings("unchecked") - List queries = ( List ) defaults.get( NamedQuery.class ); - if ( queries != null ) { - for ( NamedQuery ann : queries ) { - QueryBinder.bindQuery( ann, context, true ); - } - } - } - { - @SuppressWarnings("unchecked") - List nativeQueries = ( List ) defaults.get( NamedNativeQuery.class ); - if ( nativeQueries != null ) { - for ( NamedNativeQuery ann : nativeQueries ) { - QueryBinder.bindNativeQuery( ann, context, true ); - } - } - } + context.getMetadataCollector().addDefaultIdentifierGenerator( idGenDef ); + } ); // result-set-mappings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - { - @SuppressWarnings("unchecked") - List mappings = ( List ) defaults.get( SqlResultSetMapping.class ); - if ( mappings != null ) { - for ( SqlResultSetMapping annotation : mappings ) { - QueryBinder.bindSqlResultSetMapping( annotation, context, true ); - } - } - } + globalRegistrations.getSqlResultSetMappingRegistrations().forEach( (name, mappingRegistration) -> { + QueryBinder.bindSqlResultSetMapping( mappingRegistration.configuration(), context, true ); + } ); - // stored procs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - { - @SuppressWarnings("unchecked") - final List storedProcedureQueries = - (List) defaults.get( NamedStoredProcedureQuery.class ); - if ( storedProcedureQueries != null ) { - for ( NamedStoredProcedureQuery annotation : storedProcedureQueries ) { - bindNamedStoredProcedureQuery( annotation, context, true ); - } - } - } - { - @SuppressWarnings("unchecked") - final List storedProcedureQueries = - (List) defaults.get( NamedStoredProcedureQueries.class ); - if ( storedProcedureQueries != null ) { - for ( NamedStoredProcedureQueries annotation : storedProcedureQueries ) { - bindNamedStoredProcedureQueries( annotation, context, true ); - } - } - } + // queries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + globalRegistrations.getNamedQueryRegistrations().forEach( (name, queryRegistration) -> { + QueryBinder.bindQuery( queryRegistration.configuration(), context, true ); + } ); + + globalRegistrations.getNamedNativeQueryRegistrations().forEach( (name, queryRegistration) -> { + QueryBinder.bindNativeQuery( queryRegistration.configuration(), context, true ); + } ); + + globalRegistrations.getNamedStoredProcedureQueryRegistrations().forEach( (name, queryRegistration) -> { + QueryBinder.bindNamedStoredProcedureQuery( queryRegistration.configuration(), context, true ); + } ); } public static void bindPackage(ClassLoaderService cls, String packageName, MetadataBuildingContext context) { @@ -215,448 +138,307 @@ public final class AnnotationBinder { if ( pack == null ) { return; } - final XPackage annotatedPackage = context.getBootstrapContext().getReflectionManager().toXPackage( pack ); + final ClassDetails packageInfoClassDetails = context.getMetadataCollector() + .getSourceModelBuildingContext() + .getClassDetailsRegistry() + .resolveClassDetails( pack.getName() + ".package-info" ); - handleIdGenerators( annotatedPackage, context ); + handleIdGenerators( packageInfoClassDetails, context ); - bindTypeDescriptorRegistrations( annotatedPackage, context ); - bindEmbeddableInstantiatorRegistrations( annotatedPackage, context ); - bindUserTypeRegistrations( annotatedPackage, context ); - bindCompositeUserTypeRegistrations( annotatedPackage, context ); - bindConverterRegistrations( annotatedPackage, context ); + bindTypeDescriptorRegistrations( packageInfoClassDetails, context ); + bindEmbeddableInstantiatorRegistrations( packageInfoClassDetails, context ); + bindUserTypeRegistrations( packageInfoClassDetails, context ); + bindCompositeUserTypeRegistrations( packageInfoClassDetails, context ); + bindConverterRegistrations( packageInfoClassDetails, context ); - bindGenericGenerators( annotatedPackage, context ); - bindQueries( annotatedPackage, context ); - bindFilterDefs( annotatedPackage, context ); + bindGenericGenerators( packageInfoClassDetails, context ); + bindQueries( packageInfoClassDetails, context ); + bindFilterDefs( packageInfoClassDetails, context ); } - private static void handleIdGenerators(XPackage annotatedPackage, MetadataBuildingContext context) { - if ( annotatedPackage.isAnnotationPresent( SequenceGenerator.class ) ) { - final SequenceGenerator sequenceGenerator = annotatedPackage.getAnnotation( SequenceGenerator.class ); - IdentifierGeneratorDefinition idGen = buildIdGenerator( sequenceGenerator, context ); + private static void handleIdGenerators(ClassDetails packageInfoClassDetails, MetadataBuildingContext context) { + packageInfoClassDetails.forEachAnnotationUsage( SequenceGenerator.class, (usage) -> { + IdentifierGeneratorDefinition idGen = buildIdGenerator( usage, context ); context.getMetadataCollector().addIdentifierGenerator( idGen ); if ( LOG.isTraceEnabled() ) { LOG.tracev( "Add sequence generator with name: {0}", idGen.getName() ); } - } - if ( annotatedPackage.isAnnotationPresent( SequenceGenerators.class ) ) { - final SequenceGenerators sequenceGenerators = annotatedPackage.getAnnotation( SequenceGenerators.class ); - for ( SequenceGenerator tableGenerator : sequenceGenerators.value() ) { - context.getMetadataCollector().addIdentifierGenerator( buildIdGenerator( tableGenerator, context ) ); - } - } + } ); - if ( annotatedPackage.isAnnotationPresent( TableGenerator.class ) ) { - final TableGenerator tableGenerator = annotatedPackage.getAnnotation( TableGenerator.class ); - IdentifierGeneratorDefinition idGen = buildIdGenerator( tableGenerator, context ); + packageInfoClassDetails.forEachAnnotationUsage( TableGenerator.class, (usage) -> { + IdentifierGeneratorDefinition idGen = buildIdGenerator( usage, context ); context.getMetadataCollector().addIdentifierGenerator( idGen ); - } - if ( annotatedPackage.isAnnotationPresent( TableGenerators.class ) ) { - final TableGenerators tableGenerators = annotatedPackage.getAnnotation( TableGenerators.class ); - for ( TableGenerator tableGenerator : tableGenerators.value() ) { - context.getMetadataCollector().addIdentifierGenerator( buildIdGenerator( tableGenerator, context ) ); + if ( LOG.isTraceEnabled() ) { + LOG.tracev( "Add table generator with name: {0}", idGen.getName() ); } - } + } ); } - private static void bindGenericGenerators(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { - final GenericGenerator genericGenerator = annotatedElement.getAnnotation( GenericGenerator.class ); - final GenericGenerators genericGenerators = annotatedElement.getAnnotation( GenericGenerators.class ); - if ( genericGenerator != null ) { - bindGenericGenerator( genericGenerator, context ); - } - if ( genericGenerators != null ) { - for ( GenericGenerator generator : genericGenerators.value() ) { - bindGenericGenerator( generator, context ); - } - } + private static void bindGenericGenerators(AnnotationTarget annotatedElement, MetadataBuildingContext context) { + annotatedElement.forEachAnnotationUsage( GenericGenerator.class, (usage) -> { + bindGenericGenerator( usage, context ); + } ); } - private static void bindGenericGenerator(GenericGenerator def, MetadataBuildingContext context) { + private static void bindGenericGenerator(AnnotationUsage def, MetadataBuildingContext context) { context.getMetadataCollector().addIdentifierGenerator( buildIdGenerator( def, context ) ); } - private static void bindNamedJpaQueries(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { - QueryBinder.bindSqlResultSetMapping( - annotatedElement.getAnnotation( SqlResultSetMapping.class ), - context, - false - ); - - QueryBinder.bindSqlResultSetMappings( - annotatedElement.getAnnotation( SqlResultSetMappings.class ), - context, - false - ); - - QueryBinder.bindQuery( - annotatedElement.getAnnotation( NamedQuery.class ), - context, - false - ); - - QueryBinder.bindQueries( - annotatedElement.getAnnotation( NamedQueries.class ), - context, - false - ); - - QueryBinder.bindNativeQuery( - annotatedElement.getAnnotation( NamedNativeQuery.class ), - context, - false - ); - - QueryBinder.bindNativeQueries( - annotatedElement.getAnnotation( NamedNativeQueries.class ), - context, - false - ); + public static void bindQueries(AnnotationTarget annotationTarget, MetadataBuildingContext context) { + bindNamedJpaQueries( annotationTarget, context ); + bindNamedHibernateQueries( annotationTarget, context ); } - public static void bindQueries(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { - bindNamedJpaQueries( annotatedElement, context ); - - QueryBinder.bindQuery( - annotatedElement.getAnnotation( org.hibernate.annotations.NamedQuery.class ), + private static void bindNamedHibernateQueries(AnnotationTarget annotationTarget, MetadataBuildingContext context) { + annotationTarget.forEachAnnotationUsage( org.hibernate.annotations.NamedQuery.class, (usage) -> QueryBinder.bindQuery( + usage, context - ); + ) ); - QueryBinder.bindQueries( - annotatedElement.getAnnotation( org.hibernate.annotations.NamedQueries.class ), + annotationTarget.forEachAnnotationUsage( org.hibernate.annotations.NamedNativeQuery.class, (usage) -> QueryBinder.bindNativeQuery( + usage, context - ); - - QueryBinder.bindNativeQuery( - annotatedElement.getAnnotation( org.hibernate.annotations.NamedNativeQuery.class ), - context - ); - - QueryBinder.bindNativeQueries( - annotatedElement.getAnnotation( org.hibernate.annotations.NamedNativeQueries.class ), - context - ); - - // NamedStoredProcedureQuery handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - bindNamedStoredProcedureQuery( - annotatedElement.getAnnotation( NamedStoredProcedureQuery.class ), - context, - false - ); - - // NamedStoredProcedureQueries handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - bindNamedStoredProcedureQueries( - annotatedElement.getAnnotation( NamedStoredProcedureQueries.class ), - context, - false - ); + ) ); } - private static void bindNamedStoredProcedureQueries( - NamedStoredProcedureQueries annotation, - MetadataBuildingContext context, - boolean isDefault) { - if ( annotation != null ) { - for ( NamedStoredProcedureQuery queryAnnotation : annotation.value() ) { - bindNamedStoredProcedureQuery( queryAnnotation, context, isDefault ); - } - } - } + private static void bindNamedJpaQueries(AnnotationTarget annotationTarget, MetadataBuildingContext context) { + annotationTarget.forEachAnnotationUsage( SqlResultSetMapping.class, (usage) -> QueryBinder.bindSqlResultSetMapping( + usage, + context, + false + ) ); - private static void bindNamedStoredProcedureQuery( - NamedStoredProcedureQuery annotation, - MetadataBuildingContext context, - boolean isDefault) { - if ( annotation != null ) { - QueryBinder.bindNamedStoredProcedureQuery( annotation, context, isDefault ); - } + annotationTarget.forEachAnnotationUsage( NamedQuery.class, (usage) -> QueryBinder.bindQuery( + usage, + context, + false + ) ); + + annotationTarget.forEachAnnotationUsage( NamedNativeQuery.class, (usage) -> QueryBinder.bindNativeQuery( + usage, + context, + false + ) ); + + annotationTarget.forEachAnnotationUsage( NamedStoredProcedureQuery.class, (usage) -> QueryBinder.bindNamedStoredProcedureQuery( + usage, + context, + false + ) ); } /** * Bind an annotated class. A subclass must be bound after its superclass. * - * @param annotatedClass entity to bind as {@code XClass} instance + * @param classDetails entity to bind as {@code XClass} instance * @param inheritanceStatePerClass Metadata about the inheritance relationships for all mapped classes * * @throws MappingException in case there is a configuration error */ public static void bindClass( - XClass annotatedClass, - Map inheritanceStatePerClass, + ClassDetails classDetails, + Map inheritanceStatePerClass, MetadataBuildingContext context) throws MappingException { - detectMappedSuperclassProblems( annotatedClass ); + detectMappedSuperclassProblems( classDetails ); - bindQueries( annotatedClass, context ); - handleImport( annotatedClass, context ); - //bindFilterDefs( annotatedClass, context ); - bindTypeDescriptorRegistrations( annotatedClass, context ); - bindEmbeddableInstantiatorRegistrations( annotatedClass, context ); - bindUserTypeRegistrations( annotatedClass, context ); - bindCompositeUserTypeRegistrations( annotatedClass, context ); - bindConverterRegistrations( annotatedClass, context ); + bindQueries( classDetails, context ); + handleImport( classDetails, context ); + //bindFilterDefs( classDetails, context ); + bindTypeDescriptorRegistrations( classDetails, context ); + bindEmbeddableInstantiatorRegistrations( classDetails, context ); + bindUserTypeRegistrations( classDetails, context ); + bindCompositeUserTypeRegistrations( classDetails, context ); + bindConverterRegistrations( classDetails, context ); // try to find class level generators - final Map generators = buildGenerators( annotatedClass, context ); - if ( context.getMetadataCollector().getClassType( annotatedClass ) == ENTITY ) { - EntityBinder.bindEntityClass( annotatedClass, inheritanceStatePerClass, generators, context ); + final Map generators = buildGenerators( classDetails, context ); + if ( context.getMetadataCollector().getClassType( classDetails ) == ENTITY ) { + EntityBinder.bindEntityClass( classDetails, inheritanceStatePerClass, generators, context ); } } - private static void handleImport(XClass annotatedClass, MetadataBuildingContext context) { - if ( annotatedClass.isAnnotationPresent( Imported.class ) ) { - String qualifiedName = annotatedClass.getName(); - String name = unqualify( qualifiedName ); - String rename = annotatedClass.getAnnotation( Imported.class ).rename(); + private static void handleImport(ClassDetails annotatedClass, MetadataBuildingContext context) { + if ( annotatedClass.hasAnnotationUsage( Imported.class ) ) { + final String qualifiedName = annotatedClass.getName(); + final String name = unqualify( qualifiedName ); + final String rename = annotatedClass.getAnnotationUsage( Imported.class ).getString( "rename" ); context.getMetadataCollector().addImport( rename.isEmpty() ? name : rename, qualifiedName ); } } - private static void detectMappedSuperclassProblems(XClass annotatedClass) { - if ( annotatedClass.isAnnotationPresent( MappedSuperclass.class ) ) { + private static void detectMappedSuperclassProblems(ClassDetails annotatedClass) { + if ( annotatedClass.hasAnnotationUsage( MappedSuperclass.class ) ) { //@Entity and @MappedSuperclass on the same class leads to a NPE down the road - if ( annotatedClass.isAnnotationPresent( Entity.class ) ) { + if ( annotatedClass.hasAnnotationUsage( Entity.class ) ) { throw new AnnotationException( "Type '" + annotatedClass.getName() + "' is annotated both '@Entity' and '@MappedSuperclass'" ); } - if ( annotatedClass.isAnnotationPresent( Table.class ) ) { + if ( annotatedClass.hasAnnotationUsage( Table.class ) ) { throw new AnnotationException( "Mapped superclass '" + annotatedClass.getName() + "' may not specify a '@Table'" ); } - if ( annotatedClass.isAnnotationPresent( Inheritance.class ) ) { + if ( annotatedClass.hasAnnotationUsage( Inheritance.class ) ) { throw new AnnotationException( "Mapped superclass '" + annotatedClass.getName() + "' may not specify an '@Inheritance' mapping strategy" ); } } } - private static void bindTypeDescriptorRegistrations(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { + private static void bindTypeDescriptorRegistrations( + AnnotationTarget annotatedElement, + MetadataBuildingContext context) { final ManagedBeanRegistry managedBeanRegistry = context.getBootstrapContext() .getServiceRegistry() .getService( ManagedBeanRegistry.class ); - final JavaTypeRegistration javaTypeRegistration = - annotatedElement.getAnnotation( JavaTypeRegistration.class ); - if ( javaTypeRegistration != null ) { - handleJavaTypeRegistration( context, managedBeanRegistry, javaTypeRegistration ); - } - else { - final JavaTypeRegistrations javaTypeRegistrations = - annotatedElement.getAnnotation( JavaTypeRegistrations.class ); - if ( javaTypeRegistrations != null ) { - for ( JavaTypeRegistration registration : javaTypeRegistrations.value() ) { - handleJavaTypeRegistration( context, managedBeanRegistry, registration ); - } - } - } + annotatedElement.forEachAnnotationUsage( JavaTypeRegistration.class, (usage) -> { + handleJavaTypeRegistration( context, managedBeanRegistry, usage ); + } ); - final JdbcTypeRegistration jdbcTypeRegistration = - annotatedElement.getAnnotation( JdbcTypeRegistration.class ); - if ( jdbcTypeRegistration != null ) { - handleJdbcTypeRegistration( context, managedBeanRegistry, jdbcTypeRegistration ); - } - else { - final JdbcTypeRegistrations jdbcTypeRegistrations = - annotatedElement.getAnnotation( JdbcTypeRegistrations.class ); - if ( jdbcTypeRegistrations != null ) { - for ( JdbcTypeRegistration registration : jdbcTypeRegistrations.value() ) { - handleJdbcTypeRegistration( context, managedBeanRegistry, registration ); - } - } - } + annotatedElement.forEachAnnotationUsage( JdbcTypeRegistration.class, (usage) -> { + handleJdbcTypeRegistration( context, managedBeanRegistry, usage ); + } ); - final CollectionTypeRegistration collectionTypeRegistration = - annotatedElement.getAnnotation( CollectionTypeRegistration.class ); - if ( collectionTypeRegistration != null ) { - context.getMetadataCollector().addCollectionTypeRegistration( collectionTypeRegistration ); - } - - final CollectionTypeRegistrations collectionTypeRegistrations = - annotatedElement.getAnnotation( CollectionTypeRegistrations.class ); - if ( collectionTypeRegistrations != null ) { - for ( CollectionTypeRegistration registration : collectionTypeRegistrations.value() ) { - context.getMetadataCollector().addCollectionTypeRegistration( registration ); - } - } + annotatedElement.forEachAnnotationUsage( CollectionTypeRegistration.class, (usage) -> { + context.getMetadataCollector().addCollectionTypeRegistration( usage ); + } ); } private static void handleJdbcTypeRegistration( MetadataBuildingContext context, ManagedBeanRegistry managedBeanRegistry, - JdbcTypeRegistration annotation) { - final Class jdbcTypeClass = annotation.value(); + AnnotationUsage annotation) { + final Class jdbcTypeClass = annotation.getClassDetails( "value" ).toJavaClass(); final JdbcType jdbcType = !context.getBuildingOptions().isAllowExtensionsInCdi() ? FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( jdbcTypeClass ) : managedBeanRegistry.getBean( jdbcTypeClass ).getBeanInstance(); - final int typeCode = annotation.registrationCode() == Integer.MIN_VALUE + final Integer registrationCode = annotation.getInteger( "registrationCode" ); + final int typeCode = registrationCode == Integer.MIN_VALUE ? jdbcType.getDefaultSqlTypeCode() - : annotation.registrationCode(); + : registrationCode; context.getMetadataCollector().addJdbcTypeRegistration( typeCode, jdbcType ); } private static void handleJavaTypeRegistration( MetadataBuildingContext context, ManagedBeanRegistry managedBeanRegistry, - JavaTypeRegistration annotation) { - final Class> javaTypeClass = annotation.descriptorClass(); - final BasicJavaType javaType = - !context.getBuildingOptions().isAllowExtensionsInCdi() - ? FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ) - : managedBeanRegistry.getBean( javaTypeClass ).getBeanInstance(); - context.getMetadataCollector().addJavaTypeRegistration( annotation.javaType(), javaType ); + AnnotationUsage annotation) { + final Class> javaTypeClass = annotation.getClassDetails( "descriptorClass" ).toJavaClass(); + final BasicJavaType javaType = !context.getBuildingOptions().isAllowExtensionsInCdi() + ? FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ) + : managedBeanRegistry.getBean( javaTypeClass ).getBeanInstance(); + context.getMetadataCollector().addJavaTypeRegistration( + annotation.getClassDetails( "javaType" ).toJavaClass(), + javaType + ); } private static void bindEmbeddableInstantiatorRegistrations( - XAnnotatedElement annotatedElement, + AnnotationTarget annotatedElement, MetadataBuildingContext context) { - final EmbeddableInstantiatorRegistration embeddableInstantiatorRegistration = - annotatedElement.getAnnotation( EmbeddableInstantiatorRegistration.class ); - if ( embeddableInstantiatorRegistration != null ) { - handleEmbeddableInstantiatorRegistration( context, embeddableInstantiatorRegistration ); - } - else { - final EmbeddableInstantiatorRegistrations embeddableInstantiatorRegistrations = - annotatedElement.getAnnotation( EmbeddableInstantiatorRegistrations.class ); - if ( embeddableInstantiatorRegistrations != null ) { - for ( EmbeddableInstantiatorRegistration registration : embeddableInstantiatorRegistrations.value() ) { - handleEmbeddableInstantiatorRegistration( context, registration ); - } - } - } + annotatedElement.forEachAnnotationUsage( EmbeddableInstantiatorRegistration.class, (usage) -> { + handleEmbeddableInstantiatorRegistration( context, usage ); + } ); } private static void handleEmbeddableInstantiatorRegistration( MetadataBuildingContext context, - EmbeddableInstantiatorRegistration annotation) { + AnnotationUsage annotation) { context.getMetadataCollector().registerEmbeddableInstantiator( - annotation.embeddableClass(), - annotation.instantiator() + annotation.getClassDetails( "embeddableClass" ).toJavaClass(), + annotation.getClassDetails( "instantiator" ).toJavaClass() ); } private static void bindCompositeUserTypeRegistrations( - XAnnotatedElement annotatedElement, + AnnotationTarget annotatedElement, MetadataBuildingContext context) { - final CompositeTypeRegistration compositeTypeRegistration = - annotatedElement.getAnnotation( CompositeTypeRegistration.class ); - if ( compositeTypeRegistration != null ) { - handleCompositeUserTypeRegistration( context, compositeTypeRegistration ); - } - else { - final CompositeTypeRegistrations compositeTypeRegistrations = - annotatedElement.getAnnotation( CompositeTypeRegistrations.class ); - if ( compositeTypeRegistrations != null ) { - for ( CompositeTypeRegistration registration : compositeTypeRegistrations.value() ) { - handleCompositeUserTypeRegistration( context, registration ); - } - } - } + annotatedElement.forEachAnnotationUsage( CompositeTypeRegistration.class, (usage) -> { + handleCompositeUserTypeRegistration( context, usage ); + } ); } private static void bindUserTypeRegistrations( - XAnnotatedElement annotatedElement, + AnnotationTarget annotatedElement, MetadataBuildingContext context) { - final TypeRegistration typeRegistration = - annotatedElement.getAnnotation( TypeRegistration.class ); - if ( typeRegistration != null ) { - handleUserTypeRegistration( context, typeRegistration ); - } - else { - final TypeRegistrations typeRegistrations = - annotatedElement.getAnnotation( TypeRegistrations.class ); - if ( typeRegistrations != null ) { - for ( TypeRegistration registration : typeRegistrations.value() ) { - handleUserTypeRegistration( context, registration ); - } - } - } + annotatedElement.forEachAnnotationUsage( TypeRegistration.class, (usage) -> { + handleUserTypeRegistration( context, usage ); + } ); } private static void handleUserTypeRegistration( MetadataBuildingContext context, - TypeRegistration compositeTypeRegistration) { + AnnotationUsage compositeTypeRegistration) { // TODO: check that the two classes agree, i.e. that // the user type knows how to handle the type context.getMetadataCollector().registerUserType( - compositeTypeRegistration.basicClass(), - compositeTypeRegistration.userType() + compositeTypeRegistration.getClassDetails( "basicClass" ).toJavaClass(), + compositeTypeRegistration.getClassDetails( "userType" ).toJavaClass() ); } private static void handleCompositeUserTypeRegistration( MetadataBuildingContext context, - CompositeTypeRegistration compositeTypeRegistration) { + AnnotationUsage compositeTypeRegistration) { // TODO: check that the two classes agree, i.e. that // the user type knows how to handle the type context.getMetadataCollector().registerCompositeUserType( - compositeTypeRegistration.embeddableClass(), - compositeTypeRegistration.userType() + compositeTypeRegistration.getClassDetails( "embeddableClass" ).toJavaClass(), + compositeTypeRegistration.getClassDetails( "userType" ).toJavaClass() ); } - private static void bindConverterRegistrations(XAnnotatedElement container, MetadataBuildingContext context) { - final ConverterRegistration converterRegistration = container.getAnnotation( ConverterRegistration.class ); - if ( converterRegistration != null ) { - handleConverterRegistration( converterRegistration, context ); - } - else { - final ConverterRegistrations converterRegistrations = container.getAnnotation( ConverterRegistrations.class ); - if ( converterRegistrations != null ) { - for ( ConverterRegistration registration : converterRegistrations.value() ) { - handleConverterRegistration( registration, context ); - } - } - } + private static void bindConverterRegistrations(AnnotationTarget container, MetadataBuildingContext context) { + container.forEachAnnotationUsage( ConverterRegistration.class, (usage) -> { + handleConverterRegistration( usage, context ); + } ); } - private static void handleConverterRegistration(ConverterRegistration registration, MetadataBuildingContext context) { - context.getMetadataCollector().getConverterRegistry() - .addRegisteredConversion( - new RegisteredConversion( - registration.domainType(), - registration.converter(), - registration.autoApply(), - context - ) - ); + private static void handleConverterRegistration(AnnotationUsage registration, MetadataBuildingContext context) { + context.getMetadataCollector().getConverterRegistry().addRegisteredConversion( new RegisteredConversion( + registration.getClassDetails( "domainType" ).toJavaClass(), + registration.getClassDetails( "converter" ).toJavaClass(), + registration.getBoolean( "autoApply" ), + context + ) ); } - public static void bindFetchProfilesForClass(XClass annotatedClass, MetadataBuildingContext context) { + public static void bindFetchProfilesForClass(AnnotationTarget annotatedClass, MetadataBuildingContext context) { bindFetchProfiles( annotatedClass, context ); } public static void bindFetchProfilesForPackage(ClassLoaderService cls, String packageName, MetadataBuildingContext context) { - final Package pack = cls.packageForNameOrNull( packageName ); - if ( pack != null ) { - final ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager(); - bindFetchProfiles( reflectionManager.toXPackage( pack ), context ); + final ClassDetails packageInfoClassDetails = context + .getMetadataCollector() + .getClassDetailsRegistry() + .findClassDetails( packageName + ".package-info" ); + if ( packageInfoClassDetails != null ) { + bindFetchProfiles( packageInfoClassDetails, context ); } } - private static void bindFetchProfiles(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { - final FetchProfile fetchProfile = annotatedElement.getAnnotation( FetchProfile.class ); - final FetchProfiles fetchProfiles = annotatedElement.getAnnotation( FetchProfiles.class ); - if ( fetchProfile != null ) { - bindFetchProfile( fetchProfile, context ); - } - if ( fetchProfiles != null ) { - for ( FetchProfile profile : fetchProfiles.value() ) { - bindFetchProfile( profile, context ); - } - } + private static void bindFetchProfiles(AnnotationTarget annotatedElement, MetadataBuildingContext context) { + annotatedElement.forEachAnnotationUsage( FetchProfile.class, (usage) -> { + bindFetchProfile( usage, context ); + } ); } - private static void bindFetchProfile(FetchProfile fetchProfile, MetadataBuildingContext context) { - final String name = fetchProfile.name(); + private static void bindFetchProfile(AnnotationUsage fetchProfile, MetadataBuildingContext context) { + final String name = fetchProfile.getString( "name" ); if ( reuseOrCreateFetchProfile( context, name ) ) { - for ( FetchOverride fetch : fetchProfile.fetchOverrides() ) { - if ( fetch.fetch() == FetchType.LAZY && fetch.mode() == FetchMode.JOIN ) { - throw new AnnotationException( "Fetch profile '" + name - + "' has a '@FetchOverride' with 'fetch=LAZY' and 'mode=JOIN'" - + " (join fetching is eager by nature)"); + final List> fetchOverrides = fetchProfile.getList( "fetchOverrides" ); + for ( AnnotationUsage fetchOverride : fetchOverrides ) { + final FetchType type = fetchOverride.getEnum( "fetch" ); + final FetchMode mode = fetchOverride.getEnum( "mode" ); + if ( type == FetchType.LAZY && mode == FetchMode.JOIN ) { + throw new AnnotationException( + "Fetch profile '" + name + + "' has a '@FetchOverride' with 'fetch=LAZY' and 'mode=JOIN'" + + " (join fetching is eager by nature)" + ); } - context.getMetadataCollector() - .addSecondPass( new FetchOverrideSecondPass( name, fetch, context ) ); + context.getMetadataCollector().addSecondPass( new FetchOverrideSecondPass( name, fetchOverride, context ) ); } } // otherwise, it's a fetch profile defined in XML, and it overrides @@ -686,17 +468,15 @@ public final class AnnotationBinder { * * @return A map of {@code InheritanceState}s keyed against their {@code XClass}. */ - public static Map buildInheritanceStates( - List orderedClasses, + public static Map buildInheritanceStates( + List orderedClasses, MetadataBuildingContext buildingContext) { - final Map inheritanceStatePerClass = new HashMap<>( orderedClasses.size() ); - for ( XClass clazz : orderedClasses ) { - final InheritanceState superclassState = - getSuperclassInheritanceState( clazz, inheritanceStatePerClass ); - final InheritanceState state = - new InheritanceState( clazz, inheritanceStatePerClass, buildingContext ); + final Map inheritanceStatePerClass = new HashMap<>( orderedClasses.size() ); + for ( ClassDetails clazz : orderedClasses ) { + final InheritanceState superclassState = getSuperclassInheritanceState( clazz, inheritanceStatePerClass ); + final InheritanceState state = new InheritanceState( clazz, inheritanceStatePerClass, buildingContext ); final AnnotatedClassType classType = buildingContext.getMetadataCollector().getClassType( clazz ); - if ( classType == EMBEDDABLE && !clazz.isAnnotationPresent( Imported.class ) ) { + if ( classType == EMBEDDABLE && !clazz.hasAnnotationUsage( Imported.class ) ) { final String className = clazz.getName(); buildingContext.getMetadataCollector().addImport( unqualify( className ), className ); } @@ -709,7 +489,7 @@ public final class AnnotationBinder { state.setHasParents( true ); if ( classType == EMBEDDABLE ) { buildingContext.getMetadataCollector().registerEmbeddableSubclass( - superEntityState.getClazz(), + superEntityState.getClassDetails(), clazz ); } @@ -729,12 +509,12 @@ public final class AnnotationBinder { return inheritanceStatePerClass; } - private static void logMixedInheritance(XClass clazz, InheritanceState superclassState, InheritanceState state) { + private static void logMixedInheritance(ClassDetails classDetails, InheritanceState superclassState, InheritanceState state) { if ( state.getType() != null && superclassState.getType() != null ) { final boolean nonDefault = InheritanceType.SINGLE_TABLE != state.getType(); final boolean mixingStrategy = state.getType() != superclassState.getType(); if ( nonDefault && mixingStrategy ) { - throw new AnnotationException( "Entity '" + clazz.getName() + throw new AnnotationException( "Entity '" + classDetails.getName() + "' may not override the inheritance mapping strategy '" + superclassState.getType() + "' of its hierarchy" + "' (each entity hierarchy has a single inheritance mapping strategy)" ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationHelper.java new file mode 100644 index 0000000000..335f31b8ec --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationHelper.java @@ -0,0 +1,28 @@ +/* + * 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.boot.model.internal; + +import java.util.HashMap; +import java.util.List; + +import org.hibernate.annotations.Parameter; +import org.hibernate.models.spi.AnnotationUsage; + +import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize; + +/** + * @author Steve Ebersole + */ +public class AnnotationHelper { + public static HashMap extractParameterMap(List> parameters) { + final HashMap paramMap = mapOfSize( parameters.size() ); + parameters.forEach( (usage) -> { + paramMap.put( usage.getString( "name" ), usage.getString( "value" ) ); + } ); + return paramMap; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java index 8ddecb6a14..929addb9bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java @@ -6,9 +6,8 @@ */ package org.hibernate.boot.model.internal; -import jakarta.persistence.Column; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinTable; +import java.util.Locale; + import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.annotations.Cascade; @@ -16,14 +15,17 @@ import org.hibernate.annotations.Columns; import org.hibernate.annotations.Formula; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.mapping.Any; import org.hibernate.mapping.Join; import org.hibernate.mapping.Property; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.MemberDetails; -import java.util.Locale; +import jakarta.persistence.Column; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinTable; import static org.hibernate.boot.model.internal.BinderHelper.getCascadeStrategy; import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation; @@ -38,12 +40,12 @@ public class AnyBinder { EntityBinder entityBinder, boolean isIdentifierMapper, MetadataBuildingContext context, - XProperty property, + MemberDetails property, AnnotatedJoinColumns joinColumns, boolean forcePersist) { //check validity - if ( property.isAnnotationPresent( Columns.class ) ) { + if ( property.hasAnnotationUsage( Columns.class ) ) { throw new AnnotationException( String.format( Locale.ROOT, @@ -54,9 +56,9 @@ public class AnyBinder { ); } - final Cascade hibernateCascade = property.getAnnotation( Cascade.class ); - final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class ); - final JoinTable assocTable = propertyHolder.getJoinTable(property); + final AnnotationUsage hibernateCascade = property.getAnnotationUsage( Cascade.class ); + final AnnotationUsage onDeleteAnn = property.getAnnotationUsage( OnDelete.class ); + final AnnotationUsage assocTable = propertyHolder.getJoinTable( property ); if ( assocTable != null ) { final Join join = propertyHolder.addJoin( assocTable, false ); for ( AnnotatedJoinColumn joinColumn : joinColumns.getJoinColumns() ) { @@ -67,7 +69,7 @@ public class AnyBinder { getCascadeStrategy( null, hibernateCascade, false, forcePersist ), //@Any has no cascade attribute joinColumns, - onDeleteAnn == null ? null : onDeleteAnn.action(), + onDeleteAnn == null ? null : onDeleteAnn.getEnum( "action" ), nullability, propertyHolder, inferredData, @@ -87,16 +89,16 @@ public class AnyBinder { EntityBinder entityBinder, boolean isIdentifierMapper, MetadataBuildingContext context) { - final XProperty property = inferredData.getProperty(); - final org.hibernate.annotations.Any any = property.getAnnotation( org.hibernate.annotations.Any.class ); + final MemberDetails property = inferredData.getAttributeMember(); + final AnnotationUsage any = property.getAnnotationUsage( org.hibernate.annotations.Any.class ); if ( any == null ) { throw new AssertionFailure( "Missing @Any annotation: " + getPath( propertyHolder, inferredData ) ); } - final boolean lazy = any.fetch() == FetchType.LAZY; - final boolean optional = any.optional(); + final boolean lazy = any.getEnum( "fetch" ) == FetchType.LAZY; + final boolean optional = any.getBoolean( "optional" ); final Any value = BinderHelper.buildAnyValue( - property.getAnnotation( Column.class ), + property.getAnnotationUsage( Column.class ), getOverridableAnnotation( property, Formula.class, context ), columns, inferredData, @@ -127,7 +129,7 @@ public class AnyBinder { Property prop = binder.makeProperty(); prop.setOptional( optional && value.isNullable() ); //composite FK columns are in the same table, so it's OK - propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() ); + propertyHolder.addProperty( prop, inferredData.getAttributeMember(), columns, inferredData.getDeclaringClass() ); binder.callAttributeBindersInSecondPass( prop ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AttributeConversionInfo.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AttributeConversionInfo.java index 4cba59c734..f8d0c4364e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AttributeConversionInfo.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AttributeConversionInfo.java @@ -6,7 +6,9 @@ */ package org.hibernate.boot.model.internal; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.MemberDetails; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Convert; @@ -22,30 +24,28 @@ import jakarta.persistence.Convert; public class AttributeConversionInfo { private final Class> converterClass; private final boolean conversionDisabled; - private final String attributeName; - private final XAnnotatedElement source; + private final AnnotationTarget source; @SuppressWarnings({ "unchecked", "rawtypes" }) public AttributeConversionInfo( Class converterClass, boolean conversionDisabled, String attributeName, - XAnnotatedElement source) { + AnnotationTarget source) { this.converterClass = (Class>) converterClass; this.conversionDisabled = conversionDisabled; this.attributeName = attributeName; this.source = source; } - @SuppressWarnings("unchecked") - public AttributeConversionInfo(Convert convertAnnotation, XAnnotatedElement xAnnotatedElement) { + public AttributeConversionInfo(AnnotationUsage convertAnnotation, AnnotationTarget source) { this( - convertAnnotation.converter(), - convertAnnotation.disableConversion(), - convertAnnotation.attributeName(), - xAnnotatedElement + convertAnnotation.getClassDetails( "converter" ).toJavaClass(), + convertAnnotation.getBoolean( "disableConversion" ), + convertAnnotation.getString( "attributeName" ), + source ); } @@ -75,7 +75,7 @@ public class AttributeConversionInfo { /** * The annotated element */ - public XAnnotatedElement getSource() { + public AnnotationTarget getSource() { return source; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java index 48558dd2cb..d57b9abfcc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java @@ -8,9 +8,10 @@ package org.hibernate.boot.model.internal; import java.io.Serializable; import java.lang.reflect.ParameterizedType; -import java.util.Collection; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Function; @@ -41,15 +42,12 @@ import org.hibernate.annotations.MapKeyMutability; import org.hibernate.annotations.MapKeyType; import org.hibernate.annotations.Mutability; import org.hibernate.annotations.Nationalized; -import org.hibernate.annotations.Parameter; import org.hibernate.annotations.PartitionKey; import org.hibernate.annotations.Target; import org.hibernate.annotations.TimeZoneColumn; import org.hibernate.annotations.TimeZoneStorage; import org.hibernate.annotations.TimeZoneStorageType; import org.hibernate.annotations.Type; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.TypeDefinition; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.spi.AccessType; @@ -62,6 +60,11 @@ import org.hibernate.internal.util.ReflectHelper; import org.hibernate.mapping.BasicValue; import org.hibernate.mapping.Component; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.ParameterizedTypeDetails; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; @@ -81,6 +84,7 @@ import org.hibernate.usertype.UserType; import org.jboss.logging.Logger; +import jakarta.persistence.DiscriminatorType; import jakarta.persistence.ElementCollection; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -93,7 +97,7 @@ import jakarta.persistence.Temporal; import jakarta.persistence.TemporalType; import jakarta.persistence.Version; -import static org.hibernate.boot.model.internal.HCANNHelper.findAnnotation; +import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; /** * A stateful binder responsible for creating instances of {@link BasicValue}. @@ -142,7 +146,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { private Function explicitMutabilityAccess; private Function implicitJavaTypeAccess; - private XProperty xproperty; + private MemberDetails xproperty; private AccessType accessType; private ConverterDescriptor converterDescriptor; @@ -319,13 +323,13 @@ public class BasicValueBinder implements JdbcTypeIndicators { public void setType( - XProperty modelXProperty, - XClass modelPropertyTypeXClass, + MemberDetails valueMember, + TypeDetails typeDetails, String declaringClassName, ConverterDescriptor converterDescriptor) { - this.xproperty = modelXProperty; - boolean isArray = modelXProperty.isArray(); - if ( modelPropertyTypeXClass == null && !isArray ) { + this.xproperty = valueMember; + boolean isArray = valueMember.isArray(); + if ( typeDetails == null && !isArray ) { // we cannot guess anything return; } @@ -338,74 +342,66 @@ public class BasicValueBinder implements JdbcTypeIndicators { // throw new AssertionFailure( "Expecting just one column, but found `" + Arrays.toString( columns ) + "`" ); // } - final XClass modelTypeXClass = isArray - ? modelXProperty.getElementClass() - : modelPropertyTypeXClass; - - // If we get into this method we know that there is a Java type for the value - // and that it is safe to load on the app classloader. - final java.lang.reflect.Type modelJavaType = resolveJavaType( modelTypeXClass ); - if ( modelJavaType == null ) { - throw new IllegalStateException( "BasicType requires Java type" ); - } + final TypeDetails modelClassDetails = isArray + ? valueMember.getElementType() + : typeDetails; if ( kind != Kind.LIST_INDEX && kind != Kind.MAP_KEY ) { - isLob = modelXProperty.isAnnotationPresent( Lob.class ); + isLob = valueMember.hasAnnotationUsage( Lob.class ); } if ( getDialect().getNationalizationSupport() == NationalizationSupport.EXPLICIT ) { - isNationalized = HCANNHelper.findAnnotation( modelXProperty, Nationalized.class ) != null - || buildingContext.getBuildingOptions().useNationalizedCharacterData(); + isNationalized = buildingContext.getBuildingOptions().useNationalizedCharacterData() + || valueMember.locateAnnotationUsage( Nationalized.class ) != null; } - applyJpaConverter( modelXProperty, converterDescriptor ); + applyJpaConverter( valueMember, converterDescriptor ); - final Class> userTypeImpl = kind.mappingAccess.customType( modelXProperty ); + final Class> userTypeImpl = kind.mappingAccess.customType( valueMember ); if ( userTypeImpl != null ) { - applyExplicitType( userTypeImpl, kind.mappingAccess.customTypeParameters( modelXProperty ) ); + applyExplicitType( userTypeImpl, kind.mappingAccess.customTypeParameters( valueMember ) ); // An explicit custom UserType has top precedence when we get to BasicValue resolution. return; } - else if ( modelTypeXClass != null ) { - final Class basicClass = buildingContext.getBootstrapContext() - .getReflectionManager() - .toClass( modelTypeXClass ); + else if ( modelClassDetails != null ) { + final ClassDetails rawClassDetails = modelClassDetails.determineRawClass(); + final Class basicClass = rawClassDetails.toJavaClass(); final Class> registeredUserTypeImpl = buildingContext.getMetadataCollector().findRegisteredUserType( basicClass ); if ( registeredUserTypeImpl != null ) { - applyExplicitType( registeredUserTypeImpl, new Parameter[0] ); + applyExplicitType( registeredUserTypeImpl, Collections.emptyMap() ); return; } } switch ( kind ) { case ATTRIBUTE: { - prepareBasicAttribute( declaringClassName, modelXProperty, modelPropertyTypeXClass ); + prepareBasicAttribute( declaringClassName, valueMember, typeDetails ); break; } case ANY_DISCRIMINATOR: { - prepareAnyDiscriminator( modelXProperty ); + prepareAnyDiscriminator( valueMember ); break; } case ANY_KEY: { - prepareAnyKey( modelXProperty ); + prepareAnyKey( valueMember ); break; } case COLLECTION_ID: { - prepareCollectionId( modelXProperty ); + prepareCollectionId( valueMember ); break; } case LIST_INDEX: { - prepareListIndex( modelXProperty ); + prepareListIndex( valueMember ); break; } case MAP_KEY: { - prepareMapKey( modelXProperty, modelPropertyTypeXClass ); + prepareMapKey( valueMember, typeDetails ); break; } case COLLECTION_ELEMENT: { - prepareCollectionElement( modelXProperty, modelPropertyTypeXClass ); + prepareCollectionElement( valueMember, typeDetails ); break; } default: { @@ -415,30 +411,13 @@ public class BasicValueBinder implements JdbcTypeIndicators { } - private void applyExplicitType(Class> impl, Parameter[] params) { + private void applyExplicitType(Class> impl, Map params) { this.explicitCustomType = impl; - this.explicitLocalTypeParams = extractTypeParams( params ); + this.explicitLocalTypeParams = params; } - private Map extractTypeParams(Parameter[] parameters) { - if ( parameters == null || parameters.length == 0 ) { - return Collections.emptyMap(); - } - - if ( parameters.length == 1 ) { - return Collections.singletonMap( parameters[0].name(), parameters[0].value() ); - } - - final Map map = new HashMap<>(); - for ( Parameter parameter: parameters ) { - map.put( parameter.name(), parameter.value() ); - } - - return map; - } - - private void prepareCollectionId(XProperty modelXProperty) { - final CollectionId collectionIdAnn = modelXProperty.getAnnotation( CollectionId.class ); + private void prepareCollectionId(MemberDetails attributeMember) { + final AnnotationUsage collectionIdAnn = attributeMember.getAnnotationUsage( CollectionId.class ); if ( collectionIdAnn == null ) { throw new MappingException( "idbag mapping missing @CollectionId" ); } @@ -450,10 +429,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { implicitJavaTypeAccess = (typeConfiguration) -> null; explicitJavaTypeAccess = (typeConfiguration) -> { - - final CollectionIdJavaType javaTypeAnn = findAnnotation( modelXProperty, CollectionIdJavaType.class ); + final AnnotationUsage javaTypeAnn = attributeMember.locateAnnotationUsage( CollectionIdJavaType.class ); if ( javaTypeAnn != null ) { - final Class> javaTypeClass = normalizeJavaType( javaTypeAnn.value() ); + final ClassDetails implDetails = javaTypeAnn.getClassDetails( "value" ); + final Class> javaTypeClass = normalizeJavaType( implDetails.toJavaClass() ); if ( javaTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ); @@ -467,9 +446,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; explicitJdbcTypeAccess = (typeConfiguration) -> { - final CollectionIdJdbcType jdbcTypeAnn = findAnnotation( modelXProperty, CollectionIdJdbcType.class ); + final AnnotationUsage jdbcTypeAnn = attributeMember.locateAnnotationUsage( CollectionIdJdbcType.class ); if ( jdbcTypeAnn != null ) { - final Class jdbcTypeClass = normalizeJdbcType( jdbcTypeAnn.value() ); + final ClassDetails implDetails = jdbcTypeAnn.getClassDetails( "value" ); + final Class jdbcTypeClass = normalizeJdbcType( implDetails.toJavaClass() ); if ( jdbcTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( jdbcTypeClass ); @@ -479,10 +459,11 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final CollectionIdJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( modelXProperty, CollectionIdJdbcTypeCode.class ); + final AnnotationUsage jdbcTypeCodeAnn = attributeMember.locateAnnotationUsage( CollectionIdJdbcTypeCode.class ); if ( jdbcTypeCodeAnn != null ) { - if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) { - return typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCodeAnn.value() ); + final int code = jdbcTypeCodeAnn.getInteger( "value" ); + if ( code != Integer.MIN_VALUE ) { + return typeConfiguration.getJdbcTypeRegistry().getDescriptor( code ); } } @@ -490,9 +471,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; explicitMutabilityAccess = (typeConfiguration) -> { - final CollectionIdMutability mutabilityAnn = findAnnotation( modelXProperty, CollectionIdMutability.class ); + final AnnotationUsage mutabilityAnn = attributeMember.locateAnnotationUsage( CollectionIdMutability.class ); if ( mutabilityAnn != null ) { - final Class> mutabilityClass = mutabilityAnn.value(); + final ClassDetails implDetails = mutabilityAnn.getClassDetails( "value" ); + final Class> mutabilityClass = implDetails.toJavaClass(); if ( mutabilityClass != null ) { return resolveMutability( mutabilityClass ); } @@ -526,7 +508,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { } // if there is a UserType, see if its Class is annotated with mutability-related annotations - final Class> customTypeImpl = Kind.ATTRIBUTE.mappingAccess.customType( modelXProperty ); + final Class> customTypeImpl = Kind.ATTRIBUTE.mappingAccess.customType( attributeMember ); if ( customTypeImpl != null ) { final Mutability customTypeMutabilityAnn = customTypeImpl.getAnnotation( Mutability.class ); if ( customTypeMutabilityAnn != null ) { @@ -550,28 +532,33 @@ public class BasicValueBinder implements JdbcTypeIndicators { } private void prepareMapKey( - XProperty mapAttribute, - XClass modelPropertyTypeXClass) { - final XClass mapKeyClass = modelPropertyTypeXClass == null ? mapAttribute.getMapKey() : modelPropertyTypeXClass; - final java.lang.reflect.Type javaType = resolveJavaType( mapKeyClass ); - implicitJavaTypeAccess = typeConfiguration -> javaType; + MemberDetails attributeMember, + TypeDetails explicitMapKeyTypeDetails) { + final TypeDetails mapKeyClass = explicitMapKeyTypeDetails == null + ? attributeMember.getMapKeyType() + : explicitMapKeyTypeDetails; + implicitJavaTypeAccess = typeConfiguration -> { + final ClassDetails rawKeyClassDetails = mapKeyClass.determineRawClass(); + return rawKeyClassDetails.toJavaClass(); + }; - final MapKeyEnumerated mapKeyEnumeratedAnn = mapAttribute.getAnnotation( MapKeyEnumerated.class ); + final AnnotationUsage mapKeyEnumeratedAnn = attributeMember.getAnnotationUsage( MapKeyEnumerated.class ); if ( mapKeyEnumeratedAnn != null ) { - enumType = mapKeyEnumeratedAnn.value(); + enumType = mapKeyEnumeratedAnn.getEnum( "value" ); } - final MapKeyTemporal mapKeyTemporalAnn = mapAttribute.getAnnotation( MapKeyTemporal.class ); + final AnnotationUsage mapKeyTemporalAnn = attributeMember.getAnnotationUsage( MapKeyTemporal.class ); if ( mapKeyTemporalAnn != null ) { - temporalPrecision = mapKeyTemporalAnn.value(); + temporalPrecision = mapKeyTemporalAnn.getEnum( "value" ); } final boolean useDeferredBeanContainerAccess = !buildingContext.getBuildingOptions().isAllowExtensionsInCdi(); explicitJdbcTypeAccess = typeConfiguration -> { - final MapKeyJdbcType jdbcTypeAnn = findAnnotation( mapAttribute, MapKeyJdbcType.class ); + final AnnotationUsage jdbcTypeAnn = attributeMember.locateAnnotationUsage( MapKeyJdbcType.class ); if ( jdbcTypeAnn != null ) { - final Class jdbcTypeClass = normalizeJdbcType( jdbcTypeAnn.value() ); + final ClassDetails implDetails = jdbcTypeAnn.getClassDetails( "value" ); + final Class jdbcTypeClass = normalizeJdbcType( implDetails.toJavaClass() ); if ( jdbcTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( jdbcTypeClass ); @@ -580,9 +567,9 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final MapKeyJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( mapAttribute, MapKeyJdbcTypeCode.class ); + final AnnotationUsage jdbcTypeCodeAnn = attributeMember.locateAnnotationUsage( MapKeyJdbcTypeCode.class ); if ( jdbcTypeCodeAnn != null ) { - final int jdbcTypeCode = jdbcTypeCodeAnn.value(); + final int jdbcTypeCode = jdbcTypeCodeAnn.getInteger( "value" ); if ( jdbcTypeCode != Integer.MIN_VALUE ) { return typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCode ); } @@ -592,9 +579,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; explicitJavaTypeAccess = typeConfiguration -> { - final MapKeyJavaType javaTypeAnn = findAnnotation( mapAttribute, MapKeyJavaType.class ); + final AnnotationUsage javaTypeAnn = attributeMember.locateAnnotationUsage( MapKeyJavaType.class ); if ( javaTypeAnn != null ) { - final Class> javaTypeClass = normalizeJavaType( javaTypeAnn.value() ); + final ClassDetails implDetails = javaTypeAnn.getClassDetails( "value" ); + final Class> javaTypeClass = normalizeJavaType( implDetails.toJavaClass() ); if ( javaTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ); @@ -603,19 +591,19 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final MapKeyClass mapKeyClassAnn = mapAttribute.getAnnotation( MapKeyClass.class ); + final AnnotationUsage mapKeyClassAnn = attributeMember.getAnnotationUsage( MapKeyClass.class ); if ( mapKeyClassAnn != null ) { - return (BasicJavaType) typeConfiguration.getJavaTypeRegistry() - .getDescriptor( mapKeyClassAnn.value() ); + final ClassDetails mapKeyClassDetails = mapKeyClassAnn.getClassDetails( "value" ); + return (BasicJavaType) typeConfiguration.getJavaTypeRegistry().getDescriptor( mapKeyClassDetails.toJavaClass() ); } return null; }; explicitMutabilityAccess = typeConfiguration -> { - final MapKeyMutability mutabilityAnn = findAnnotation( mapAttribute, MapKeyMutability.class ); + final AnnotationUsage mutabilityAnn = attributeMember.locateAnnotationUsage( MapKeyMutability.class ); if ( mutabilityAnn != null ) { - final Class> mutabilityClass = mutabilityAnn.value(); + final Class> mutabilityClass = mutabilityAnn.getClassDetails( "value" ).toJavaClass(); if ( mutabilityClass != null ) { return resolveMutability( mutabilityClass ); } @@ -649,7 +637,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { } // if there is a UserType, see if its Class is annotated with mutability-related annotations - final Class> customTypeImpl = Kind.MAP_KEY.mappingAccess.customType( mapAttribute ); + final Class> customTypeImpl = Kind.MAP_KEY.mappingAccess.customType( attributeMember ); if ( customTypeImpl != null ) { final Mutability customTypeMutabilityAnn = customTypeImpl.getAnnotation( Mutability.class ); if ( customTypeMutabilityAnn != null ) { @@ -666,7 +654,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; } - private void prepareListIndex(XProperty listAttribute) { + private void prepareListIndex(MemberDetails attributeMember) { implicitJavaTypeAccess = typeConfiguration -> Integer.class; final boolean useDeferredBeanContainerAccess = !buildingContext.getBuildingOptions().isAllowExtensionsInCdi(); @@ -675,9 +663,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { .requireService( ManagedBeanRegistry.class ); explicitJavaTypeAccess = (typeConfiguration) -> { - final ListIndexJavaType javaTypeAnn = findAnnotation( listAttribute, ListIndexJavaType.class ); + final AnnotationUsage javaTypeAnn = attributeMember.locateAnnotationUsage( ListIndexJavaType.class ); if ( javaTypeAnn != null ) { - final Class> javaTypeClass = normalizeJavaType( javaTypeAnn.value() ); + final ClassDetails implDetails = javaTypeAnn.getClassDetails( "value" ); + final Class> javaTypeClass = normalizeJavaType( implDetails.toJavaClass() ); if ( javaTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ); @@ -691,9 +680,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; explicitJdbcTypeAccess = (typeConfiguration) -> { - final ListIndexJdbcType jdbcTypeAnn = findAnnotation( listAttribute, ListIndexJdbcType.class ); + final AnnotationUsage jdbcTypeAnn = attributeMember.locateAnnotationUsage( ListIndexJdbcType.class ); if ( jdbcTypeAnn != null ) { - final Class jdbcTypeClass = normalizeJdbcType( jdbcTypeAnn.value() ); + final ClassDetails implDetails = jdbcTypeAnn.getClassDetails( "value" ); + final Class jdbcTypeClass = normalizeJdbcType( implDetails.toJavaClass() ); if ( jdbcTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( jdbcTypeClass ); @@ -703,33 +693,35 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final ListIndexJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( listAttribute, ListIndexJdbcTypeCode.class ); + final AnnotationUsage jdbcTypeCodeAnn = attributeMember.locateAnnotationUsage( ListIndexJdbcTypeCode.class ); if ( jdbcTypeCodeAnn != null ) { - return typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCodeAnn.value() ); + return typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCodeAnn.getInteger( "value" ) ); } return null; }; } - private void prepareCollectionElement(XProperty attributeXProperty, XClass elementTypeXClass) { - - XClass xclass = elementTypeXClass == null && attributeXProperty.isArray() - ? attributeXProperty.getElementClass() - : elementTypeXClass; - final java.lang.reflect.Type javaType = resolveJavaType( xclass ); + private void prepareCollectionElement( + MemberDetails attributeMember, + TypeDetails explicitElementTypeDetails) { + final TypeDetails elementTypeDetails = explicitElementTypeDetails == null && attributeMember.isArray() + ? attributeMember.getElementType() + : explicitElementTypeDetails; + final ClassDetails rawElementType = elementTypeDetails.determineRawClass(); + final java.lang.reflect.Type javaType = rawElementType.toJavaClass(); final Class javaTypeClass = ReflectHelper.getClass( javaType ); implicitJavaTypeAccess = typeConfiguration -> javaType; - final Temporal temporalAnn = attributeXProperty.getAnnotation( Temporal.class ); + final AnnotationUsage temporalAnn = attributeMember.getAnnotationUsage( Temporal.class ); if ( temporalAnn != null ) { - temporalPrecision = temporalAnn.value(); + DEPRECATION_LOGGER.deprecatedAnnotation( Temporal.class, attributeMember.getName() ); + temporalPrecision = temporalAnn.getEnum( "value" ); if ( temporalPrecision == null ) { throw new IllegalStateException( "No jakarta.persistence.TemporalType defined for @jakarta.persistence.Temporal " + - "associated with attribute " + attributeXProperty.getDeclaringClass().getName() + - '.' + attributeXProperty.getName() + "associated with attribute " + attributeMember.getName() ); } } @@ -738,14 +730,13 @@ public class BasicValueBinder implements JdbcTypeIndicators { } if ( javaTypeClass.isEnum() ) { - final Enumerated enumeratedAnn = attributeXProperty.getAnnotation( Enumerated.class ); + final AnnotationUsage enumeratedAnn = attributeMember.getAnnotationUsage( Enumerated.class ); if ( enumeratedAnn != null ) { - enumType = enumeratedAnn.value(); + enumType = enumeratedAnn.getEnum( "value" ); if ( enumType == null ) { throw new IllegalStateException( "jakarta.persistence.EnumType was null on @jakarta.persistence.Enumerated " + - " associated with attribute " + attributeXProperty.getDeclaringClass().getName() + - '.' + attributeXProperty.getName() + " associated with attribute " + attributeMember.getName() ); } } @@ -754,42 +745,48 @@ public class BasicValueBinder implements JdbcTypeIndicators { enumType = null; } - normalSupplementalDetails( attributeXProperty); + normalSupplementalDetails( attributeMember); // layer in support for JPA's approach for specifying a specific Java type for the collection elements... - final ElementCollection elementCollectionAnn = attributeXProperty.getAnnotation( ElementCollection.class ); - if ( elementCollectionAnn != null - && elementCollectionAnn.targetClass() != null - && elementCollectionAnn.targetClass() != void.class ) { - final Function original = explicitJavaTypeAccess; - explicitJavaTypeAccess = (typeConfiguration) -> { - final BasicJavaType originalResult = original.apply( typeConfiguration ); - if ( originalResult != null ) { - return originalResult; - } + final AnnotationUsage elementCollectionAnn = attributeMember.getAnnotationUsage( ElementCollection.class ); + if ( elementCollectionAnn != null ) { + final ClassDetails targetClassDetails = elementCollectionAnn.getClassDetails( "targetClass" ); + if ( ClassDetails.VOID_CLASS_DETAILS != targetClassDetails ) { + //noinspection rawtypes + final Function original = explicitJavaTypeAccess; + explicitJavaTypeAccess = (typeConfiguration) -> { + final BasicJavaType originalResult = original.apply( typeConfiguration ); + if ( originalResult != null ) { + return originalResult; + } - return (BasicJavaType) typeConfiguration - .getJavaTypeRegistry() - .getDescriptor( elementCollectionAnn.targetClass() ); - }; + return (BasicJavaType) typeConfiguration + .getJavaTypeRegistry() + .getDescriptor( targetClassDetails.toJavaClass() ); + }; + } } } - private void prepareBasicAttribute(String declaringClassName, XProperty attributeDescriptor, XClass attributeType) { + private void prepareBasicAttribute( + String declaringClassName, + MemberDetails attributeMember, + TypeDetails attributeType) { - final java.lang.reflect.Type javaType = resolveJavaType( attributeType ); - final Class javaTypeClass = ReflectHelper.getClass( javaType ); + final Class javaTypeClass = attributeType.determineRawClass().toJavaClass(); - implicitJavaTypeAccess = typeConfiguration -> javaType; + implicitJavaTypeAccess = typeConfiguration -> attributeType.determineRawClass().toJavaClass(); - final Temporal temporalAnn = attributeDescriptor.getAnnotation( Temporal.class ); + //noinspection deprecation + final var temporalAnn = attributeMember.getAnnotationUsage( Temporal.class ); if ( temporalAnn != null ) { - this.temporalPrecision = temporalAnn.value(); + //noinspection deprecation + DEPRECATION_LOGGER.deprecatedAnnotation( Temporal.class, declaringClassName + "." + attributeMember.getName() ); + this.temporalPrecision = temporalAnn.getEnum( "value" ); if ( this.temporalPrecision == null ) { throw new IllegalStateException( "No jakarta.persistence.TemporalType defined for @jakarta.persistence.Temporal " + - "associated with attribute " + attributeDescriptor.getDeclaringClass().getName() + - '.' + attributeDescriptor.getName() + "associated with attribute " + declaringClassName + "." + attributeMember.getName() ); } } @@ -797,15 +794,14 @@ public class BasicValueBinder implements JdbcTypeIndicators { this.temporalPrecision = null; } - final Enumerated enumeratedAnn = attributeDescriptor.getAnnotation( Enumerated.class ); + final AnnotationUsage enumeratedAnn = attributeMember.getAnnotationUsage( Enumerated.class ); if ( enumeratedAnn != null ) { - this.enumType = enumeratedAnn.value(); - if ( canUseEnumerated( javaType, javaTypeClass ) ) { + this.enumType = enumeratedAnn.getEnum( "value" ); + if ( canUseEnumerated( attributeType, javaTypeClass ) ) { if ( this.enumType == null ) { throw new IllegalStateException( "jakarta.persistence.EnumType was null on @jakarta.persistence.Enumerated " + - " associated with attribute " + attributeDescriptor.getDeclaringClass().getName() + - '.' + attributeDescriptor.getName() + " associated with attribute " + declaringClassName + "." + attributeMember.getName() ); } } @@ -814,7 +810,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { String.format( "Property '%s.%s' is annotated '@Enumerated' but its type '%s' is not an enum", declaringClassName, - attributeDescriptor.getName(), + attributeMember.getName(), attributeType.getName() ) ); @@ -824,45 +820,41 @@ public class BasicValueBinder implements JdbcTypeIndicators { this.enumType = null; } - normalSupplementalDetails( attributeDescriptor); + normalSupplementalDetails( attributeMember ); } - private boolean canUseEnumerated(java.lang.reflect.Type javaType, Class javaTypeClass) { + private boolean canUseEnumerated(TypeDetails javaType, Class javaTypeClass) { if ( javaTypeClass.isEnum() || javaTypeClass.isArray() && javaTypeClass.getComponentType().isEnum() ) { return true; } - if ( Collection.class.isAssignableFrom( javaTypeClass ) ) { - final java.lang.reflect.Type[] typeArguments = ( (ParameterizedType) javaType ).getActualTypeArguments(); - if ( typeArguments.length != 0 ) { - return ReflectHelper.getClass( typeArguments[0] ).isEnum(); + if ( javaType.isImplementor( org.hibernate.mapping.Collection.class ) ) { + final ParameterizedTypeDetails parameterizedType = javaType.asParameterizedType(); + final List typeArguments = parameterizedType.getArguments(); + if ( !typeArguments.isEmpty() ) { + return typeArguments.get( 0 ).isImplementor( Enumeration.class ); } } return false; } - private void prepareAnyDiscriminator(XProperty modelXProperty) { - final AnyDiscriminator anyDiscriminatorAnn = findAnnotation( modelXProperty, AnyDiscriminator.class ); + private void prepareAnyDiscriminator(MemberDetails memberDetails) { + final AnnotationUsage anyDiscriminatorAnn = memberDetails.locateAnnotationUsage( AnyDiscriminator.class ); implicitJavaTypeAccess = (typeConfiguration) -> { if ( anyDiscriminatorAnn != null ) { - switch ( anyDiscriminatorAnn.value() ) { - case CHAR: { - return Character.class; - } - case INTEGER: { - return Integer.class; - } - default: { - return String.class; - } - } + final DiscriminatorType anyDiscriminatorType = anyDiscriminatorAnn.getEnum( "value" ); + return switch ( anyDiscriminatorAnn.getEnum( "value", DiscriminatorType.class ) ) { + case CHAR -> Character.class; + case INTEGER -> Integer.class; + default -> String.class; + }; } return String.class; }; - normalJdbcTypeDetails( modelXProperty); - normalMutabilityDetails( modelXProperty ); + normalJdbcTypeDetails( memberDetails); + normalMutabilityDetails( memberDetails ); // layer AnyDiscriminator into the JdbcType resolution final Function originalJdbcTypeResolution = explicitJdbcTypeAccess; @@ -880,39 +872,42 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; } - private void prepareAnyKey(XProperty modelXProperty) { + private void prepareAnyKey(MemberDetails memberDetails) { implicitJavaTypeAccess = (typeConfiguration) -> null; final boolean useDeferredBeanContainerAccess = !buildingContext.getBuildingOptions().isAllowExtensionsInCdi(); explicitJavaTypeAccess = (typeConfiguration) -> { - final AnyKeyJavaType javaTypeAnn = findAnnotation( modelXProperty, AnyKeyJavaType.class ); + final AnnotationUsage javaTypeAnn = memberDetails.locateAnnotationUsage( AnyKeyJavaType.class ); if ( javaTypeAnn != null ) { - final Class> javaTypeClass = normalizeJavaType( javaTypeAnn.value() ); + final ClassDetails implDetails = javaTypeAnn.getClassDetails( "value" ); + final Class> implClass = normalizeJavaType( implDetails.toJavaClass() ); - if ( javaTypeClass != null ) { + if ( implClass != null ) { if ( useDeferredBeanContainerAccess ) { - return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ); + return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( implClass ); } - return getManagedBeanRegistry().getBean( javaTypeClass ).getBeanInstance(); + return getManagedBeanRegistry().getBean( implClass ).getBeanInstance(); } } - final AnyKeyJavaClass javaClassAnn = findAnnotation( modelXProperty, AnyKeyJavaClass.class ); + final AnnotationUsage javaClassAnn = memberDetails.locateAnnotationUsage( AnyKeyJavaClass.class ); if ( javaClassAnn != null ) { + final ClassDetails implDetails = javaClassAnn.getClassDetails( "value" ); //noinspection rawtypes return (BasicJavaType) typeConfiguration .getJavaTypeRegistry() - .getDescriptor( javaClassAnn.value() ); + .getDescriptor( implDetails.toJavaClass() ); } throw new MappingException("Could not determine key type for '@Any' mapping (specify '@AnyKeyJavaType' or '@AnyKeyJavaClass')"); }; explicitJdbcTypeAccess = (typeConfiguration) -> { - final AnyKeyJdbcType jdbcTypeAnn = findAnnotation( modelXProperty, AnyKeyJdbcType.class ); + final AnnotationUsage jdbcTypeAnn = memberDetails.locateAnnotationUsage( AnyKeyJdbcType.class ); if ( jdbcTypeAnn != null ) { - final Class jdbcTypeClass = normalizeJdbcType( jdbcTypeAnn.value() ); + final ClassDetails implDetails = jdbcTypeAnn.getClassDetails( "value" ); + final Class jdbcTypeClass = normalizeJdbcType( implDetails.toJavaClass() ); if ( jdbcTypeClass != null ) { if ( useDeferredBeanContainerAccess ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( jdbcTypeClass ); @@ -922,10 +917,11 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final AnyKeyJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( modelXProperty, AnyKeyJdbcTypeCode.class ); + final AnnotationUsage jdbcTypeCodeAnn = memberDetails.locateAnnotationUsage( AnyKeyJdbcTypeCode.class ); if ( jdbcTypeCodeAnn != null ) { - if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) { - return typeConfiguration.getJdbcTypeRegistry().getDescriptor( jdbcTypeCodeAnn.value() ); + final int code = jdbcTypeCodeAnn.getInteger( "value" ); + if ( code != Integer.MIN_VALUE ) { + return typeConfiguration.getJdbcTypeRegistry().getDescriptor( code ); } } @@ -933,12 +929,11 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; } - private void normalJdbcTypeDetails(XProperty attributeXProperty) { + private void normalJdbcTypeDetails(MemberDetails attributeMember) { explicitJdbcTypeAccess = typeConfiguration -> { - - final org.hibernate.annotations.JdbcType jdbcTypeAnn = findAnnotation( attributeXProperty, org.hibernate.annotations.JdbcType.class ); + final AnnotationUsage jdbcTypeAnn = attributeMember.locateAnnotationUsage( org.hibernate.annotations.JdbcType.class ); if ( jdbcTypeAnn != null ) { - final Class jdbcTypeClass = normalizeJdbcType( jdbcTypeAnn.value() ); + final Class jdbcTypeClass = normalizeJdbcType( jdbcTypeAnn.getClassDetails( "value" ).toJavaClass() ); if ( jdbcTypeClass != null ) { if ( !buildingContext.getBuildingOptions().isAllowExtensionsInCdi() ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( jdbcTypeClass ); @@ -947,9 +942,9 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final JdbcTypeCode jdbcTypeCodeAnn = findAnnotation( attributeXProperty, JdbcTypeCode.class ); + final AnnotationUsage jdbcTypeCodeAnn = attributeMember.locateAnnotationUsage( JdbcTypeCode.class ); if ( jdbcTypeCodeAnn != null ) { - final int jdbcTypeCode = jdbcTypeCodeAnn.value(); + final int jdbcTypeCode = jdbcTypeCodeAnn.getInteger( "value" ); if ( jdbcTypeCode != Integer.MIN_VALUE ) { final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry(); if ( jdbcTypeRegistry.getConstructor( jdbcTypeCode ) != null ) { @@ -965,20 +960,19 @@ public class BasicValueBinder implements JdbcTypeIndicators { }; } - private void normalMutabilityDetails(XProperty attributeXProperty) { + private void normalMutabilityDetails(MemberDetails attributeMember) { explicitMutabilityAccess = typeConfiguration -> { // Look for `@Mutability` on the attribute - final Mutability mutabilityAnn = findAnnotation( attributeXProperty, Mutability.class ); + final AnnotationUsage mutabilityAnn = attributeMember.locateAnnotationUsage( Mutability.class ); if ( mutabilityAnn != null ) { - final Class> mutability = mutabilityAnn.value(); + final Class> mutability = mutabilityAnn.getClassDetails( "value" ).toJavaClass(); if ( mutability != null ) { return resolveMutability( mutability ); } } // Look for `@Immutable` on the attribute - final Immutable immutableAnn = attributeXProperty.getAnnotation( Immutable.class ); - if ( immutableAnn != null ) { + if ( attributeMember.hasAnnotationUsage( Immutable.class ) ) { return ImmutableMutabilityPlan.instance(); } @@ -1030,7 +1024,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { } // if a custom UserType is specified, see if the UserType Class is annotated `@Mutability` - final Class> customTypeImpl = Kind.ATTRIBUTE.mappingAccess.customType( attributeXProperty ); + final Class> customTypeImpl = Kind.ATTRIBUTE.mappingAccess.customType( attributeMember ); if ( customTypeImpl != null ) { final Mutability customTypeMutabilityAnn = customTypeImpl.getAnnotation( Mutability.class ); if ( customTypeMutabilityAnn != null ) { @@ -1066,13 +1060,11 @@ public class BasicValueBinder implements JdbcTypeIndicators { return getManagedBeanRegistry().getBean( mutability ).getBeanInstance(); } - private void normalSupplementalDetails(XProperty attributeXProperty) { - + private void normalSupplementalDetails(MemberDetails attributeMember) { explicitJavaTypeAccess = typeConfiguration -> { - final org.hibernate.annotations.JavaType javaType = - findAnnotation( attributeXProperty, org.hibernate.annotations.JavaType.class ); + final AnnotationUsage javaType = attributeMember.locateAnnotationUsage( org.hibernate.annotations.JavaType.class ); if ( javaType != null ) { - final Class> javaTypeClass = normalizeJavaType( javaType.value() ); + final Class> javaTypeClass = normalizeJavaType( javaType.getClassDetails( "value" ).toJavaClass() ); if ( javaTypeClass != null ) { if ( !buildingContext.getBuildingOptions().isAllowExtensionsInCdi() ) { return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass ); @@ -1081,51 +1073,51 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } - final Target targetAnn = findAnnotation( attributeXProperty, Target.class ); + //noinspection deprecation + final var targetAnn = attributeMember.locateAnnotationUsage( Target.class ); if ( targetAnn != null ) { - return (BasicJavaType) typeConfiguration.getJavaTypeRegistry().getDescriptor( targetAnn.value() ); + //noinspection deprecation + DEPRECATION_LOGGER.deprecatedAnnotation( Target.class, attributeMember.getName() ); + return (BasicJavaType) typeConfiguration.getJavaTypeRegistry().getDescriptor( targetAnn.getClassDetails( "value" ).toJavaClass() ); } return null; }; - final org.hibernate.annotations.JdbcTypeCode jdbcType = - findAnnotation( attributeXProperty, org.hibernate.annotations.JdbcTypeCode.class ); + final AnnotationUsage jdbcType = attributeMember.locateAnnotationUsage( JdbcTypeCode.class ); if ( jdbcType != null ) { - jdbcTypeCode = jdbcType.value(); + jdbcTypeCode = jdbcType.getInteger( "value" ); } - normalJdbcTypeDetails( attributeXProperty); - normalMutabilityDetails( attributeXProperty ); + normalJdbcTypeDetails( attributeMember); + normalMutabilityDetails( attributeMember ); - final Enumerated enumerated = attributeXProperty.getAnnotation( Enumerated.class ); + final AnnotationUsage enumerated = attributeMember.getAnnotationUsage( Enumerated.class ); if ( enumerated != null ) { - enumType = enumerated.value(); + enumType = enumerated.getEnum( "value" ); } - final Temporal temporal = attributeXProperty.getAnnotation( Temporal.class ); + final AnnotationUsage temporal = attributeMember.getAnnotationUsage( Temporal.class ); if ( temporal != null ) { - temporalPrecision = temporal.value(); + temporalPrecision = temporal.getEnum( "value" ); } - final TimeZoneStorage timeZoneStorage = attributeXProperty.getAnnotation( TimeZoneStorage.class ); + final AnnotationUsage timeZoneStorage = attributeMember.getAnnotationUsage( TimeZoneStorage.class ); if ( timeZoneStorage != null ) { - timeZoneStorageType = timeZoneStorage.value(); - final TimeZoneColumn timeZoneColumnAnn = attributeXProperty.getAnnotation( TimeZoneColumn.class ); + timeZoneStorageType = timeZoneStorage.getEnum( "value" ); + final AnnotationUsage timeZoneColumnAnn = attributeMember.getAnnotationUsage( TimeZoneColumn.class ); if ( timeZoneColumnAnn != null ) { if ( timeZoneStorageType != TimeZoneStorageType.AUTO && timeZoneStorageType != TimeZoneStorageType.COLUMN ) { throw new IllegalStateException( "@TimeZoneColumn can not be used in conjunction with @TimeZoneStorage( " + timeZoneStorageType + - " ) with attribute " + attributeXProperty.getDeclaringClass().getName() + - '.' + attributeXProperty.getName() + " ) with attribute " + attributeMember.getDeclaringType().getName() + + '.' + attributeMember.getName() ); } } } - final PartitionKey partitionKey = attributeXProperty.getAnnotation( PartitionKey.class ); - if ( partitionKey != null ) { - this.partitionKey = true; - } + + this.partitionKey = attributeMember.hasAnnotationUsage( PartitionKey.class ); } private static Class> normalizeUserType(Class> userType) { @@ -1140,59 +1132,53 @@ public class BasicValueBinder implements JdbcTypeIndicators { return javaType; } - private java.lang.reflect.Type resolveJavaType(XClass returnedClassOrElement) { - return buildingContext.getBootstrapContext() - .getReflectionManager() - .toType( returnedClassOrElement ); - } - @Override public Dialect getDialect() { return buildingContext.getMetadataCollector().getDatabase().getDialect(); } - private void applyJpaConverter(XProperty property, ConverterDescriptor attributeConverterDescriptor) { + private void applyJpaConverter(MemberDetails attributeMember, ConverterDescriptor attributeConverterDescriptor) { if ( attributeConverterDescriptor == null ) { return; } - LOG.debugf( "Applying JPA converter [%s:%s]", persistentClassName, property.getName() ); + LOG.debugf( "Applying JPA converter [%s:%s]", persistentClassName, attributeMember.getName() ); - if ( property.isAnnotationPresent( Id.class ) ) { - LOG.debugf( "Skipping AttributeConverter checks for Id attribute [%s]", property.getName() ); + if ( attributeMember.hasAnnotationUsage( Id.class ) ) { + LOG.debugf( "Skipping AttributeConverter checks for Id attribute [%s]", attributeMember.getName() ); return; } - if ( property.isAnnotationPresent( Version.class ) ) { - LOG.debugf( "Skipping AttributeConverter checks for version attribute [%s]", property.getName() ); + if ( attributeMember.hasAnnotationUsage( Version.class ) ) { + LOG.debugf( "Skipping AttributeConverter checks for version attribute [%s]", attributeMember.getName() ); return; } if ( kind == Kind.MAP_KEY ) { - if ( property.isAnnotationPresent( MapKeyTemporal.class ) ) { - LOG.debugf( "Skipping AttributeConverter checks for map-key annotated as MapKeyTemporal [%s]", property.getName() ); + if ( attributeMember.hasAnnotationUsage( MapKeyTemporal.class ) ) { + LOG.debugf( "Skipping AttributeConverter checks for map-key annotated as MapKeyTemporal [%s]", attributeMember.getName() ); return; } - if ( property.isAnnotationPresent( MapKeyEnumerated.class ) ) { - LOG.debugf( "Skipping AttributeConverter checks for map-key annotated as MapKeyEnumerated [%s]", property.getName() ); + if ( attributeMember.hasAnnotationUsage( MapKeyEnumerated.class ) ) { + LOG.debugf( "Skipping AttributeConverter checks for map-key annotated as MapKeyEnumerated [%s]", attributeMember.getName() ); return; } } else { - if ( property.isAnnotationPresent( Temporal.class ) ) { - LOG.debugf( "Skipping AttributeConverter checks for Temporal attribute [%s]", property.getName() ); + if ( attributeMember.hasAnnotationUsage( Temporal.class ) ) { + LOG.debugf( "Skipping AttributeConverter checks for Temporal attribute [%s]", attributeMember.getName() ); return; } - if ( property.isAnnotationPresent( Enumerated.class ) ) { - LOG.debugf( "Skipping AttributeConverter checks for Enumerated attribute [%s]", property.getName() ); + if ( attributeMember.hasAnnotationUsage( Enumerated.class ) ) { + LOG.debugf( "Skipping AttributeConverter checks for Enumerated attribute [%s]", attributeMember.getName() ); return; } } if ( isAssociation() ) { - LOG.debugf( "Skipping AttributeConverter checks for association attribute [%s]", property.getName() ); + LOG.debugf( "Skipping AttributeConverter checks for association attribute [%s]", attributeMember.getName() ); return; } @@ -1464,30 +1450,31 @@ public class BasicValueBinder implements JdbcTypeIndicators { * Access to detail of basic value mappings based on {@link Kind} */ private interface BasicMappingAccess { - Class> customType(XProperty xProperty); - Parameter[] customTypeParameters(XProperty xProperty); + Class> customType(MemberDetails attributeMember); + Map customTypeParameters(MemberDetails attributeMember); } private static class ValueMappingAccess implements BasicMappingAccess { public static final ValueMappingAccess INSTANCE = new ValueMappingAccess(); @Override - public Class> customType(XProperty xProperty) { - final Type customType = findAnnotation( xProperty, Type.class ); + public Class> customType(MemberDetails attributeMember) { + final AnnotationUsage customType = attributeMember.locateAnnotationUsage( Type.class ); if ( customType == null ) { return null; } - return normalizeUserType( customType.value() ); + return normalizeUserType( customType.getClassDetails( "value" ).toJavaClass() ); } @Override - public Parameter[] customTypeParameters(XProperty xProperty) { - final Type customType = findAnnotation( xProperty, Type.class ); + public Map customTypeParameters(MemberDetails attributeMember) { + final AnnotationUsage customType = attributeMember.locateAnnotationUsage( Type.class ); if ( customType == null ) { return null; } - return customType.parameters(); + + return AnnotationHelper.extractParameterMap( customType.getList( "parameters" ) ); } } @@ -1495,15 +1482,13 @@ public class BasicValueBinder implements JdbcTypeIndicators { public static final AnyDiscriminatorMappingAccess INSTANCE = new AnyDiscriminatorMappingAccess(); @Override - public Class> customType(XProperty xProperty) { + public Class> customType(MemberDetails attributeMember) { return null; } - private static final Parameter[] EMPTY_PARAMS = new Parameter[0]; - @Override - public Parameter[] customTypeParameters(XProperty xProperty) { - return EMPTY_PARAMS; + public Map customTypeParameters(MemberDetails attributeMember) { + return Collections.emptyMap(); } } @@ -1511,15 +1496,13 @@ public class BasicValueBinder implements JdbcTypeIndicators { public static final AnyKeyMappingAccess INSTANCE = new AnyKeyMappingAccess(); @Override - public Class> customType(XProperty xProperty) { + public Class> customType(MemberDetails attributeMember) { return null; } - private static final Parameter[] EMPTY_PARAMS = new Parameter[0]; - @Override - public Parameter[] customTypeParameters(XProperty xProperty) { - return EMPTY_PARAMS; + public Map customTypeParameters(MemberDetails attributeMember) { + return Collections.emptyMap(); } } @@ -1527,22 +1510,23 @@ public class BasicValueBinder implements JdbcTypeIndicators { public static final MapKeyMappingAccess INSTANCE = new MapKeyMappingAccess(); @Override - public Class> customType(XProperty xProperty) { - final MapKeyType customType = findAnnotation( xProperty, MapKeyType.class ); + public Class> customType(MemberDetails attributeMember) { + final AnnotationUsage customType = attributeMember.locateAnnotationUsage( MapKeyType.class ); if ( customType == null ) { return null; } - return normalizeUserType( customType.value() ); + return normalizeUserType( customType.getClassDetails( "value" ).toJavaClass() ); } @Override - public Parameter[] customTypeParameters(XProperty xProperty) { - final MapKeyType customType = findAnnotation( xProperty, MapKeyType.class ); + public Map customTypeParameters(MemberDetails attributeMember) { + final AnnotationUsage customType = attributeMember.locateAnnotationUsage( MapKeyType.class ); if ( customType == null ) { return null; } - return customType.parameters(); + + return AnnotationHelper.extractParameterMap( customType.getList( "parameters" ) ); } } @@ -1550,22 +1534,23 @@ public class BasicValueBinder implements JdbcTypeIndicators { public static final CollectionIdMappingAccess INSTANCE = new CollectionIdMappingAccess(); @Override - public Class> customType(XProperty xProperty) { - final CollectionIdType customType = findAnnotation( xProperty, CollectionIdType.class ); + public Class> customType(MemberDetails attributeMember) { + final AnnotationUsage customType = attributeMember.locateAnnotationUsage( CollectionIdType.class ); if ( customType == null ) { return null; } - return normalizeUserType( customType.value() ); + return normalizeUserType( customType.getClassDetails( "value" ).toJavaClass() ); } @Override - public Parameter[] customTypeParameters(XProperty xProperty) { - final CollectionIdType customType = findAnnotation( xProperty, CollectionIdType.class ); + public Map customTypeParameters(MemberDetails attributeMember) { + final AnnotationUsage customType = attributeMember.locateAnnotationUsage( CollectionIdType.class ); if ( customType == null ) { return null; } - return customType.parameters(); + + return AnnotationHelper.extractParameterMap( customType.getList( "parameters" ) ); } } @@ -1573,13 +1558,13 @@ public class BasicValueBinder implements JdbcTypeIndicators { public static final ListIndexMappingAccess INSTANCE = new ListIndexMappingAccess(); @Override - public Class> customType(XProperty xProperty) { + public Class> customType(MemberDetails attributeMember) { return null; } @Override - public Parameter[] customTypeParameters(XProperty xProperty) { - return null; + public Map customTypeParameters(MemberDetails attributeMember) { + return Collections.emptyMap(); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java index 059c9ce8cf..cd5efebb21 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java @@ -7,20 +7,15 @@ package org.hibernate.boot.model.internal; import java.lang.annotation.Annotation; -import java.lang.annotation.Repeatable; -import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.function.Consumer; -import java.util.stream.Stream; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; @@ -30,20 +25,13 @@ import org.hibernate.annotations.AnyDiscriminatorValue; import org.hibernate.annotations.AnyDiscriminatorValues; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; -import org.hibernate.annotations.DialectOverride; import org.hibernate.annotations.Formula; import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.SqlFragmentAlias; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XPackage; -import org.hibernate.annotations.common.reflection.XProperty; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; -import org.hibernate.dialect.DatabaseVersion; -import org.hibernate.dialect.Dialect; import org.hibernate.mapping.Any; import org.hibernate.mapping.AttributeContainer; import org.hibernate.mapping.BasicValue; @@ -59,6 +47,13 @@ import org.hibernate.mapping.SyntheticProperty; import org.hibernate.mapping.Table; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.Value; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; +import org.hibernate.models.spi.TypeDetailsHelper; import org.hibernate.type.descriptor.java.JavaType; import jakarta.persistence.ConstraintMode; @@ -72,7 +67,6 @@ import jakarta.persistence.OneToOne; import static jakarta.persistence.ConstraintMode.NO_CONSTRAINT; import static jakarta.persistence.ConstraintMode.PROVIDER_DEFAULT; import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnOrFormulaFromAnnotation; -import static org.hibernate.boot.model.internal.HCANNHelper.findAnnotation; import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.qualifier; @@ -749,8 +743,8 @@ public class BinderHelper { } public static Any buildAnyValue( - jakarta.persistence.Column discriminatorColumn, - Formula discriminatorFormula, + AnnotationUsage discriminatorColumn, + AnnotationUsage discriminatorFormula, AnnotatedJoinColumns keyColumns, PropertyData inferredData, OnDeleteAction onDeleteAction, @@ -760,7 +754,7 @@ public class BinderHelper { EntityBinder entityBinder, boolean optional, MetadataBuildingContext context) { - final XProperty property = inferredData.getProperty(); + final MemberDetails property = inferredData.getAttributeMember(); final Any value = new Any( context, keyColumns.getTable(), true ); value.setLazy( lazy ); @@ -803,10 +797,10 @@ public class BinderHelper { final Map> discriminatorValueMappings = new HashMap<>(); processAnyDiscriminatorValues( - inferredData.getProperty(), + inferredData.getAttributeMember(), valueMapping -> discriminatorValueMappings.put( - discriminatorJavaType.wrap( valueMapping.discriminator(), null ), - valueMapping.entity() + discriminatorJavaType.wrap( valueMapping.getString( "discriminator" ), null ), + valueMapping.getClassDetails( "entity" ).toJavaClass() ) ); value.setDiscriminatorValueMappings( discriminatorValueMappings ); @@ -831,25 +825,23 @@ public class BinderHelper { } private static void processAnyDiscriminatorValues( - XProperty property, - Consumer consumer) { - final AnyDiscriminatorValue valueAnn = findAnnotation( property, AnyDiscriminatorValue.class ); + MemberDetails property, + Consumer> consumer) { + final AnnotationUsage valueAnn = property.locateAnnotationUsage( AnyDiscriminatorValue.class ); if ( valueAnn != null ) { consumer.accept( valueAnn ); - return; } - final AnyDiscriminatorValues valuesAnn = findAnnotation( property, AnyDiscriminatorValues.class ); + final AnnotationUsage valuesAnn = property.locateAnnotationUsage( AnyDiscriminatorValues.class ); if ( valuesAnn != null ) { - for ( AnyDiscriminatorValue discriminatorValue : valuesAnn.value() ) { - consumer.accept( discriminatorValue ); - } + final List> nestedList = valuesAnn.getList( "value" ); + nestedList.forEach( consumer ); } } public static MappedSuperclass getMappedSuperclassOrNull( - XClass declaringClass, - Map inheritanceStatePerClass, + ClassDetails declaringClass, + Map inheritanceStatePerClass, MetadataBuildingContext context) { boolean retrieve = false; if ( declaringClass != null ) { @@ -865,9 +857,7 @@ public class BinderHelper { } if ( retrieve ) { - return context.getMetadataCollector().getMappedSuperclass( - context.getBootstrapContext().getReflectionManager().toClass( declaringClass ) - ); + return context.getMetadataCollector().getMappedSuperclass( declaringClass.toJavaClass() ); } else { return null; @@ -883,138 +873,51 @@ public class BinderHelper { PropertyHolder propertyHolder, String propertyName, MetadataBuildingContext buildingContext) { - final XClass mappedClass = buildingContext.getBootstrapContext().getReflectionManager() - .toXClass( propertyHolder.getPersistentClass().getMappedClass() ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getMetadataCollector() + .getSourceModelBuildingContext() + .getClassDetailsRegistry(); + final ClassDetails classDetails = classDetailsRegistry.resolveClassDetails( propertyHolder.getPersistentClass().getClassName() ); final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector(); if ( propertyHolder.isInIdClass() ) { - final PropertyData data = metadataCollector.getPropertyAnnotatedWithIdAndToOne( mappedClass, propertyName ); + final PropertyData data = metadataCollector.getPropertyAnnotatedWithIdAndToOne( classDetails, propertyName ); if ( data != null ) { return data; } // TODO: is this branch even necessary? else if ( buildingContext.getBuildingOptions().isSpecjProprietarySyntaxEnabled() ) { - return metadataCollector.getPropertyAnnotatedWithMapsId( mappedClass, propertyName ); + return metadataCollector.getPropertyAnnotatedWithMapsId( classDetails, propertyName ); } } - return metadataCollector.getPropertyAnnotatedWithMapsId( mappedClass, isId ? "" : propertyName ); + return metadataCollector.getPropertyAnnotatedWithMapsId( classDetails, isId ? "" : propertyName ); } - public static Map toAliasTableMap(SqlFragmentAlias[] aliases){ + public static Map toAliasTableMap(List> aliases){ final Map ret = new HashMap<>(); - for ( SqlFragmentAlias alias : aliases ) { - if ( isNotEmpty( alias.table() ) ) { - ret.put( alias.alias(), alias.table() ); + for ( AnnotationUsage aliasAnnotation : aliases ) { + final String table = aliasAnnotation.getString( "table" ); + if ( isNotEmpty( table ) ) { + ret.put( aliasAnnotation.getString( "alias" ), table ); } } return ret; } - public static Map toAliasEntityMap(SqlFragmentAlias[] aliases){ + public static Map toAliasEntityMap(List> aliases){ final Map result = new HashMap<>(); - for ( SqlFragmentAlias alias : aliases ) { - if ( alias.entity() != void.class ) { - result.put( alias.alias(), alias.entity().getName() ); + for ( AnnotationUsage aliasAnnotation : aliases ) { + final ClassDetails entityClassDetails = aliasAnnotation.getClassDetails( "entity" ); + if ( entityClassDetails != ClassDetails.VOID_CLASS_DETAILS ) { + result.put( aliasAnnotation.getString( "alias" ), entityClassDetails.getName() ); } } return result; } - public static boolean hasToOneAnnotation(XAnnotatedElement property) { - return property.isAnnotationPresent(ManyToOne.class) - || property.isAnnotationPresent(OneToOne.class); + public static boolean hasToOneAnnotation(AnnotationTarget property) { + return property.hasAnnotationUsage(ManyToOne.class) + || property.hasAnnotationUsage(OneToOne.class); } - public static T getOverridableAnnotation( - XAnnotatedElement element, - Class annotationType, - MetadataBuildingContext context) { - final Dialect dialect = context.getMetadataCollector().getDatabase().getDialect(); - final Iterator annotations = - Arrays.stream( element.getAnnotations() ) - .flatMap( annotation -> { - final Method valueExtractor = isRepeableAndDialectOverride( annotation ); - if ( valueExtractor != null ) { - try { - return Stream.of( (Annotation[]) valueExtractor.invoke( annotation ) ); - } - catch (Exception e) { - throw new AssertionFailure("could not read @DialectOverride annotation", e); - } - } - return Stream.of( annotation ); - } ).iterator(); - while ( annotations.hasNext() ) { - final Annotation annotation = annotations.next(); - final Class type = annotation.annotationType(); - final DialectOverride.OverridesAnnotation overridesAnnotation = - type.getAnnotation(DialectOverride.OverridesAnnotation.class); - if ( overridesAnnotation != null - && overridesAnnotation.value().equals(annotationType) ) { - try { - //noinspection unchecked - final Class overrideDialect = (Class) - type.getDeclaredMethod("dialect").invoke(annotation); - if ( overrideDialect.isAssignableFrom( dialect.getClass() ) ) { - final DialectOverride.Version before = (DialectOverride.Version) - type.getDeclaredMethod("before").invoke(annotation); - final DialectOverride.Version sameOrAfter = (DialectOverride.Version) - type.getDeclaredMethod("sameOrAfter").invoke(annotation); - DatabaseVersion version = dialect.getVersion(); - if ( version.isBefore( before.major(), before.minor() ) - && version.isSameOrAfter( sameOrAfter.major(), sameOrAfter.minor() ) ) { - //noinspection unchecked - return (T) type.getDeclaredMethod("override").invoke(annotation); - } - } - } - catch (Exception e) { - throw new AssertionFailure("could not read @DialectOverride annotation", e); - } - } - } - return element.getAnnotation( annotationType ); - } - - //Wondering: should we make this cache non-static and store in the metadata context so that we can clear it after bootstrap? - //(not doing it now as it would make the patch more invasive - and there might be drawbacks to consider, such as - //needing to re-initialize this cache again during hot-reload scenarios: it might be nice to be able to plug the - //cache, so that runtimes can choose the most fitting strategy) - private static final ClassValue annotationMetaCacheForRepeatableDialectOverride = new ClassValue() { - @Override - protected Object computeValue(final Class type) { - final Method valueMethod; - try { - valueMethod = type.getDeclaredMethod( "value" ); - } - catch ( NoSuchMethodException e ) { - return NOT_REPEATABLE; - } - final Class returnType = valueMethod.getReturnType(); - if ( returnType.isArray() - && returnType.getComponentType().isAnnotationPresent( Repeatable.class ) - && returnType.getComponentType().isAnnotationPresent( DialectOverride.OverridesAnnotation.class ) ) { - return new AnnotationCacheValue( valueMethod ); - } - else { - return NOT_REPEATABLE; - } - } - }; - - private static final AnnotationCacheValue NOT_REPEATABLE = new AnnotationCacheValue( null ); - - private static class AnnotationCacheValue { - final Method valueMethod; - private AnnotationCacheValue(final Method valueMethod) { - //null is intentionally allowed: it means this annotations was NOT a Repeatable & DialectOverride.OverridesAnnotation annotation, - //which is also an information we want to cache (negative caching). - this.valueMethod = valueMethod; - } - } - - private static Method isRepeableAndDialectOverride(final Annotation annotation) { - return annotationMetaCacheForRepeatableDialectOverride.get( annotation.annotationType() ).valueMethod; - } public static FetchMode getFetchMode(FetchType fetch) { switch ( fetch ) { @@ -1046,7 +949,7 @@ public class BinderHelper { } } - private static EnumSet convertToHibernateCascadeType(jakarta.persistence.CascadeType[] ejbCascades) { + private static EnumSet convertToHibernateCascadeType(List ejbCascades) { final EnumSet cascadeTypes = EnumSet.noneOf( CascadeType.class ); if ( ejbCascades != null ) { for ( jakarta.persistence.CascadeType cascade: ejbCascades ) { @@ -1057,14 +960,16 @@ public class BinderHelper { } public static String getCascadeStrategy( - jakarta.persistence.CascadeType[] ejbCascades, - Cascade hibernateCascadeAnnotation, + List ejbCascades, + AnnotationUsage hibernateCascadeAnnotation, boolean orphanRemoval, boolean forcePersist) { final EnumSet cascadeTypes = convertToHibernateCascadeType( ejbCascades ); - final CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ? null : hibernateCascadeAnnotation.value(); - if ( hibernateCascades != null && hibernateCascades.length > 0 ) { - cascadeTypes.addAll( Arrays.asList( hibernateCascades ) ); + final List hibernateCascades = hibernateCascadeAnnotation == null + ? null + : hibernateCascadeAnnotation.getList( "value" ); + if ( hibernateCascades != null && !hibernateCascades.isEmpty() ) { + cascadeTypes.addAll( hibernateCascades ); } if ( orphanRemoval ) { cascadeTypes.add( CascadeType.DELETE_ORPHAN ); @@ -1120,13 +1025,18 @@ public class BinderHelper { return context.getBootstrapContext().getJpaCompliance().isGlobalGeneratorScopeEnabled(); } - static boolean isCompositeId(XClass entityClass, XProperty idProperty) { - return entityClass.isAnnotationPresent( Embeddable.class ) - || idProperty.isAnnotationPresent( EmbeddedId.class ); + static boolean isCompositeId(ClassDetails entityClass, MemberDetails idProperty) { + return entityClass.hasAnnotationUsage( Embeddable.class ) + || idProperty.hasAnnotationUsage( EmbeddedId.class ); } - public static boolean isDefault(XClass clazz, MetadataBuildingContext context) { - return context.getBootstrapContext().getReflectionManager().equals( clazz, void.class ); + public static boolean isDefault(ClassDetails clazz, MetadataBuildingContext context) { + return clazz == ClassDetails.VOID_CLASS_DETAILS; + } + + public static boolean isDefault(TypeDetails clazz, MetadataBuildingContext context) { + final ClassDetails rawClassDetails = TypeDetailsHelper.resolveRawClass( clazz ); + return rawClassDetails == ClassDetails.VOID_CLASS_DETAILS; } public static void checkMappedByType( @@ -1176,12 +1086,12 @@ public class BinderHelper { return false; } - public static boolean noConstraint(ForeignKey foreignKey, boolean noConstraintByDefault) { + public static boolean noConstraint(AnnotationUsage foreignKey, boolean noConstraintByDefault) { if ( foreignKey == null ) { return false; } else { - final ConstraintMode mode = foreignKey.value(); + final ConstraintMode mode = foreignKey.getEnum( "value" ); return mode == NO_CONSTRAINT || mode == PROVIDER_DEFAULT && noConstraintByDefault; } @@ -1191,14 +1101,14 @@ public class BinderHelper { * Extract an annotation from the package-info for the package the given class is defined in * * @param annotationType The type of annotation to return - * @param xClass The class in the package + * @param classDetails The class in the package * @param context The processing context * * @return The annotation or {@code null} */ - public static A extractFromPackage( + public static AnnotationUsage extractFromPackage( Class annotationType, - XClass xClass, + ClassDetails classDetails, MetadataBuildingContext context) { // todo (soft-delete) : or if we want caching of this per package @@ -1208,19 +1118,23 @@ public class BinderHelper { // where context.getMetadataCollector() can cache some of this - either the annotations themselves // or even just the XPackage resolutions - final String declaringClassName = xClass.getName(); + final String declaringClassName = classDetails.getName(); final String packageName = qualifier( declaringClassName ); - if ( isNotEmpty( packageName ) ) { - final ClassLoaderService classLoaderService = - context.getBootstrapContext().getServiceRegistry() - .requireService( ClassLoaderService.class ); - final Package declaringClassPackage = classLoaderService.packageForNameOrNull( packageName ); - if ( declaringClassPackage != null ) { - // will be null when there is no `package-info.class` - final XPackage xPackage = context.getBootstrapContext().getReflectionManager().toXPackage( declaringClassPackage ); - return xPackage.getAnnotation( annotationType ); - } + + if ( isEmpty( packageName ) ) { + return null; } + + final ClassDetailsRegistry classDetailsRegistry = context.getMetadataCollector() + .getSourceModelBuildingContext() + .getClassDetailsRegistry(); + final String packageInfoName = packageName + ".package-info"; + try { + final ClassDetails packageInfoClassDetails = classDetailsRegistry.resolveClassDetails( packageInfoName ); + return packageInfoClassDetails.getAnnotationUsage( annotationType ); + } + catch (ClassLoadingException ignore) {} + return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java index 995d43a6e7..60af3d0318 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java @@ -16,8 +16,6 @@ import java.util.function.Consumer; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; import org.hibernate.PropertyNotFoundException; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.boot.spi.SecondPass; @@ -34,9 +32,14 @@ import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.Value; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.TypeDetails; import jakarta.persistence.Convert; -import jakarta.persistence.Converts; import jakarta.persistence.JoinTable; import static org.hibernate.internal.util.StringHelper.isEmpty; @@ -50,16 +53,16 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { private Map joins; private transient Map joinsPerRealTableName; private EntityBinder entityBinder; - private final Map inheritanceStatePerClass; + private final Map inheritanceStatePerClass; private final Map attributeConversionInfoMap; public ClassPropertyHolder( PersistentClass persistentClass, - XClass entityXClass, + ClassDetails entityXClass, Map joins, MetadataBuildingContext context, - Map inheritanceStatePerClass) { + Map inheritanceStatePerClass) { super( persistentClass.getEntityName(), null, entityXClass, context ); this.persistentClass = persistentClass; this.joins = joins; @@ -70,10 +73,10 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { public ClassPropertyHolder( PersistentClass persistentClass, - XClass entityXClass, + ClassDetails entityXClass, EntityBinder entityBinder, MetadataBuildingContext context, - Map inheritanceStatePerClass) { + Map inheritanceStatePerClass) { this( persistentClass, entityXClass, entityBinder.getSecondaryTables(), context, inheritanceStatePerClass ); this.entityBinder = entityBinder; } @@ -88,54 +91,39 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { return getEntityName() + '.' + attributeName; } - protected Map buildAttributeConversionInfoMap(XClass entityXClass) { + protected Map buildAttributeConversionInfoMap(ClassDetails entityClassDetails) { final HashMap map = new HashMap<>(); - collectAttributeConversionInfo( map, entityXClass ); + collectAttributeConversionInfo( map, entityClassDetails ); return map; } - private void collectAttributeConversionInfo(Map infoMap, XClass xClass) { - if ( xClass == null ) { + private void collectAttributeConversionInfo(Map infoMap, ClassDetails entityClassDetails) { + if ( entityClassDetails == null ) { // typically indicates we have reached the end of the inheritance hierarchy return; } // collect superclass info first - collectAttributeConversionInfo( infoMap, xClass.getSuperclass() ); + collectAttributeConversionInfo( infoMap, entityClassDetails.getSuperClass() ); - final boolean canContainConvert = xClass.isAnnotationPresent( jakarta.persistence.Entity.class ) - || xClass.isAnnotationPresent( jakarta.persistence.MappedSuperclass.class ) - || xClass.isAnnotationPresent( jakarta.persistence.Embeddable.class ); + final boolean canContainConvert = entityClassDetails.hasAnnotationUsage( jakarta.persistence.Entity.class ) + || entityClassDetails.hasAnnotationUsage( jakarta.persistence.MappedSuperclass.class ) + || entityClassDetails.hasAnnotationUsage( jakarta.persistence.Embeddable.class ); if ( ! canContainConvert ) { return; } - { - final Convert convertAnnotation = xClass.getAnnotation( Convert.class ); - if ( convertAnnotation != null ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, xClass ); - if ( isEmpty( info.getAttributeName() ) ) { - throw new IllegalStateException( "@Convert placed on @Entity/@MappedSuperclass must define attributeName" ); - } - infoMap.put( info.getAttributeName(), info ); + entityClassDetails.forEachAnnotationUsage( Convert.class, (usage) -> { + final AttributeConversionInfo info = new AttributeConversionInfo( usage, entityClassDetails ); + if ( isEmpty( info.getAttributeName() ) ) { + throw new IllegalStateException( "@Convert placed on @Entity/@MappedSuperclass must define attributeName" ); } - } - { - final Converts convertsAnnotation = xClass.getAnnotation( Converts.class ); - if ( convertsAnnotation != null ) { - for ( Convert convertAnnotation : convertsAnnotation.value() ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, xClass ); - if ( isEmpty( info.getAttributeName() ) ) { - throw new IllegalStateException( "@Converts placed on @Entity/@MappedSuperclass must define attributeName" ); - } - infoMap.put( info.getAttributeName(), info ); - } - } - } + infoMap.put( info.getAttributeName(), info ); + } ); } @Override - public void startingProperty(XProperty property) { + public void startingProperty(MemberDetails property) { if ( property == null ) { return; } @@ -145,39 +133,20 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { return; } - { - // @Convert annotation on the Embeddable attribute - final Convert convertAnnotation = property.getAnnotation( Convert.class ); - if ( convertAnnotation != null ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property ); - if ( isEmpty( info.getAttributeName() ) ) { - attributeConversionInfoMap.put( propertyName, info ); - } - else { - attributeConversionInfoMap.put( propertyName + '.' + info.getAttributeName(), info ); - } + property.forEachAnnotationUsage( Convert.class, (usage) -> { + final AttributeConversionInfo info = new AttributeConversionInfo( usage, property ); + if ( isEmpty( info.getAttributeName() ) ) { + attributeConversionInfoMap.put( propertyName, info ); } - } - { - // @Converts annotation on the Embeddable attribute - final Converts convertsAnnotation = property.getAnnotation( Converts.class ); - if ( convertsAnnotation != null ) { - for ( Convert convertAnnotation : convertsAnnotation.value() ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property ); - if ( isEmpty( info.getAttributeName() ) ) { - attributeConversionInfoMap.put( propertyName, info ); - } - else { - attributeConversionInfoMap.put( propertyName + '.' + info.getAttributeName(), info ); - } - } + else { + attributeConversionInfoMap.put( propertyName + '.' + info.getAttributeName(), info ); } - } + } ); } @Override - protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) { - return locateAttributeConversionInfo( property.getName() ); + protected AttributeConversionInfo locateAttributeConversionInfo(MemberDetails attributeMember) { + return locateAttributeConversionInfo( attributeMember.getName() ); } @Override @@ -191,53 +160,53 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { } @Override - public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) { + public void addProperty(Property prop, MemberDetails memberDetails, AnnotatedColumns columns, ClassDetails declaringClass) { //AnnotatedColumn.checkPropertyConsistency( ); //already called earlier if ( columns != null ) { if ( columns.isSecondary() ) { - addPropertyToJoin( prop, declaringClass, columns.getJoin() ); + addPropertyToJoin( prop, memberDetails, declaringClass, columns.getJoin() ); } else { - addProperty( prop, declaringClass ); + addProperty( prop, memberDetails, declaringClass ); } } else { - addProperty( prop, declaringClass ); + addProperty( prop, memberDetails, declaringClass ); } } @Override - public void addProperty(Property prop, XClass declaringClass) { + public void addProperty(Property prop, MemberDetails memberDetails, ClassDetails declaringClass) { if ( prop.getValue() instanceof Component ) { //TODO handle quote and non quote table comparison String tableName = prop.getValue().getTable().getName(); if ( getJoinsPerRealTableName().containsKey( tableName ) ) { final Join join = getJoinsPerRealTableName().get( tableName ); - addPropertyToJoin( prop, declaringClass, join ); + addPropertyToJoin( prop, memberDetails, declaringClass, join ); } else { - addPropertyToPersistentClass( prop, declaringClass ); + addPropertyToPersistentClass( prop, memberDetails, declaringClass ); } } else { - addPropertyToPersistentClass( prop, declaringClass ); + addPropertyToPersistentClass( prop, memberDetails, declaringClass ); } } @Override - public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) { - final Join join = entityBinder.addJoin( joinTableAnn, this, noDelayInPkColumnCreation ); + public Join addJoin(AnnotationUsage joinTableAnn, boolean noDelayInPkColumnCreation) { + final Join join = entityBinder.addJoinTable( joinTableAnn, this, noDelayInPkColumnCreation ); joins = entityBinder.getSecondaryTables(); return join; } @Override - public Join addJoin(JoinTable joinTable, Table table, boolean noDelayInPkColumnCreation) { + public Join addJoin(AnnotationUsage joinTable, Table table, boolean noDelayInPkColumnCreation) { final Join join = entityBinder.createJoin( this, noDelayInPkColumnCreation, false, - joinTable.joinColumns(), + joinTable.getList( "joinColumns" ), table.getQualifiedTableName(), table ); @@ -251,7 +220,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { * as generic, to later be able to resolve its concrete type, and creating a new component * with correctly typed sub-properties for the metamodel. */ - public static void handleGenericComponentProperty(Property property, MetadataBuildingContext context) { + public static void handleGenericComponentProperty(Property property, MemberDetails memberDetails, MetadataBuildingContext context) { final Value value = property.getValue(); if ( value instanceof Component ) { final Component component = (Component) value; @@ -265,7 +234,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { for ( Property prop : component.getProperties() ) { prepareActualProperty( prop, - component.getComponentClass(), + memberDetails, true, context, copy::addProperty @@ -276,8 +245,8 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { } } - private void addPropertyToPersistentClass(Property property, XClass declaringClass) { - handleGenericComponentProperty( property, getContext() ); + private void addPropertyToPersistentClass(Property property, MemberDetails memberDetails, ClassDetails declaringClass) { + handleGenericComponentProperty( property, memberDetails, getContext() ); if ( declaringClass != null ) { final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass ); if ( inheritanceState == null ) { @@ -287,7 +256,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { } if ( inheritanceState.isEmbeddableSuperclass() ) { persistentClass.addMappedSuperclassProperty( property ); - addPropertyToMappedSuperclass( property, declaringClass, getContext() ); + addPropertyToMappedSuperclass( property, memberDetails, declaringClass, getContext() ); } else { persistentClass.addProperty( property ); @@ -298,143 +267,178 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { } } - static void addPropertyToMappedSuperclass(Property prop, XClass declaringClass, MetadataBuildingContext context) { - final Class type = context.getBootstrapContext().getReflectionManager().toClass( declaringClass ); - final MappedSuperclass superclass = context.getMetadataCollector().getMappedSuperclass( type ); - prepareActualProperty( prop, type, true, context, superclass::addDeclaredProperty ); + private void addPropertyToMappedSuperclass(Property prop, MemberDetails memberDetails, ClassDetails declaringClass) { + final MappedSuperclass superclass = getContext().getMetadataCollector().getMappedSuperclass( declaringClass.toJavaClass() ); + prepareActualProperty( prop, memberDetails, true, getContext(), superclass::addDeclaredProperty ); } static void prepareActualProperty( Property prop, - Class type, + MemberDetails memberDetails, boolean allowCollections, MetadataBuildingContext context, Consumer propertyConsumer) { - if ( type.getTypeParameters().length == 0 ) { + final ClassDetails declaringType = memberDetails.getDeclaringType(); + if ( CollectionHelper.isEmpty( declaringType.getTypeParameters() ) ) { propertyConsumer.accept( prop ); + return; } - else { - // If the type has type parameters, we have to look up the XClass and actual property again - // because the given XClass has a TypeEnvironment based on the type variable assignments of a subclass - // and that might result in a wrong property type being used for a property which uses a type variable - final XClass actualDeclaringClass = context.getBootstrapContext().getReflectionManager().toXClass( type ); - for ( XProperty declaredProperty : getDeclaredProperties( actualDeclaringClass, prop.getPropertyAccessorName() ) ) { - if ( prop.getName().equals( declaredProperty.getName() ) ) { - final PropertyData inferredData = new PropertyInferredData( - actualDeclaringClass, - declaredProperty, - null, - context.getBootstrapContext().getReflectionManager() - ); - if ( declaredProperty.isTypeResolved() ) { - // Avoid copying when the property doesn't depend on a type variable - propertyConsumer.accept( prop ); - return; - } - // If the property depends on a type variable, we have to copy it and the Value - final Property actualProperty = prop.copy(); - actualProperty.setGeneric( true ); - actualProperty.setReturnedClassName( inferredData.getTypeName() ); - final Value value = actualProperty.getValue().copy(); - if ( value instanceof Collection ) { - if ( !allowCollections ) { - throw new AssertionFailure( "Collections are not allowed as identifier properties" ); - } - final Collection collection = (Collection) value; - // The owner is a MappedSuperclass which is not a PersistentClass, so set it to null + + // no idea what this code should be doing + final TypeDetails typeDetails = memberDetails.getType(); + if ( typeDetails.getTypeKind() == TypeDetails.Kind.PARAMETERIZED_TYPE ) { + + } + else if ( typeDetails.getTypeKind() == TypeDetails.Kind.TYPE_VARIABLE ) { + + } + + applyGenerics2( prop, memberDetails, typeDetails, allowCollections, propertyConsumer, context ); + //applyGenerics( prop, typeDetails, allowCollections, propertyConsumer, context ); + } + + private static void applyGenerics2( + Property prop, + MemberDetails memberDetails, + TypeDetails typeDetails, + boolean allowCollections, + Consumer propertyConsumer, + MetadataBuildingContext context) { + if ( typeDetails.determineRawClass().getTypeParameters().isEmpty() ) { + propertyConsumer.accept( prop ); + return; + } + + final ClassDetails declaringClassDetails = memberDetails.getDeclaringType(); + final List declaredAttributeMembers = getDeclaredAttributeMembers( declaringClassDetails, prop.getPropertyAccessorName() ); + members_loop: for ( MemberDetails attributeMember : declaredAttributeMembers ) { + if ( !prop.getName().equals( attributeMember.resolveAttributeName() ) ) { + continue; + } + + final PropertyData inferredData = new PropertyInferredData( + declaringClassDetails, + attributeMember, + null, + context + ); + final Value originalValue = prop.getValue(); + + // If the property depends on a type variable, we have to copy it and the Value + final Property actualProperty = prop.copy(); + actualProperty.setGeneric( true ); + actualProperty.setReturnedClassName( inferredData.getTypeName() ); + final Value value = actualProperty.getValue().copy(); + if ( value instanceof Collection collection ) { + if ( !allowCollections ) { + throw new AssertionFailure( "Collections are not allowed as identifier properties" ); + } + // The owner is a MappedSuperclass which is not a PersistentClass, so set it to null // collection.setOwner( null ); - collection.setRole( type.getName() + "." + prop.getName() ); - // To copy the element and key values, we need to defer setting the type name until the CollectionBinder ran - final Value originalValue = prop.getValue(); - context.getMetadataCollector().addSecondPass( - new SecondPass() { - @Override - public void doSecondPass(Map persistentClasses) throws MappingException { - final Collection initializedCollection = (Collection) originalValue; - final Value element = initializedCollection.getElement().copy(); - setTypeName( element, inferredData.getProperty().getElementClass().getName() ); - if ( initializedCollection instanceof IndexedCollection ) { - final Value index = ( (IndexedCollection) initializedCollection ).getIndex().copy(); - if ( inferredData.getProperty().getMapKey() != null ) { - setTypeName( index, inferredData.getProperty().getMapKey().getName() ); - } - ( (IndexedCollection) collection ).setIndex( index ); - } - collection.setElement( element ); + collection.setRole( typeDetails.getName() + "." + prop.getName() ); + // To copy the element and key values, we need to defer setting the type name until the CollectionBinder ran + final Value originalValue = prop.getValue();context.getMetadataCollector().addSecondPass( + new SecondPass() { + @Override + public void doSecondPass(Map persistentClasses) throws MappingException { + final Collection initializedCollection = (Collection) originalValue; + final Value element = initializedCollection.getElement().copy(); + setTypeName( element, inferredData.getAttributeMember().getElementType().getName() ); + if ( initializedCollection instanceof IndexedCollection ) { + final Value index = ( (IndexedCollection) initializedCollection ).getIndex().copy(); + if ( inferredData.getAttributeMember().getMapKeyType() != null ) { + setTypeName( index, inferredData.getAttributeMember().getMapKeyType().getName() ); } + ( (IndexedCollection) collection ).setIndex( index ); } - ); + collection.setElement( element ); + } + } + ); + } + else { + setTypeName( value, inferredData.getTypeName() ); + } + + if ( value instanceof Component component ) { + final Class componentClass = component.getComponentClass(); + if ( component.isGeneric() ) { + actualProperty.setValue( context.getMetadataCollector().getGenericComponent( componentClass ) ); + } + else { + if ( componentClass == Object.class ) { + // Object is not a valid component class, but that is what we get when using a type variable + component.clearProperties(); } else { - setTypeName( value, inferredData.getTypeName() ); - } - if ( value instanceof Component ) { - final Component component = ( (Component) value ); - final Class componentClass = component.getComponentClass(); - if ( component.isGeneric() ) { - actualProperty.setValue( context.getMetadataCollector().getGenericComponent( componentClass ) ); - } - else { - if ( componentClass == Object.class ) { - // Object is not a valid component class, but that is what we get when using a type variable - component.clearProperties(); + final Iterator propertyIterator = component.getProperties().iterator(); + while ( propertyIterator.hasNext() ) { + try { + propertyIterator.next().getGetter( componentClass ); } - else { - final Iterator propertyIterator = component.getPropertyIterator(); - while ( propertyIterator.hasNext() ) { - try { - propertyIterator.next().getGetter( componentClass ); - } - catch (PropertyNotFoundException e) { - propertyIterator.remove(); - } - } + catch (PropertyNotFoundException e) { + propertyIterator.remove(); } } } - actualProperty.setValue( value ); - propertyConsumer.accept( actualProperty ); - break; } } + actualProperty.setValue( value ); + propertyConsumer.accept( actualProperty ); + + // avoid the rest of the iteration + //noinspection UnnecessaryLabelOnBreakStatement + break members_loop; } } - private static List getDeclaredProperties(XClass declaringClass, String accessType) { - final List properties = new ArrayList<>(); - XClass superclass = declaringClass; + private static List getDeclaredAttributeMembers( + ClassDetails declaringType, + String propertyAccessorName) { + final List members = new ArrayList<>(); + ClassDetails superclass = declaringType; while ( superclass != null ) { - properties.addAll( superclass.getDeclaredProperties( accessType ) ); - superclass = superclass.getSuperclass(); + applyAttributeMembers( superclass, propertyAccessorName, members ); + superclass = superclass.getSuperClass(); } - return properties; + return members; } - private static String getTypeName(Property property) { - final String typeName = getTypeName( property.getValue() ); - return typeName != null ? typeName : property.getReturnedClassName(); - } - private static String getTypeName(Value value) { - if ( value instanceof Component ) { - final Component component = (Component) value; - final String typeName = component.getTypeName(); - if ( typeName != null ) { - return typeName; + public static final String ACCESS_PROPERTY = "property"; + public static final String ACCESS_FIELD = "field"; + public static final String ACCESS_RECORD = "record"; + + @SuppressWarnings("RedundantLabeledSwitchRuleCodeBlock") + private static void applyAttributeMembers(ClassDetails classDetails, String accessType, List members) { + switch ( accessType ) { + case ACCESS_FIELD -> { + for ( FieldDetails field : classDetails.getFields() ) { + if ( field.isPersistable() ) { + members.add( field ); + } + } + } + case ACCESS_PROPERTY -> { + for ( MethodDetails methodDetails : classDetails.getMethods() ) { + if ( methodDetails.isPersistable() ) { + members.add( methodDetails ); + } + } + } + case ACCESS_RECORD -> { + members.addAll( classDetails.getRecordComponents() ); } - return component.getComponentClassName(); } - return ( (SimpleValue) value ).getTypeName(); + throw new IllegalArgumentException( "Unknown access type " + accessType ); } private static void setTypeName(Value value, String typeName) { - if ( value instanceof ToOne ) { - final ToOne toOne = (ToOne) value; + if ( value instanceof ToOne toOne ) { toOne.setReferencedEntityName( typeName ); toOne.setTypeName( typeName ); } - else if ( value instanceof Component ) { - final Component component = (Component) value; + else if ( value instanceof Component component ) { // Avoid setting type name for generic components if ( !component.isGeneric() ) { component.setComponentClassName( typeName ); @@ -448,7 +452,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { } } - private void addPropertyToJoin(Property property, XClass declaringClass, Join join) { + private void addPropertyToJoin(Property property, MemberDetails memberDetails, ClassDetails declaringClass, Join join) { if ( declaringClass != null ) { final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass ); if ( inheritanceState == null ) { @@ -458,7 +462,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { } if ( inheritanceState.isEmbeddableSuperclass() ) { join.addMappedSuperclassProperty( property ); - addPropertyToMappedSuperclass( property, declaringClass, getContext() ); + addPropertyToMappedSuperclass( property, memberDetails, declaringClass, getContext() ); } else { join.addProperty( property ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java index 786e6dc7f8..c4117a9575 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java @@ -34,11 +34,8 @@ import org.hibernate.annotations.Columns; import org.hibernate.annotations.CompositeType; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchProfileOverride; -import org.hibernate.annotations.FetchProfileOverrides; import org.hibernate.annotations.Filter; import org.hibernate.annotations.FilterJoinTable; -import org.hibernate.annotations.FilterJoinTables; -import org.hibernate.annotations.Filters; import org.hibernate.annotations.Formula; import org.hibernate.annotations.HQLSelect; import org.hibernate.annotations.Immutable; @@ -62,7 +59,6 @@ import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.OptimisticLock; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Persister; import org.hibernate.annotations.QueryCacheLayout; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLDeleteAll; @@ -75,12 +71,11 @@ import org.hibernate.annotations.SQLUpdate; import org.hibernate.annotations.SoftDelete; import org.hibernate.annotations.SortComparator; import org.hibernate.annotations.SortNatural; +import org.hibernate.annotations.SqlFragmentAlias; import org.hibernate.annotations.Synchronize; import org.hibernate.annotations.Where; import org.hibernate.annotations.WhereJoinTable; import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.BootLogging; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.TypeDefinition; @@ -93,6 +88,7 @@ import org.hibernate.boot.spi.SecondPass; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jdbc.Expectation; import org.hibernate.mapping.Any; @@ -114,7 +110,12 @@ import org.hibernate.mapping.Value; import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.UnsupportedMappingException; import org.hibernate.metamodel.spi.EmbeddableInstantiator; -import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.models.internal.ClassTypeDetailsImpl; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.usertype.CompositeUserType; @@ -170,11 +171,8 @@ import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnot import static org.hibernate.boot.model.internal.BinderHelper.getPath; import static org.hibernate.boot.model.internal.BinderHelper.isDefault; import static org.hibernate.boot.model.internal.BinderHelper.isPrimitive; -import static org.hibernate.boot.model.internal.BinderHelper.toAliasEntityMap; -import static org.hibernate.boot.model.internal.BinderHelper.toAliasTableMap; import static org.hibernate.boot.model.internal.EmbeddableBinder.fillEmbeddable; import static org.hibernate.boot.model.internal.GeneratorBinder.buildGenerators; -import static org.hibernate.boot.model.internal.HCANNHelper.findAnnotation; import static org.hibernate.boot.model.internal.PropertyHolderBuilder.buildPropertyHolder; import static org.hibernate.boot.model.source.internal.hbm.ModelBinder.useEntityWhereClauseForCollections; import static org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle.fromResultCheckStyle; @@ -212,8 +210,10 @@ public abstract class CollectionBinder { protected String propertyName; protected PropertyHolder propertyHolder; private String mappedBy; - private XClass collectionElementType; - private XClass targetEntity; + private ClassDetails declaringClass; + protected MemberDetails property; + private TypeDetails collectionElementType; + private TypeDetails targetEntity; private String cascadeStrategy; private String cacheConcurrencyStrategy; private String cacheRegionName; @@ -231,23 +231,21 @@ public abstract class CollectionBinder { private boolean isExplicitAssociationTable; private AnnotatedColumns elementColumns; protected boolean isEmbedded; - protected XProperty property; protected NotFoundAction notFoundAction; private TableBinder tableBinder; protected AnnotatedColumns mapKeyColumns; protected AnnotatedJoinColumns mapKeyManyToManyColumns; protected Map localGenerators; - protected Map inheritanceStatePerClass; - private XClass declaringClass; + protected Map inheritanceStatePerClass; private boolean declaringClassSet; private AccessType accessType; private boolean hibernateExtensionMapping; - private OrderBy jpaOrderBy; - private org.hibernate.annotations.OrderBy sqlOrderBy; - private SQLOrder sqlOrder; - private SortNatural naturalSort; - private SortComparator comparatorSort; + private AnnotationUsage jpaOrderBy; + private AnnotationUsage sqlOrderBy; + private AnnotationUsage sqlOrder; + private AnnotationUsage naturalSort; + private AnnotationUsage comparatorSort; private String explicitType; private final Map explicitTypeParameters = new HashMap<>(); @@ -272,39 +270,38 @@ public abstract class CollectionBinder { EntityBinder entityBinder, boolean isIdentifierMapper, MetadataBuildingContext context, - Map inheritanceStatePerClass, - XProperty property, + Map inheritanceStatePerClass, + MemberDetails property, AnnotatedJoinColumns joinColumns) { - - final OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class ); - final ManyToMany manyToManyAnn = property.getAnnotation( ManyToMany.class ); - final ElementCollection elementCollectionAnn = property.getAnnotation( ElementCollection.class ); + final AnnotationUsage oneToManyAnn = property.getAnnotationUsage( OneToMany.class ); + final AnnotationUsage manyToManyAnn = property.getAnnotationUsage( ManyToMany.class ); + final AnnotationUsage elementCollectionAnn = property.getAnnotationUsage( ElementCollection.class ); checkAnnotations( propertyHolder, inferredData, property, oneToManyAnn, manyToManyAnn, elementCollectionAnn ); final CollectionBinder collectionBinder = getCollectionBinder( property, hasMapKeyAnnotation( property ), context ); collectionBinder.setIndexColumn( getIndexColumn( propertyHolder, inferredData, entityBinder, context, property ) ); - collectionBinder.setMapKey( property.getAnnotation( MapKey.class ) ); + collectionBinder.setMapKey( property.getAnnotationUsage( MapKey.class ) ); collectionBinder.setPropertyName( inferredData.getPropertyName() ); - collectionBinder.setJpaOrderBy( property.getAnnotation( OrderBy.class ) ); + collectionBinder.setJpaOrderBy( property.getAnnotationUsage( OrderBy.class ) ); collectionBinder.setSqlOrderBy( getOverridableAnnotation( property, org.hibernate.annotations.OrderBy.class, context ) ); collectionBinder.setSqlOrder( getOverridableAnnotation( property, SQLOrder.class, context ) ); - collectionBinder.setNaturalSort( property.getAnnotation( SortNatural.class ) ); - collectionBinder.setComparatorSort( property.getAnnotation( SortComparator.class ) ); - collectionBinder.setCache( property.getAnnotation( Cache.class ) ); - collectionBinder.setQueryCacheLayout( property.getAnnotation( QueryCacheLayout.class ) ); + collectionBinder.setNaturalSort( property.getAnnotationUsage( SortNatural.class ) ); + collectionBinder.setComparatorSort( property.getAnnotationUsage( SortComparator.class ) ); + collectionBinder.setCache( property.getAnnotationUsage( Cache.class ) ); + collectionBinder.setQueryCacheLayout( property.getAnnotationUsage( QueryCacheLayout.class ) ); collectionBinder.setPropertyHolder(propertyHolder); collectionBinder.setNotFoundAction( notFoundAction( propertyHolder, inferredData, property, manyToManyAnn ) ); - collectionBinder.setElementType( inferredData.getProperty().getElementClass() ); + collectionBinder.setElementType( inferredData.getClassOrElementType() ); collectionBinder.setAccessType( inferredData.getDefaultAccess() ); - collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) ); + collectionBinder.setEmbedded( property.hasAnnotationUsage( Embedded.class ) ); collectionBinder.setProperty( property ); collectionBinder.setOnDeleteActionAction( onDeleteAction( property ) ); collectionBinder.setInheritanceStatePerClass( inheritanceStatePerClass ); collectionBinder.setDeclaringClass( inferredData.getDeclaringClass() ); // final Comment comment = property.getAnnotation( Comment.class ); - final Cascade hibernateCascade = property.getAnnotation( Cascade.class ); + final AnnotationUsage hibernateCascade = property.getAnnotationUsage( Cascade.class ); collectionBinder.setElementColumns( elementColumns( propertyHolder, @@ -359,7 +356,9 @@ public abstract class CollectionBinder { collectionBinder.setInsertable( false ); collectionBinder.setUpdatable( false ); } - if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary + + if ( property.hasAnnotationUsage( CollectionId.class ) ) { + //do not compute the generators unless necessary final HashMap localGenerators = new HashMap<>(classGenerators); localGenerators.putAll( buildGenerators( property, context ) ); collectionBinder.setLocalGenerators( localGenerators ); @@ -368,18 +367,22 @@ public abstract class CollectionBinder { collectionBinder.bind(); } + private static TypeDetails determineElementType(PropertyData inferredData) { + return inferredData.getClassOrElementType(); + } + private static NotFoundAction notFoundAction( PropertyHolder propertyHolder, PropertyData inferredData, - XProperty property, - ManyToMany manyToManyAnn) { - final NotFound notFound = property.getAnnotation( NotFound.class ); + MemberDetails property, + AnnotationUsage manyToManyAnn) { + final AnnotationUsage notFound = property.getAnnotationUsage( NotFound.class ); if ( notFound != null ) { if ( manyToManyAnn == null ) { throw new AnnotationException( "Collection '" + getPath(propertyHolder, inferredData) + "' annotated '@NotFound' is not a '@ManyToMany' association" ); } - return notFound.action(); + return notFound.getEnum( "action" ); } else { return null; @@ -391,10 +394,10 @@ public abstract class CollectionBinder { PropertyData inferredData, EntityBinder entityBinder, MetadataBuildingContext context, - XProperty property) { + MemberDetails property) { // Comment comment) { return buildJoinColumnsWithDefaultColumnSuffix( - mapKeyJoinColumnAnnotations( propertyHolder, inferredData, property ), + mapKeyJoinColumnAnnotations( propertyHolder, inferredData, property, context ), // comment, null, entityBinder.getSecondaryTables(), @@ -405,14 +408,14 @@ public abstract class CollectionBinder { ); } - private static OnDeleteAction onDeleteAction(XProperty property) { - final OnDelete onDelete = property.getAnnotation( OnDelete.class ); - return onDelete == null ? null : onDelete.action(); + private static OnDeleteAction onDeleteAction(MemberDetails property) { + final AnnotationUsage onDelete = property.getAnnotationUsage( OnDelete.class ); + return onDelete == null ? null : onDelete.getEnum( "action" ); } - private static PropertyData virtualPropertyData(PropertyData inferredData, XProperty property) { + private static PropertyData virtualPropertyData(PropertyData inferredData, MemberDetails property) { //do not use "element" if you are a JPA 2 @ElementCollection, only for legacy Hibernate mappings - return property.isAnnotationPresent( ElementCollection.class ) + return property.hasAnnotationUsage( ElementCollection.class ) ? inferredData : new WrappedInferredData(inferredData, "element" ); } @@ -420,10 +423,10 @@ public abstract class CollectionBinder { private static void checkAnnotations( PropertyHolder propertyHolder, PropertyData inferredData, - XProperty property, - OneToMany oneToMany, - ManyToMany manyToMany, - ElementCollection elementCollection) { + MemberDetails property, + AnnotationUsage oneToMany, + AnnotationUsage manyToMany, + AnnotationUsage elementCollection) { if ( ( oneToMany != null || manyToMany != null || elementCollection != null ) && isToManyAssociationWithinEmbeddableCollection( propertyHolder ) ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) + @@ -431,21 +434,22 @@ public abstract class CollectionBinder { + annotationName( oneToMany, manyToMany, elementCollection )); } - if ( oneToMany != null && property.isAnnotationPresent( SoftDelete.class ) ) { + if ( oneToMany != null && property.hasAnnotationUsage( SoftDelete.class ) ) { throw new UnsupportedMappingException( "@SoftDelete cannot be applied to @OneToMany - " + - property.getDeclaringClass().getName() + "." + property.getName() + property.getDeclaringType().getName() + "." + property.getName() ); } - if ( property.isAnnotationPresent( OrderColumn.class ) - && manyToMany != null && !manyToMany.mappedBy().isEmpty() ) { + if ( property.hasAnnotationUsage( OrderColumn.class ) + && manyToMany != null + && StringHelper.isNotEmpty( manyToMany.getString( "mappedBy" ) ) ) { throw new AnnotationException("Collection '" + getPath( propertyHolder, inferredData ) + "' is the unowned side of a bidirectional '@ManyToMany' and may not have an '@OrderColumn'"); } if ( manyToMany != null || elementCollection != null ) { - if ( property.isAnnotationPresent( JoinColumn.class ) || property.isAnnotationPresent( JoinColumns.class ) ) { + if ( property.hasAnnotationUsage( JoinColumn.class ) || property.hasAnnotationUsage( JoinColumns.class ) ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) + "' is a " + annotationName( oneToMany, manyToMany, elementCollection ) + " and is directly annotated '@JoinColumn'" @@ -454,7 +458,10 @@ public abstract class CollectionBinder { } } - private static String annotationName(OneToMany oneToMany, ManyToMany manyToMany, ElementCollection elementCollection) { + private static String annotationName( + AnnotationUsage oneToMany, + AnnotationUsage manyToMany, + AnnotationUsage elementCollection) { return oneToMany != null ? "'@OneToMany'" : manyToMany != null ? "'@ManyToMany'" : "'@ElementCollection'"; } @@ -463,11 +470,11 @@ public abstract class CollectionBinder { PropertyData inferredData, EntityBinder entityBinder, MetadataBuildingContext context, - XProperty property) { + MemberDetails property) { return IndexColumn.fromAnnotations( - property.getAnnotation( OrderColumn.class ), - property.getAnnotation( org.hibernate.annotations.IndexColumn.class ), - property.getAnnotation( ListIndexBase.class ), + property.getAnnotationUsage( OrderColumn.class ), + property.getAnnotationUsage( org.hibernate.annotations.IndexColumn.class ), + property.getAnnotationUsage( ListIndexBase.class ), propertyHolder, inferredData, entityBinder.getSecondaryTables(), @@ -479,13 +486,13 @@ public abstract class CollectionBinder { PropertyHolder propertyHolder, PropertyData inferredData, MetadataBuildingContext context, - XProperty property, + MemberDetails property, AnnotatedJoinColumns joinColumns, - OneToMany oneToManyAnn, - ManyToMany manyToManyAnn, - ElementCollection elementCollectionAnn, + AnnotationUsage oneToManyAnn, + AnnotationUsage manyToManyAnn, + AnnotationUsage elementCollectionAnn, CollectionBinder collectionBinder, - Cascade hibernateCascade) { + AnnotationUsage hibernateCascade) { //TODO enhance exception with @ManyToAny and @CollectionOfElements if ( oneToManyAnn != null && manyToManyAnn != null ) { @@ -500,12 +507,14 @@ public abstract class CollectionBinder { + "' has foreign key in secondary table" ); } collectionBinder.setFkJoinColumns( joinColumns ); - mappedBy = nullIfEmpty( oneToManyAnn.mappedBy() ); - //noinspection unchecked - collectionBinder.setTargetEntity( reflectionManager.toXClass( oneToManyAnn.targetEntity() ) ); - collectionBinder.setCascadeStrategy( - getCascadeStrategy( oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval(), false ) - ); + mappedBy = nullIfEmpty( oneToManyAnn.getString( "mappedBy" ) ); + collectionBinder.setTargetEntity( oneToManyAnn.getClassDetails( "targetEntity" ) ); + collectionBinder.setCascadeStrategy( getCascadeStrategy( + oneToManyAnn.getList( "cascade" ), + hibernateCascade, + oneToManyAnn.getBoolean( "orphanRemoval" ), + false + ) ); collectionBinder.setOneToMany( true ); } else if ( elementCollectionAnn != null ) { @@ -515,26 +524,30 @@ public abstract class CollectionBinder { } collectionBinder.setFkJoinColumns( joinColumns ); mappedBy = null; - final Class targetElement = elementCollectionAnn.targetClass(); - collectionBinder.setTargetEntity( reflectionManager.toXClass( targetElement ) ); - //collectionBinder.setCascadeStrategy( getCascadeStrategy( embeddedCollectionAnn.cascade(), hibernateCascade ) ); + final ClassDetails targetClassDetails = elementCollectionAnn.getClassDetails( "targetClass" ); + collectionBinder.setTargetEntity( targetClassDetails ); collectionBinder.setOneToMany( false ); } else if ( manyToManyAnn != null ) { - mappedBy = nullIfEmpty( manyToManyAnn.mappedBy() ); - //noinspection unchecked - collectionBinder.setTargetEntity( reflectionManager.toXClass( manyToManyAnn.targetEntity() ) ); - collectionBinder.setCascadeStrategy( - getCascadeStrategy( manyToManyAnn.cascade(), hibernateCascade, false, false ) - ); + mappedBy = nullIfEmpty( manyToManyAnn.getString( "mappedBy" ) ); + collectionBinder.setTargetEntity( manyToManyAnn.getClassDetails( "targetEntity" ) ); + collectionBinder.setCascadeStrategy( getCascadeStrategy( + manyToManyAnn.getList( "cascade" ), + hibernateCascade, + false, + false + ) ); collectionBinder.setOneToMany( false ); } - else if ( property.isAnnotationPresent( ManyToAny.class ) ) { + else if ( property.hasAnnotationUsage( ManyToAny.class ) ) { mappedBy = null; - collectionBinder.setTargetEntity( reflectionManager.toXClass( void.class ) ); - collectionBinder.setCascadeStrategy( - getCascadeStrategy( null, hibernateCascade, false, false ) - ); + collectionBinder.setTargetEntity( ClassDetails.VOID_CLASS_DETAILS ); + collectionBinder.setCascadeStrategy( getCascadeStrategy( + null, + hibernateCascade, + false, + false + ) ); collectionBinder.setOneToMany( false ); } else { @@ -544,13 +557,13 @@ public abstract class CollectionBinder { return mappedBy; } - private static boolean hasMapKeyAnnotation(XProperty property) { - return property.isAnnotationPresent(MapKeyJavaType.class) - || property.isAnnotationPresent(MapKeyJdbcType.class) - || property.isAnnotationPresent(MapKeyJdbcTypeCode.class) - || property.isAnnotationPresent(MapKeyMutability.class) - || property.isAnnotationPresent(MapKey.class) - || property.isAnnotationPresent(MapKeyType.class); + private static boolean hasMapKeyAnnotation(MemberDetails property) { + return property.hasAnnotationUsage(MapKeyJavaType.class) + || property.hasAnnotationUsage(MapKeyJdbcType.class) + || property.hasAnnotationUsage(MapKeyJdbcTypeCode.class) + || property.hasAnnotationUsage(MapKeyMutability.class) + || property.hasAnnotationUsage(MapKey.class) + || property.hasAnnotationUsage(MapKeyType.class); } private static boolean isToManyAssociationWithinEmbeddableCollection(PropertyHolder propertyHolder) { @@ -568,12 +581,12 @@ public abstract class CollectionBinder { Nullability nullability, EntityBinder entityBinder, MetadataBuildingContext context, - XProperty property, + MemberDetails property, PropertyData virtualProperty) { // Comment comment) { - if ( property.isAnnotationPresent( jakarta.persistence.Column.class ) ) { + if ( property.hasAnnotationUsage( jakarta.persistence.Column.class ) ) { return buildColumnFromAnnotation( - property.getAnnotation( jakarta.persistence.Column.class ), + property.getAnnotationUsage( jakarta.persistence.Column.class ), null, // comment, nullability, @@ -583,7 +596,7 @@ public abstract class CollectionBinder { context ); } - else if ( property.isAnnotationPresent( Formula.class ) ) { + else if ( property.hasAnnotationUsage( Formula.class ) ) { return buildFormulaFromAnnotation( getOverridableAnnotation(property, Formula.class, context), // comment, @@ -594,9 +607,9 @@ public abstract class CollectionBinder { context ); } - else if ( property.isAnnotationPresent( Columns.class ) ) { + else if ( property.hasAnnotationUsage( Columns.class ) ) { return buildColumnsFromAnnotations( - property.getAnnotation( Columns.class ).columns(), + property.getAnnotationUsage( Columns.class ).getList( "columns" ), null, // comment, nullability, @@ -619,26 +632,36 @@ public abstract class CollectionBinder { } } - private static JoinColumn[] mapKeyJoinColumnAnnotations( + private static List> mapKeyJoinColumnAnnotations( PropertyHolder propertyHolder, PropertyData inferredData, - XProperty property) { - if ( property.isAnnotationPresent( MapKeyJoinColumns.class ) ) { - final MapKeyJoinColumn[] mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class ).value(); - final JoinColumn[] joinKeyColumns = new JoinColumn[mapKeyJoinColumns.length]; - int index = 0; - for ( MapKeyJoinColumn joinColumn : mapKeyJoinColumns ) { - joinKeyColumns[index] = new MapKeyJoinColumnDelegator( joinColumn ); - index++; + MemberDetails property, + MetadataBuildingContext context) { + if ( property.hasAnnotationUsage( MapKeyJoinColumns.class ) ) { + if ( property.hasAnnotationUsage( MapKeyJoinColumn.class ) ) { + throw new AnnotationException( + "Property '" + getPath( propertyHolder, inferredData ) + + "' is annotated with both '@MapKeyJoinColumn' and '@MapKeyJoinColumns'" + ); } - if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { - throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) - + "' is annotated both '@MapKeyJoinColumn' and '@MapKeyJoinColumns'" ); + final List> mapKeyJoinColumns = property.getAnnotationUsage( MapKeyJoinColumns.class ).getList( "value" ); + final List> joinKeyColumns = CollectionHelper.arrayList( mapKeyJoinColumns.size() ); + int index = 0; + for ( AnnotationUsage mapKeyJoinColumn : mapKeyJoinColumns ) { + final MutableAnnotationUsage joinColumn + = MapKeyJoinColumnDelegator.fromMapKeyJoinColumn( mapKeyJoinColumn, property, context ); + joinKeyColumns.add( joinColumn ); + index++; } return joinKeyColumns; } - else if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { - return new JoinColumn[] { new MapKeyJoinColumnDelegator( property.getAnnotation( MapKeyJoinColumn.class ) ) }; + else if ( property.hasAnnotationUsage( MapKeyJoinColumn.class ) ) { + final MutableAnnotationUsage delegator = MapKeyJoinColumnDelegator.fromMapKeyJoinColumn( + property.getAnnotationUsage( MapKeyJoinColumn.class ), + property, + context + ); + return List.of( delegator ); } else { return null; @@ -650,13 +673,12 @@ public abstract class CollectionBinder { PropertyData inferredData, EntityBinder entityBinder, MetadataBuildingContext context, - XProperty property) { + MemberDetails property) { // Comment comment) { + //noinspection unchecked,rawtypes,RedundantCast return buildColumnsFromAnnotations( - property.isAnnotationPresent( MapKeyColumn.class ) - ? new jakarta.persistence.Column[] { - new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) - } + property.hasAnnotationUsage( MapKeyColumn.class ) + ? (List) List.of( property.getAnnotationUsage( MapKeyColumn.class ) ) : null, // comment, Nullability.FORCED_NOT_NULL, @@ -669,7 +691,7 @@ public abstract class CollectionBinder { } private static void bindJoinedTableAssociation( - XProperty property, + MemberDetails property, MetadataBuildingContext buildingContext, EntityBinder entityBinder, CollectionBinder collectionBinder, @@ -677,42 +699,42 @@ public abstract class CollectionBinder { PropertyData inferredData, String mappedBy) { final TableBinder associationTableBinder = new TableBinder(); - final JoinTable assocTable = propertyHolder.getJoinTable( property ); - final CollectionTable collectionTable = property.getAnnotation( CollectionTable.class ); - final JoinColumn[] annJoins; - final JoinColumn[] annInverseJoins; - if ( assocTable != null || collectionTable != null ) { + final AnnotationUsage assocTable = propertyHolder.getJoinTable( property ); + final AnnotationUsage collectionTable = property.getAnnotationUsage( CollectionTable.class ); + final List> annJoins; + final List> annInverseJoins; + if ( assocTable != null || collectionTable != null ) { final String catalog; final String schema; final String tableName; - final UniqueConstraint[] uniqueConstraints; - final JoinColumn[] joins; - final JoinColumn[] inverseJoins; - final Index[] jpaIndexes; + final List> uniqueConstraints; + final List> joins; + final List> inverseJoins; + final List> jpaIndexes; //JPA 2 has priority if ( collectionTable != null ) { - catalog = collectionTable.catalog(); - schema = collectionTable.schema(); - tableName = collectionTable.name(); - uniqueConstraints = collectionTable.uniqueConstraints(); - joins = collectionTable.joinColumns(); + catalog = collectionTable.getString( "catalog" ); + schema = collectionTable.getString( "schema" ); + tableName = collectionTable.getString( "name" ); + uniqueConstraints = collectionTable.getList( "uniqueConstraints" ); + joins = collectionTable.getList( "joinColumns" ); inverseJoins = null; - jpaIndexes = collectionTable.indexes(); + jpaIndexes = collectionTable.getList( "indexes" ); } else { - catalog = assocTable.catalog(); - schema = assocTable.schema(); - tableName = assocTable.name(); - uniqueConstraints = assocTable.uniqueConstraints(); - joins = assocTable.joinColumns(); - inverseJoins = assocTable.inverseJoinColumns(); - jpaIndexes = assocTable.indexes(); + catalog = assocTable.getString( "catalog" ); + schema = assocTable.getString( "schema" ); + tableName = assocTable.getString( "name" ); + uniqueConstraints = assocTable.getList( "uniqueConstraints" ); + joins = assocTable.getList( "joinColumns" ); + inverseJoins = assocTable.getList( "inverseJoinColumns" ); + jpaIndexes = assocTable.getList( "indexes" ); } collectionBinder.setExplicitAssociationTable( true ); - if ( jpaIndexes != null && jpaIndexes.length > 0 ) { + if ( CollectionHelper.isNotEmpty( jpaIndexes ) ) { associationTableBinder.setJpaIndex( jpaIndexes ); } if ( !schema.isEmpty() ) { @@ -727,8 +749,8 @@ public abstract class CollectionBinder { associationTableBinder.setUniqueConstraints( uniqueConstraints ); associationTableBinder.setJpaIndex( jpaIndexes ); //set check constraint in the second pass - annJoins = joins.length == 0 ? null : joins; - annInverseJoins = inverseJoins == null || inverseJoins.length == 0 ? null : inverseJoins; + annJoins = joins.isEmpty() ? null : joins; + annInverseJoins = inverseJoins == null || inverseJoins.isEmpty() ? null : inverseJoins; } else { annJoins = null; @@ -778,7 +800,7 @@ public abstract class CollectionBinder { this.updatable = updatable; } - public void setInheritanceStatePerClass(Map inheritanceStatePerClass) { + public void setInheritanceStatePerClass(Map inheritanceStatePerClass) { this.inheritanceStatePerClass = inheritanceStatePerClass; } @@ -806,23 +828,24 @@ public abstract class CollectionBinder { this.propertyHolder = propertyHolder; } - public void setJpaOrderBy(jakarta.persistence.OrderBy jpaOrderBy) { + public void setJpaOrderBy(AnnotationUsage jpaOrderBy) { this.jpaOrderBy = jpaOrderBy; } - public void setSqlOrderBy(org.hibernate.annotations.OrderBy sqlOrderBy) { + @SuppressWarnings("removal") + public void setSqlOrderBy(AnnotationUsage sqlOrderBy) { this.sqlOrderBy = sqlOrderBy; } - public void setSqlOrder(SQLOrder sqlOrder) { + public void setSqlOrder(AnnotationUsage sqlOrder) { this.sqlOrder = sqlOrder; } - public void setNaturalSort(SortNatural naturalSort) { + public void setNaturalSort(AnnotationUsage naturalSort) { this.naturalSort = naturalSort; } - public void setComparatorSort(SortComparator comparatorSort) { + public void setComparatorSort(AnnotationUsage comparatorSort) { this.comparatorSort = comparatorSort; } @@ -830,18 +853,18 @@ public abstract class CollectionBinder { * collection binder factory */ public static CollectionBinder getCollectionBinder( - XProperty property, + MemberDetails property, boolean isHibernateExtensionMapping, MetadataBuildingContext buildingContext) { final CollectionBinder binder; - final CollectionType typeAnnotation = findAnnotation( property, CollectionType.class ); + final AnnotationUsage typeAnnotation = property.getAnnotationUsage( CollectionType.class ); if ( typeAnnotation != null ) { binder = createBinderFromCustomTypeAnnotation( property, typeAnnotation, buildingContext ); // todo (6.0) - technically, these should no longer be needed - binder.explicitType = typeAnnotation.type().getName(); - for ( Parameter param : typeAnnotation.parameters() ) { - binder.explicitTypeParameters.put( param.name(), param.value() ); + binder.explicitType = typeAnnotation.getClassDetails( "type" ).getClassName(); + for ( AnnotationUsage param : typeAnnotation.>getList( "parameters" ) ) { + binder.explicitTypeParameters.put( param.getString( "name" ), param.getString( "value" ) ); } } else { @@ -851,7 +874,7 @@ public abstract class CollectionBinder { return binder; } - private static CollectionBinder createBinderAutomatically(XProperty property, MetadataBuildingContext context) { + private static CollectionBinder createBinderAutomatically(MemberDetails property, MetadataBuildingContext context) { final CollectionClassification classification = determineCollectionClassification( property, context ); final CollectionTypeRegistrationDescriptor typeRegistration = context.getMetadataCollector().findCollectionTypeRegistration( classification ); @@ -861,14 +884,14 @@ public abstract class CollectionBinder { } private static CollectionBinder createBinderFromTypeRegistration( - XProperty property, + MemberDetails property, CollectionClassification classification, CollectionTypeRegistrationDescriptor typeRegistration, MetadataBuildingContext buildingContext) { return createBinder( property, () -> createCustomType( - property.getDeclaringClass().getName() + "#" + property.getName(), + property.getDeclaringType().getName() + "#" + property.getName(), typeRegistration.getImplementation(), typeRegistration.getParameters(), buildingContext @@ -920,18 +943,21 @@ public abstract class CollectionBinder { return managedBean; } - private static CollectionBinder createBinderFromProperty(XProperty property, MetadataBuildingContext context) { + private static CollectionBinder createBinderFromProperty(MemberDetails property, MetadataBuildingContext context) { final CollectionClassification classification = determineCollectionClassification( property, context ); return createBinder( property, null, classification, context ); } private static CollectionBinder createBinderFromCustomTypeAnnotation( - XProperty property, - CollectionType typeAnnotation, + MemberDetails property, + AnnotationUsage typeAnnotation, MetadataBuildingContext buildingContext) { - determineSemanticJavaType( property ); - final ManagedBean customTypeBean - = resolveCustomType( property, typeAnnotation, buildingContext ); + determineSemanticJavaType( property, buildingContext ); + final ManagedBean customTypeBean = resolveCustomType( + property, + typeAnnotation, + buildingContext + ); return createBinder( property, () -> customTypeBean, @@ -941,179 +967,174 @@ public abstract class CollectionBinder { } public static ManagedBean resolveCustomType( - XProperty property, - CollectionType typeAnnotation, + MemberDetails property, + AnnotationUsage typeAnnotation, MetadataBuildingContext context) { final Properties parameters = extractParameters( typeAnnotation ); //noinspection unchecked,rawtypes return createCustomType( - property.getDeclaringClass().getName() + "." + property.getName(), - typeAnnotation.type(), + property.getDeclaringType().getName() + "." + property.getName(), + typeAnnotation.getClassDetails( "type" ).toJavaClass(), (Map) parameters, context ); } - private static Properties extractParameters(CollectionType typeAnnotation) { - final Parameter[] parameterAnnotations = typeAnnotation.parameters(); - final Properties configParams = new Properties( parameterAnnotations.length ); - for ( Parameter parameterAnnotation : parameterAnnotations ) { - configParams.put( parameterAnnotation.name(), parameterAnnotation.value() ); + private static Properties extractParameters(AnnotationUsage typeAnnotation) { + final List> parameterAnnotations = typeAnnotation.getList( "parameters" ); + final Properties configParams = new Properties( parameterAnnotations.size() ); + for ( AnnotationUsage parameterAnnotation : parameterAnnotations ) { + configParams.put( parameterAnnotation.getString( "name" ), parameterAnnotation.getString( "value" ) ); } return configParams; } private static CollectionBinder createBinder( - XProperty property, + MemberDetails property, Supplier> customTypeBeanAccess, CollectionClassification classification, MetadataBuildingContext buildingContext) { - switch ( classification ) { - case ARRAY: - return property.getElementClass().isPrimitive() - ? new PrimitiveArrayBinder( customTypeBeanAccess, buildingContext ) - : new ArrayBinder( customTypeBeanAccess, buildingContext ); - case BAG: - return new BagBinder( customTypeBeanAccess, buildingContext ); - case ID_BAG: - return new IdBagBinder( customTypeBeanAccess, buildingContext ); - case LIST: - return new ListBinder( customTypeBeanAccess, buildingContext ); - case MAP: - case ORDERED_MAP: - return new MapBinder( customTypeBeanAccess, false, buildingContext ); - case SORTED_MAP: - return new MapBinder( customTypeBeanAccess, true, buildingContext ); - case SET: - case ORDERED_SET: - return new SetBinder( customTypeBeanAccess, false, buildingContext ); - case SORTED_SET: - return new SetBinder( customTypeBeanAccess, true, buildingContext ); - default: - throw new AnnotationException( - String.format( - Locale.ROOT, - "Unable to determine proper CollectionBinder (`%s) : %s.%s", - classification, - property.getDeclaringClass().getName(), - property.getName() - ) - ); - } + final TypeDetails elementType = property.getElementType(); + + return switch ( classification ) { + case ARRAY -> elementType.getTypeKind() == TypeDetails.Kind.PRIMITIVE + ? new PrimitiveArrayBinder( customTypeBeanAccess, buildingContext ) + : new ArrayBinder( customTypeBeanAccess, buildingContext ); + case BAG -> new BagBinder( customTypeBeanAccess, buildingContext ); + case ID_BAG -> new IdBagBinder( customTypeBeanAccess, buildingContext ); + case LIST -> new ListBinder( customTypeBeanAccess, buildingContext ); + case MAP, ORDERED_MAP -> new MapBinder( customTypeBeanAccess, false, buildingContext ); + case SORTED_MAP -> new MapBinder( customTypeBeanAccess, true, buildingContext ); + case SET, ORDERED_SET -> new SetBinder( customTypeBeanAccess, false, buildingContext ); + case SORTED_SET -> new SetBinder( customTypeBeanAccess, true, buildingContext ); + }; } private static CollectionClassification determineCollectionClassification( - XProperty property, + MemberDetails property, MetadataBuildingContext buildingContext) { if ( property.isArray() ) { return CollectionClassification.ARRAY; } - else if ( findAnnotation( property, Bag.class ) == null ) { - return determineCollectionClassification( determineSemanticJavaType( property ), property, buildingContext ); + + if ( !property.hasAnnotationUsage( Bag.class ) ) { + return determineCollectionClassification( determineSemanticJavaType( property, buildingContext ), property, buildingContext ); + } + + if ( property.hasAnnotationUsage( OrderColumn.class ) ) { + throw new AnnotationException( "Attribute '" + + qualify( property.getDeclaringType().getName(), property.getName() ) + + "' is annotated '@Bag' and may not also be annotated '@OrderColumn'" ); + } + + if ( property.hasAnnotationUsage( ListIndexBase.class ) ) { + throw new AnnotationException( "Attribute '" + + qualify( property.getDeclaringType().getName(), property.getName() ) + + "' is annotated '@Bag' and may not also be annotated '@ListIndexBase'" ); + } + + final ClassDetails collectionClassDetails = property.getType().determineRawClass(); + final Class collectionJavaType = collectionClassDetails.toJavaClass(); + if ( java.util.List.class.equals( collectionJavaType ) + || java.util.Collection.class.equals( collectionJavaType ) ) { + return CollectionClassification.BAG; } else { - if ( property.isAnnotationPresent( OrderColumn.class ) ) { - throw new AnnotationException( "Attribute '" - + qualify( property.getDeclaringClass().getName(), property.getName() ) - + "' is annotated '@Bag' and may not also be annotated '@OrderColumn'" ); - } - if ( property.isAnnotationPresent( ListIndexBase.class ) ) { - throw new AnnotationException( "Attribute '" - + qualify( property.getDeclaringClass().getName(), property.getName() ) - + "' is annotated '@Bag' and may not also be annotated '@ListIndexBase'" ); - } - final Class collectionJavaType = property.getCollectionClass(); - if ( java.util.List.class.equals( collectionJavaType ) - || java.util.Collection.class.equals( collectionJavaType ) ) { - return CollectionClassification.BAG; - } - else { - throw new AnnotationException( - String.format( - Locale.ROOT, - "Attribute '%s.%s' of type '%s' is annotated '@Bag' (bags are of type '%s' or '%s')", - property.getDeclaringClass().getName(), - property.getName(), - collectionJavaType.getName(), - java.util.List.class.getName(), - java.util.Collection.class.getName() - ) - ); - } + throw new AnnotationException( + String.format( + Locale.ROOT, + "Attribute '%s.%s' of type '%s' is annotated '@Bag' (bags are of type '%s' or '%s')", + property.getDeclaringType().getName(), + property.getName(), + collectionJavaType.getName(), + java.util.List.class.getName(), + java.util.Collection.class.getName() + ) + ); } } private static CollectionClassification determineCollectionClassification( Class semanticJavaType, - XProperty property, + MemberDetails property, MetadataBuildingContext buildingContext) { if ( semanticJavaType.isArray() ) { return CollectionClassification.ARRAY; } - else if ( property.isAnnotationPresent( CollectionId.class ) - || property.isAnnotationPresent( CollectionIdJdbcType.class ) - || property.isAnnotationPresent( CollectionIdJdbcTypeCode.class ) - || property.isAnnotationPresent( CollectionIdJavaType.class ) ) { + + if ( property.hasAnnotationUsage( CollectionId.class ) + || property.hasAnnotationUsage( CollectionIdJdbcType.class ) + || property.hasAnnotationUsage( CollectionIdJdbcTypeCode.class ) + || property.hasAnnotationUsage( CollectionIdJavaType.class ) ) { // explicitly an ID_BAG return CollectionClassification.ID_BAG; } - else if ( java.util.List.class.isAssignableFrom( semanticJavaType ) ) { - if ( property.isAnnotationPresent( OrderColumn.class ) - || property.isAnnotationPresent( org.hibernate.annotations.IndexColumn.class ) - || property.isAnnotationPresent( ListIndexBase.class ) - || property.isAnnotationPresent( ListIndexJdbcType.class ) - || property.isAnnotationPresent( ListIndexJdbcTypeCode.class ) - || property.isAnnotationPresent( ListIndexJavaType.class ) ) { + + if ( java.util.List.class.isAssignableFrom( semanticJavaType ) ) { + if ( property.hasAnnotationUsage( OrderColumn.class ) + || property.hasAnnotationUsage( org.hibernate.annotations.IndexColumn.class ) + || property.hasAnnotationUsage( ListIndexBase.class ) + || property.hasAnnotationUsage( ListIndexJdbcType.class ) + || property.hasAnnotationUsage( ListIndexJdbcTypeCode.class ) + || property.hasAnnotationUsage( ListIndexJavaType.class ) ) { // it is implicitly a LIST because of presence of explicit List index config return CollectionClassification.LIST; } - if ( property.isAnnotationPresent( jakarta.persistence.OrderBy.class ) - || property.isAnnotationPresent( org.hibernate.annotations.OrderBy.class ) ) { + + if ( property.hasAnnotationUsage( jakarta.persistence.OrderBy.class ) + || property.hasAnnotationUsage( org.hibernate.annotations.OrderBy.class ) ) { return CollectionClassification.BAG; } - ManyToMany manyToMany = property.getAnnotation( ManyToMany.class ); - if ( manyToMany != null && !manyToMany.mappedBy().isEmpty() ) { + + final AnnotationUsage manyToMany = property.getAnnotationUsage( ManyToMany.class ); + if ( manyToMany != null && !manyToMany.getString( "mappedBy" ).isEmpty() ) { // We don't support @OrderColumn on the non-owning side of a many-to-many association. return CollectionClassification.BAG; } - OneToMany oneToMany = property.getAnnotation( OneToMany.class ); - if ( oneToMany != null && !oneToMany.mappedBy().isEmpty() ) { + + final AnnotationUsage oneToMany = property.getAnnotationUsage( OneToMany.class ); + if ( oneToMany != null && !oneToMany.getString( "mappedBy" ).isEmpty() ) { // Unowned to-many mappings are always considered BAG by default return CollectionClassification.BAG; } + // otherwise, return the implicit classification for List attributes return buildingContext.getBuildingOptions().getMappingDefaults().getImplicitListClassification(); } - else if ( java.util.SortedSet.class.isAssignableFrom( semanticJavaType ) ) { + + if ( java.util.SortedSet.class.isAssignableFrom( semanticJavaType ) ) { return CollectionClassification.SORTED_SET; } - else if ( java.util.Set.class.isAssignableFrom( semanticJavaType ) ) { + + if ( java.util.Set.class.isAssignableFrom( semanticJavaType ) ) { return CollectionClassification.SET; } - else if ( java.util.SortedMap.class.isAssignableFrom( semanticJavaType ) ) { + + if ( java.util.SortedMap.class.isAssignableFrom( semanticJavaType ) ) { return CollectionClassification.SORTED_MAP; } - else if ( java.util.Map.class.isAssignableFrom( semanticJavaType ) ) { + + if ( java.util.Map.class.isAssignableFrom( semanticJavaType ) ) { return CollectionClassification.MAP; } - else if ( java.util.Collection.class.isAssignableFrom( semanticJavaType ) ) { - if ( property.isAnnotationPresent( CollectionId.class ) ) { + + if ( java.util.Collection.class.isAssignableFrom( semanticJavaType ) ) { + if ( property.hasAnnotationUsage( CollectionId.class ) ) { return CollectionClassification.ID_BAG; } else { return CollectionClassification.BAG; } } - else { - return null; - } + + return null; } - private static Class determineSemanticJavaType(XProperty property) { - @SuppressWarnings("rawtypes") - Class collectionClass = property.getCollectionClass(); - if ( collectionClass != null ) { + private static Class determineSemanticJavaType(MemberDetails property, MetadataBuildingContext buildingContext) { + if ( property.isPlural() ) { + final ClassDetails collectionClassDetails = property.getType().determineRawClass(); + final Class collectionClass = collectionClassDetails.toJavaClass(); return inferCollectionClassFromSubclass( collectionClass ); } else { @@ -1121,7 +1142,7 @@ public abstract class CollectionBinder { String.format( Locale.ROOT, "Property '%s.%s' is not a collection and may not be a '@OneToMany', '@ManyToMany', or '@ElementCollection'", - property.getDeclaringClass().getName(), + property.getDeclaringType().getName(), property.getName() ) ); @@ -1145,11 +1166,15 @@ public abstract class CollectionBinder { this.tableBinder = tableBinder; } - public void setElementType(XClass collectionElementType) { + public void setElementType(TypeDetails collectionElementType) { this.collectionElementType = collectionElementType; } - public void setTargetEntity(XClass targetEntity) { + public void setTargetEntity(ClassDetails targetEntity) { + setTargetEntity( new ClassTypeDetailsImpl( targetEntity, TypeDetails.Kind.CLASS ) ); + } + + public void setTargetEntity(TypeDetails targetEntity) { this.targetEntity = targetEntity; } @@ -1163,7 +1188,7 @@ public abstract class CollectionBinder { this.propertyName = propertyName; } - public void setDeclaringClass(XClass declaringClass) { + public void setDeclaringClass(ClassDetails declaringClass) { this.declaringClass = declaringClass; this.declaringClassSet = true; } @@ -1183,7 +1208,6 @@ public abstract class CollectionBinder { //work on association boolean isUnowned = isUnownedCollection(); bindOptimisticLock( isUnowned ); - bindCustomPersister(); applySortingAndOrdering(); bindCache(); bindLoader(); @@ -1201,11 +1225,11 @@ public abstract class CollectionBinder { } private boolean isMutable() { - return !property.isAnnotationPresent( Immutable.class ); + return !property.hasAnnotationUsage( Immutable.class ); } private void checkMapKeyColumn() { - if ( property.isAnnotationPresent( MapKeyColumn.class ) && hasMapKeyProperty ) { + if ( property.hasAnnotationUsage( MapKeyColumn.class ) && hasMapKeyProperty ) { throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName ) + "' is annotated both '@MapKey' and '@MapKeyColumn'" ); } @@ -1224,22 +1248,9 @@ public abstract class CollectionBinder { metadataCollector.addSecondPass( getSecondPass(), !isMappedBy ); } - @SuppressWarnings({"rawtypes", "unchecked"}) - private void bindCustomPersister() { - Persister persisterAnn = property.getAnnotation( Persister.class ); - if ( persisterAnn != null ) { - Class clazz = persisterAnn.impl(); - if ( !CollectionPersister.class.isAssignableFrom( clazz ) ) { - throw new AnnotationException( "Persister class '" + clazz.getName() - + "' does not implement 'CollectionPersister'" ); - } - collection.setCollectionPersisterClass( clazz ); - } - } - private void bindOptimisticLock(boolean isMappedBy) { - final OptimisticLock lockAnn = property.getAnnotation( OptimisticLock.class ); - final boolean includeInOptimisticLockChecks = lockAnn != null ? !lockAnn.excluded() : !isMappedBy; + final AnnotationUsage lockAnn = property.getAnnotationUsage( OptimisticLock.class ); + final boolean includeInOptimisticLockChecks = lockAnn != null ? !lockAnn.getBoolean( "excluded" ) : !isMappedBy; collection.setOptimisticLocked( includeInOptimisticLockChecks ); } @@ -1270,8 +1281,8 @@ public abstract class CollectionBinder { private void detectMappedByProblem(boolean isMappedBy) { if ( isMappedBy - && ( property.isAnnotationPresent( JoinColumn.class ) - || property.isAnnotationPresent( JoinColumns.class ) ) ) { + && ( property.hasAnnotationUsage( JoinColumn.class ) + || property.hasAnnotationUsage( JoinColumns.class ) ) ) { throw new AnnotationException( "Association '" + qualify( propertyHolder.getPath(), propertyName ) + "' is 'mappedBy' another entity and may not specify the '@JoinColumn'" ); @@ -1286,9 +1297,9 @@ public abstract class CollectionBinder { if ( !isMappedBy && oneToMany - && property.isAnnotationPresent( OnDelete.class ) - && !property.isAnnotationPresent( JoinColumn.class ) - && !property.isAnnotationPresent( JoinColumns.class )) { + && property.hasAnnotationUsage( OnDelete.class ) + && !property.hasAnnotationUsage( JoinColumn.class ) + && !property.hasAnnotationUsage( JoinColumns.class )) { throw new AnnotationException( "Unidirectional '@OneToMany' association '" + qualify( propertyHolder.getPath(), propertyName ) + "' is annotated '@OnDelete' and must explicitly specify a '@JoinColumn'" ); @@ -1305,12 +1316,12 @@ public abstract class CollectionBinder { collection.setOrphanDelete( true ); } binder.setLazy( collection.isLazy() ); - final LazyGroup lazyGroupAnnotation = property.getAnnotation( LazyGroup.class ); + final AnnotationUsage lazyGroupAnnotation = property.getAnnotationUsage( LazyGroup.class ); if ( lazyGroupAnnotation != null ) { - binder.setLazyGroup( lazyGroupAnnotation.value() ); + binder.setLazyGroup( lazyGroupAnnotation.getString( "value" ) ); } binder.setAccessType( accessType ); - binder.setProperty( property ); + binder.setMemberDetails( property ); binder.setInsertable( insertable ); binder.setUpdatable( updatable ); binder.setBuildingContext( buildingContext ); @@ -1320,7 +1331,7 @@ public abstract class CollectionBinder { if ( !declaringClassSet ) { throw new AssertionFailure( "DeclaringClass is not set in CollectionBinder while binding" ); } - propertyHolder.addProperty( prop, declaringClass ); + propertyHolder.addProperty( prop, property, declaringClass ); binder.callAttributeBindersInSecondPass( prop ); } @@ -1328,55 +1339,55 @@ public abstract class CollectionBinder { private void bindLoader() { //SQL overriding - final SQLInsert sqlInsert = property.getAnnotation( SQLInsert.class ); + final AnnotationUsage sqlInsert = property.getAnnotationUsage( SQLInsert.class ); if ( sqlInsert != null ) { collection.setCustomSQLInsert( - sqlInsert.sql().trim(), - sqlInsert.callable(), - fromResultCheckStyle( sqlInsert.check() ) + sqlInsert.getString( "sql" ).trim(), + sqlInsert.getBoolean( "callable" ), + fromResultCheckStyle( sqlInsert.getEnum( "check" ) ) ); if ( sqlInsert.verify() != Expectation.class ) { collection.setInsertExpectation( getDefaultSupplier( sqlInsert.verify() ) ); } } - final SQLUpdate sqlUpdate = property.getAnnotation( SQLUpdate.class ); + final AnnotationUsage sqlUpdate = property.getAnnotationUsage( SQLUpdate.class ); if ( sqlUpdate != null ) { collection.setCustomSQLUpdate( - sqlUpdate.sql().trim(), - sqlUpdate.callable(), - fromResultCheckStyle( sqlUpdate.check() ) + sqlUpdate.getString( "sql" ).trim(), + sqlUpdate.getBoolean( "callable" ), + fromResultCheckStyle( sqlUpdate.getEnum( "check" ) ) ); if ( sqlUpdate.verify() != Expectation.class ) { collection.setUpdateExpectation( getDefaultSupplier( sqlUpdate.verify() ) ); } } - final SQLDelete sqlDelete = property.getAnnotation( SQLDelete.class ); + final AnnotationUsage sqlDelete = property.getAnnotationUsage( SQLDelete.class ); if ( sqlDelete != null ) { collection.setCustomSQLDelete( - sqlDelete.sql().trim(), - sqlDelete.callable(), - fromResultCheckStyle( sqlDelete.check() ) + sqlDelete.getString( "sql" ).trim(), + sqlDelete.getBoolean( "callable" ), + fromResultCheckStyle( sqlDelete.getEnum( "check" ) ) ); if ( sqlDelete.verify() != Expectation.class ) { collection.setDeleteExpectation( getDefaultSupplier( sqlDelete.verify() ) ); } } - final SQLDeleteAll sqlDeleteAll = property.getAnnotation( SQLDeleteAll.class ); + final AnnotationUsage sqlDeleteAll = property.getAnnotationUsage( SQLDeleteAll.class ); if ( sqlDeleteAll != null ) { collection.setCustomSQLDeleteAll( - sqlDeleteAll.sql().trim(), - sqlDeleteAll.callable(), - fromResultCheckStyle( sqlDeleteAll.check() ) + sqlDeleteAll.getString( "sql" ).trim(), + sqlDeleteAll.getBoolean( "callable" ), + fromResultCheckStyle( sqlDeleteAll.getEnum( "check" ) ) ); if ( sqlDeleteAll.verify() != Expectation.class ) { collection.setDeleteAllExpectation( getDefaultSupplier( sqlDeleteAll.verify() ) ); } } - final SQLSelect sqlSelect = property.getAnnotation( SQLSelect.class ); + final AnnotationUsage sqlSelect = property.getAnnotationUsage( SQLSelect.class ); if ( sqlSelect != null ) { final String loaderName = collection.getRole() + "$SQLSelect"; collection.setLoaderName( loaderName ); @@ -1384,16 +1395,16 @@ public abstract class CollectionBinder { QueryBinder.bindNativeQuery( loaderName, sqlSelect, null, buildingContext ); } - final HQLSelect hqlSelect = property.getAnnotation( HQLSelect.class ); + final AnnotationUsage hqlSelect = property.getAnnotationUsage( HQLSelect.class ); if ( hqlSelect != null ) { final String loaderName = collection.getRole() + "$HQLSelect"; collection.setLoaderName( loaderName ); QueryBinder.bindQuery( loaderName, hqlSelect, buildingContext ); } - final Loader loader = property.getAnnotation( Loader.class ); + final AnnotationUsage loader = property.getAnnotationUsage( Loader.class ); if ( loader != null ) { - collection.setLoaderName( loader.namedQuery() ); + collection.setLoaderName( loader.getString( "namedQuery" ) ); } } @@ -1408,7 +1419,7 @@ public abstract class CollectionBinder { comparatorClass = null; } else if ( comparatorSort != null ) { - comparatorClass = comparatorSort.value(); + comparatorClass = comparatorSort.getClassDetails( "value" ).toJavaClass(); } else { comparatorClass = null; @@ -1421,10 +1432,10 @@ public abstract class CollectionBinder { if ( ordered ) { // we can only apply the sql-based order by up front. The jpa order by has to wait for second pass if ( sqlOrderBy != null ) { - collection.setOrderBy( sqlOrderBy.clause() ); + collection.setOrderBy( sqlOrderBy.getString( "clause" ) ); } if ( sqlOrder != null ) { - collection.setOrderBy( sqlOrder.value() ); + collection.setOrderBy( sqlOrder.getString( "value" ) ); } } @@ -1498,23 +1509,21 @@ public abstract class CollectionBinder { } private void handleFetchProfileOverrides() { - if ( property.isAnnotationPresent( FetchProfileOverride.class ) ) { - final FetchProfileOverride fetch = property.getAnnotation( FetchProfileOverride.class ); - buildingContext.getMetadataCollector() - .addSecondPass( new FetchSecondPass( fetch, propertyHolder, propertyName, buildingContext ) ); - } - else if ( property.isAnnotationPresent( FetchProfileOverrides.class ) ) { - for ( FetchProfileOverride fetch: property.getAnnotation( FetchProfileOverrides.class ).value() ) { - buildingContext.getMetadataCollector() - .addSecondPass( new FetchSecondPass( fetch, propertyHolder, propertyName, buildingContext ) ); - } - } + property.forEachAnnotationUsage( FetchProfileOverride.class, (usage) -> { + buildingContext.getMetadataCollector().addSecondPass( new FetchSecondPass( + usage, + propertyHolder, + propertyName, + buildingContext + ) ); + } ); } private void handleFetch() { - if ( property.isAnnotationPresent( Fetch.class ) ) { + final AnnotationUsage fetchAnnotation = property.getAnnotationUsage( Fetch.class ); + if ( fetchAnnotation != null ) { // Hibernate @Fetch annotation takes precedence - setHibernateFetchMode( property.getAnnotation( Fetch.class ).value() ); + setHibernateFetchMode( fetchAnnotation.getEnum( "value" ) ); } else { collection.setFetchMode( getFetchMode( getJpaFetchType() ) ); @@ -1523,34 +1532,37 @@ public abstract class CollectionBinder { private void setHibernateFetchMode(org.hibernate.annotations.FetchMode fetchMode) { switch ( fetchMode ) { - case JOIN: + case JOIN -> { collection.setFetchMode( FetchMode.JOIN ); collection.setLazy( false ); - break; - case SELECT: + } + case SELECT -> { collection.setFetchMode( FetchMode.SELECT ); - break; - case SUBSELECT: + } + case SUBSELECT -> { collection.setFetchMode( FetchMode.SELECT ); collection.setSubselectLoadable( true ); collection.getOwner().setSubselectLoadableCollections( true ); - break; - default: - throw new AssertionFailure( "unknown fetch type"); + } + default -> { + throw new AssertionFailure( "unknown fetch type" ); + } } } + @SuppressWarnings("deprecation") private void handleLazy() { final FetchType jpaFetchType = getJpaFetchType(); - if ( property.isAnnotationPresent( LazyCollection.class ) ) { - final LazyCollection lazy = property.getAnnotation( LazyCollection.class ); - boolean eager = lazy.value() == LazyCollectionOption.FALSE; + final AnnotationUsage lazyCollectionAnnotation = property.getAnnotationUsage( LazyCollection.class ); + if ( lazyCollectionAnnotation != null ) { + final LazyCollectionOption option = lazyCollectionAnnotation.getEnum( "value" ); + boolean eager = option == LazyCollectionOption.FALSE; if ( !eager && jpaFetchType == EAGER ) { throw new AnnotationException("Collection '" + safeCollectionRole() - + "' is marked 'fetch=EAGER' and '@LazyCollection(" + lazy.value() + ")'"); + + "' is marked 'fetch=EAGER' and '@LazyCollection(" + option + ")'"); } collection.setLazy( !eager ); - collection.setExtraLazy( lazy.value() == LazyCollectionOption.EXTRA ); + collection.setExtraLazy( option == LazyCollectionOption.EXTRA ); } else { collection.setLazy( jpaFetchType == LAZY ); @@ -1559,30 +1571,32 @@ public abstract class CollectionBinder { } private FetchType getJpaFetchType() { - final OneToMany oneToMany = property.getAnnotation( OneToMany.class ); - final ManyToMany manyToMany = property.getAnnotation( ManyToMany.class ); - final ElementCollection elementCollection = property.getAnnotation( ElementCollection.class ); - final ManyToAny manyToAny = property.getAnnotation( ManyToAny.class ); + final AnnotationUsage oneToMany = property.getAnnotationUsage( OneToMany.class ); + final AnnotationUsage manyToMany = property.getAnnotationUsage( ManyToMany.class ); + final AnnotationUsage elementCollection = property.getAnnotationUsage( ElementCollection.class ); + final AnnotationUsage manyToAny = property.getAnnotationUsage( ManyToAny.class ); if ( oneToMany != null ) { - return oneToMany.fetch(); + return oneToMany.getEnum( "fetch" ); } - else if ( manyToMany != null ) { - return manyToMany.fetch(); + + if ( manyToMany != null ) { + return manyToMany.getEnum( "fetch" ); } - else if ( elementCollection != null ) { - return elementCollection.fetch(); + + if ( elementCollection != null ) { + return elementCollection.getEnum( "fetch" ); } - else if ( manyToAny != null ) { + + if ( manyToAny != null ) { return LAZY; } - else { - throw new AssertionFailure( - "Define fetch strategy on a property not annotated with @ManyToOne nor @OneToMany nor @CollectionOfElements" - ); - } + + throw new AssertionFailure( + "Define fetch strategy on a property not annotated with @ManyToOne nor @OneToMany nor @CollectionOfElements" + ); } - XClass getElementType() { + TypeDetails getElementType() { if ( isDefault( targetEntity, buildingContext ) ) { if ( collectionElementType != null ) { return collectionElementType; @@ -1623,7 +1637,7 @@ public abstract class CollectionBinder { } private boolean isReversePropertyInJoin( - XClass elementType, + TypeDetails elementType, PersistentClass persistentClass, Map persistentClasses) { if ( persistentClass != null && isUnownedCollection() ) { @@ -1742,7 +1756,7 @@ public abstract class CollectionBinder { private void handleJpaOrderBy(Collection collection, PersistentClass associatedClass) { if ( jpaOrderBy != null ) { - final String orderByFragment = buildOrderByClauseFromHql( jpaOrderBy.value(), associatedClass ); + final String orderByFragment = buildOrderByClauseFromHql( jpaOrderBy.getString( "value" ), associatedClass ); if ( isNotEmpty( orderByFragment ) ) { collection.setOrderBy( orderByFragment ); } @@ -1750,11 +1764,13 @@ public abstract class CollectionBinder { } private void bindSynchronize() { - if ( property.isAnnotationPresent( Synchronize.class ) ) { + final AnnotationUsage synchronizeAnnotation = property.getAnnotationUsage( Synchronize.class ); + if ( synchronizeAnnotation != null ) { final JdbcEnvironment jdbcEnvironment = buildingContext.getMetadataCollector().getDatabase().getJdbcEnvironment(); - final Synchronize synchronize = property.getAnnotation(Synchronize.class); - for ( String table : synchronize.value() ) { - String physicalName = synchronize.logical() ? toPhysicalName( jdbcEnvironment, table ) : table; + for ( String table : synchronizeAnnotation.getList( "value" ) ) { + String physicalName = synchronizeAnnotation.getBoolean( "logical" ) + ? toPhysicalName( jdbcEnvironment, table ) + : table; collection.addSynchronizedTable( physicalName ); } } @@ -1770,48 +1786,49 @@ public abstract class CollectionBinder { } private void bindFilters(boolean hasAssociationTable) { - final Filter simpleFilter = property.getAnnotation( Filter.class ); - //set filtering - //test incompatible choices - //if ( StringHelper.isNotEmpty( where ) ) collection.setWhere( where ); - if ( simpleFilter != null ) { - addFilter( hasAssociationTable, simpleFilter ); - } - final Filters filters = getOverridableAnnotation( property, Filters.class, buildingContext ); - if ( filters != null ) { - for ( Filter filter : filters.value() ) { - addFilter( hasAssociationTable, filter ); - } - } - final FilterJoinTable simpleFilterJoinTable = property.getAnnotation( FilterJoinTable.class ); - if ( simpleFilterJoinTable != null ) { - addFilter( hasAssociationTable, simpleFilterJoinTable ); - } - final FilterJoinTables filterJoinTables = property.getAnnotation( FilterJoinTables.class ); - if ( filterJoinTables != null ) { - for ( FilterJoinTable filter : filterJoinTables.value() ) { - addFilter( hasAssociationTable, filter ); - } - } + property.forEachAnnotationUsage( Filter.class, (usage) -> { + addFilter( hasAssociationTable, usage ); + } ); + + property.forEachAnnotationUsage( FilterJoinTable.class, (usage) -> { + addFilterJoinTable( hasAssociationTable, usage ); + } ); } - private void addFilter(boolean hasAssociationTable, Filter filter) { + private void addFilter(boolean hasAssociationTable, AnnotationUsage filterAnnotation) { + final Map aliasTableMap = new HashMap<>(); + final Map aliasEntityMap = new HashMap<>(); + final List> aliasAnnotations = filterAnnotation.getList( "aliases" ); + for ( AnnotationUsage aliasAnnotation : aliasAnnotations ) { + final String alias = aliasAnnotation.getString( "alias" ); + + final String table = aliasAnnotation.getString( "table" ); + if ( isNotEmpty( table ) ) { + aliasTableMap.put( alias, table ); + } + + final ClassDetails entityClassDetails = aliasAnnotation.getClassDetails( "entity" ); + if ( entityClassDetails != ClassDetails.VOID_CLASS_DETAILS ) { + aliasEntityMap.put( alias, entityClassDetails.getName() ); + } + } + if ( hasAssociationTable ) { collection.addManyToManyFilter( - filter.name(), - getFilterCondition( filter ), - filter.deduceAliasInjectionPoints(), - toAliasTableMap( filter.aliases() ), - toAliasEntityMap( filter.aliases() ) + filterAnnotation.getString( "name" ), + getFilterCondition( filterAnnotation ), + filterAnnotation.getBoolean( "deduceAliasInjectionPoints" ), + aliasTableMap, + aliasEntityMap ); } else { collection.addFilter( - filter.name(), - getFilterCondition( filter ), - filter.deduceAliasInjectionPoints(), - toAliasTableMap( filter.aliases() ), - toAliasEntityMap( filter.aliases() ) + filterAnnotation.getString( "name" ), + getFilterCondition( filterAnnotation ), + filterAnnotation.getBoolean( "deduceAliasInjectionPoints" ), + aliasTableMap, + aliasEntityMap ); } } @@ -1849,12 +1866,12 @@ public abstract class CollectionBinder { } private String getWhereJoinTableClause() { - final SQLJoinTableRestriction joinTableRestriction = property.getAnnotation( SQLJoinTableRestriction.class ); + final AnnotationUsage joinTableRestriction = property.getAnnotationUsage( SQLJoinTableRestriction.class ); if ( joinTableRestriction != null ) { - return joinTableRestriction.value(); + return joinTableRestriction.getString( "value" ); } - final WhereJoinTable whereJoinTable = property.getAnnotation( WhereJoinTable.class ); - return whereJoinTable == null ? null : whereJoinTable.clause(); + final AnnotationUsage whereJoinTable = property.getAnnotationUsage( WhereJoinTable.class ); + return whereJoinTable == null ? null : whereJoinTable.getString( "clause" ); } private String getWhereClause() { @@ -1868,27 +1885,33 @@ public abstract class CollectionBinder { } private String getWhereOnCollectionClause() { - final SQLRestriction restrictionOnCollection = getOverridableAnnotation( property, SQLRestriction.class, getBuildingContext() ); + final AnnotationUsage restrictionOnCollection = getOverridableAnnotation( property, SQLRestriction.class, getBuildingContext() ); if ( restrictionOnCollection != null ) { - return restrictionOnCollection.value(); + return restrictionOnCollection.getString( "value" ); } - final Where whereOnCollection = getOverridableAnnotation( property, Where.class, buildingContext ); + + final AnnotationUsage whereOnCollection = getOverridableAnnotation( property, Where.class, buildingContext ); if ( whereOnCollection != null ) { - return whereOnCollection.clause(); + return whereOnCollection.getString( "clause" ); } + return null; } private String getWhereOnClassClause() { - XClass elementClass = property.getElementClass(); - if ( elementClass != null && useEntityWhereClauseForCollections( buildingContext ) ) { - final SQLRestriction restrictionOnClass = getOverridableAnnotation( elementClass, SQLRestriction.class, buildingContext ); + final TypeDetails elementType = property.getElementType(); + if ( elementType != null && useEntityWhereClauseForCollections( buildingContext ) ) { + final AnnotationUsage restrictionOnClass = getOverridableAnnotation( + property.getAssociatedType().determineRawClass(), + SQLRestriction.class, + buildingContext + ); if ( restrictionOnClass != null ) { - return restrictionOnClass.value(); + return restrictionOnClass.getString( "value" ); } - final Where whereOnClass = getOverridableAnnotation( elementClass, Where.class, buildingContext ); + final AnnotationUsage whereOnClass = getOverridableAnnotation( property, Where.class, buildingContext ); if ( whereOnClass != null ) { - return whereOnClass.clause(); + return whereOnClass.getString( "clause" ); } return null; } @@ -1897,14 +1920,31 @@ public abstract class CollectionBinder { } } - private void addFilter(boolean hasAssociationTable, FilterJoinTable filter) { + private void addFilterJoinTable(boolean hasAssociationTable, AnnotationUsage filter) { if ( hasAssociationTable ) { + final Map aliasTableMap = new HashMap<>(); + final Map aliasEntityMap = new HashMap<>(); + final List> aliasAnnotations = filter.getList( "aliases" ); + for ( AnnotationUsage aliasAnnotation : aliasAnnotations ) { + final String alias = aliasAnnotation.getString( "alias" ); + + final String table = aliasAnnotation.getString( "table" ); + if ( isNotEmpty( table ) ) { + aliasTableMap.put( alias, table ); + } + + final ClassDetails entityClassDetails = aliasAnnotation.getClassDetails( "entity" ); + if ( entityClassDetails != ClassDetails.VOID_CLASS_DETAILS ) { + aliasEntityMap.put( alias, entityClassDetails.getName() ); + } + } + collection.addFilter( - filter.name(), + filter.getString( "name" ), getFilterConditionForJoinTable( filter ), - filter.deduceAliasInjectionPoints(), - toAliasTableMap( filter.aliases() ), - toAliasEntityMap( filter.aliases() ) + filter.getBoolean( "deduceAliasInjectionPoints" ), + aliasTableMap, + aliasEntityMap ); } else { @@ -1913,37 +1953,41 @@ public abstract class CollectionBinder { } } - private String getFilterConditionForJoinTable(FilterJoinTable filter) { - final String condition = filter.condition(); - return condition.isEmpty() ? getDefaultFilterCondition( filter.name(), filter ) : condition; + private String getFilterConditionForJoinTable(AnnotationUsage filterJoinTableAnnotation) { + final String condition = filterJoinTableAnnotation.getString( "condition" ); + return condition.isEmpty() + ? getDefaultFilterCondition( filterJoinTableAnnotation.getString( "name" ), filterJoinTableAnnotation ) + : condition; } - private String getFilterCondition(Filter filter) { - final String condition = filter.condition(); - return condition.isEmpty() ? getDefaultFilterCondition( filter.name(), filter ) : condition; + private String getFilterCondition(AnnotationUsage filter) { + final String condition = filter.getString( "condition" ); + return condition.isEmpty() + ? getDefaultFilterCondition( filter.getString( "name" ), filter ) + : condition; } - private String getDefaultFilterCondition(String name, Annotation annotation) { + private String getDefaultFilterCondition(String name, AnnotationUsage annotation) { final FilterDefinition definition = buildingContext.getMetadataCollector().getFilterDefinition( name ); if ( definition == null ) { throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName ) - + "' has a '@" + annotation.annotationType().getSimpleName() + + "' has a '@" + annotation.getAnnotationType().getSimpleName() + "' for an undefined filter named '" + name + "'" ); } final String defaultCondition = definition.getDefaultFilterCondition(); if ( isEmpty( defaultCondition ) ) { throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName ) + - "' has a '@" + annotation.annotationType().getSimpleName() + "' has a '@" + annotation.getAnnotationType().getSimpleName() + "' with no 'condition' and no default condition was given by the '@FilterDef' named '" + name + "'" ); } return defaultCondition; } - public void setCache(Cache cache) { + public void setCache(AnnotationUsage cache) { if ( cache != null ) { - cacheRegionName = nullIfEmpty(cache.region()); - cacheConcurrencyStrategy = EntityBinder.getCacheConcurrencyStrategy( cache.usage() ); + cacheRegionName = nullIfEmpty( cache.getString( "region" )); + cacheConcurrencyStrategy = EntityBinder.getCacheConcurrencyStrategy( cache.getEnum( "usage" ) ); } else { cacheConcurrencyStrategy = null; @@ -1951,8 +1995,8 @@ public abstract class CollectionBinder { } } - public void setQueryCacheLayout(QueryCacheLayout queryCacheLayout) { - this.queryCacheLayout = queryCacheLayout == null ? null : queryCacheLayout.layout(); + public void setQueryCacheLayout(AnnotationUsage queryCacheLayout) { + this.queryCacheLayout = queryCacheLayout == null ? null : queryCacheLayout.getEnum( "layout" ); } public void setOneToMany(boolean oneToMany) { @@ -1963,10 +2007,10 @@ public abstract class CollectionBinder { this.indexColumn = indexColumn; } - public void setMapKey(MapKey key) { + public void setMapKey(AnnotationUsage key) { hasMapKeyProperty = key != null; if ( hasMapKeyProperty ) { - mapKeyPropertyName = nullIfEmpty( key.name() ); + mapKeyPropertyName = nullIfEmpty( key.getString( "name" ) ); } } @@ -2047,45 +2091,50 @@ public abstract class CollectionBinder { collection.setKey( key ); if ( property != null ) { - final org.hibernate.annotations.ForeignKey fk = property.getAnnotation( org.hibernate.annotations.ForeignKey.class ); - if ( fk != null && !fk.name().isEmpty() ) { - key.setForeignKeyName( fk.name() ); + final AnnotationUsage fk = property.getAnnotationUsage( org.hibernate.annotations.ForeignKey.class ); + if ( fk != null && !fk.getString( "name" ).isEmpty() ) { + key.setForeignKeyName( fk.getString( "name" ) ); } else { - final CollectionTable collectionTableAnn = property.getAnnotation( CollectionTable.class ); + final AnnotationUsage collectionTableAnn = property.getAnnotationUsage( CollectionTable.class ); if ( collectionTableAnn != null ) { - final ForeignKey foreignKey = collectionTableAnn.foreignKey(); - if ( foreignKey.value() == NO_CONSTRAINT - || foreignKey.value() == PROVIDER_DEFAULT && noConstraintByDefault ) { + final AnnotationUsage foreignKey = collectionTableAnn.getNestedUsage( "foreignKey" ); + final ConstraintMode constraintMode = foreignKey.getEnum( "value" ); + if ( constraintMode == NO_CONSTRAINT + || constraintMode == PROVIDER_DEFAULT && noConstraintByDefault ) { key.disableForeignKey(); } else { - key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) ); + key.setForeignKeyName( nullIfEmpty( foreignKey.getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( foreignKey.getString( "foreignKeyDefinition" ) ) ); if ( key.getForeignKeyName() == null && key.getForeignKeyDefinition() == null - && collectionTableAnn.joinColumns().length == 1 ) { - final JoinColumn joinColumn = collectionTableAnn.joinColumns()[0]; - key.setForeignKeyName( nullIfEmpty( joinColumn.foreignKey().name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) ); + && collectionTableAnn.getList( "joinColumns" ).size() == 1 ) { + //noinspection unchecked + final AnnotationUsage joinColumn = (AnnotationUsage) collectionTableAnn.getList( "joinColumns" ).get( 0 ); + final AnnotationUsage nestedForeignKey = joinColumn.getNestedUsage( "foreignKey" ); + key.setForeignKeyName( nullIfEmpty( nestedForeignKey.getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( nestedForeignKey.getString( "foreignKeyDefinition" ) ) ); } } } else { - final JoinTable joinTableAnn = property.getAnnotation( JoinTable.class ); + final AnnotationUsage joinTableAnn = property.getAnnotationUsage( JoinTable.class ); if ( joinTableAnn != null ) { - final ForeignKey foreignKey = joinTableAnn.foreignKey(); - String foreignKeyName = foreignKey.name(); - String foreignKeyDefinition = foreignKey.foreignKeyDefinition(); - ConstraintMode foreignKeyValue = foreignKey.value(); - if ( joinTableAnn.joinColumns().length > 0 ) { - final JoinColumn joinColumnAnn = joinTableAnn.joinColumns()[0]; + final AnnotationUsage foreignKey = joinTableAnn.getNestedUsage( "foreignKey" ); + String foreignKeyName = foreignKey.getString( "name" ); + String foreignKeyDefinition = foreignKey.getString( "foreignKeyDefinition" ); + ConstraintMode foreignKeyValue = foreignKey.getEnum( "value" ); + List> joinColumnAnnotations = joinTableAnn.getList( "joinColumns" ); + if ( !joinColumnAnnotations.isEmpty() ) { + final AnnotationUsage joinColumnAnn = joinColumnAnnotations.get( 0 ); + final AnnotationUsage joinColumnForeignKey = joinColumnAnn.getNestedUsage( "foreignKey" ); if ( foreignKeyName.isEmpty() ) { - foreignKeyName = joinColumnAnn.foreignKey().name(); - foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition(); + foreignKeyName = joinColumnForeignKey.getString( "name" ); + foreignKeyDefinition = joinColumnForeignKey.getString( "foreignKeyDefinition" ); } if ( foreignKeyValue != NO_CONSTRAINT ) { - foreignKeyValue = joinColumnAnn.foreignKey().value(); + foreignKeyValue = joinColumnForeignKey.getEnum( "value" ); } } if ( foreignKeyValue == NO_CONSTRAINT @@ -2099,24 +2148,24 @@ public abstract class CollectionBinder { } else { final String propertyPath = qualify( propertyHolder.getPath(), property.getName() ); - final ForeignKey foreignKey = propertyHolder.getOverriddenForeignKey( propertyPath ); + final AnnotationUsage foreignKey = propertyHolder.getOverriddenForeignKey( propertyPath ); if ( foreignKey != null ) { handleForeignKeyConstraint( noConstraintByDefault, key, foreignKey ); } else { - final OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class ); - final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class ); + final AnnotationUsage oneToManyAnn = property.getAnnotationUsage( OneToMany.class ); + final AnnotationUsage onDeleteAnn = property.getAnnotationUsage( OnDelete.class ); if ( oneToManyAnn != null - && !oneToManyAnn.mappedBy().isEmpty() - && ( onDeleteAnn == null || onDeleteAnn.action() != OnDeleteAction.CASCADE ) ) { + && !oneToManyAnn.getString( "mappedBy" ).isEmpty() + && ( onDeleteAnn == null || onDeleteAnn.getEnum( "action" ) != OnDeleteAction.CASCADE ) ) { // foreign key should be up to @ManyToOne side // @OnDelete generate "on delete cascade" foreign key key.disableForeignKey(); } else { - final JoinColumn joinColumnAnn = property.getAnnotation( JoinColumn.class ); + final AnnotationUsage joinColumnAnn = property.getSingleAnnotationUsage( JoinColumn.class ); if ( joinColumnAnn != null ) { - handleForeignKeyConstraint( noConstraintByDefault, key, joinColumnAnn.foreignKey() ); + handleForeignKeyConstraint( noConstraintByDefault, key, joinColumnAnn.getNestedUsage( "foreignKey" ) ); } } } @@ -2128,15 +2177,18 @@ public abstract class CollectionBinder { return key; } - private static void handleForeignKeyConstraint(boolean noConstraintByDefault, DependantValue key, ForeignKey foreignKey) { - final ConstraintMode constraintMode = foreignKey.value(); + private static void handleForeignKeyConstraint( + boolean noConstraintByDefault, + DependantValue key, + AnnotationUsage foreignKey) { + final ConstraintMode constraintMode = foreignKey.getEnum( "value" ); if ( constraintMode == NO_CONSTRAINT || constraintMode == PROVIDER_DEFAULT && noConstraintByDefault) { key.disableForeignKey(); } else { - key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) ); + key.setForeignKeyName( nullIfEmpty( foreignKey.getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( foreignKey.getString( "foreignKeyDefinition" ) ) ); } } @@ -2162,12 +2214,12 @@ public abstract class CollectionBinder { throw new AssertionFailure( "null was passed for argument property" ); } - final XClass elementType = getElementType(); + final TypeDetails elementType = getElementType(); final PersistentClass targetEntity = persistentClasses.get( elementType.getName() ); //null if this is an @ElementCollection final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy ); final boolean isCollectionOfEntities = targetEntity != null; - final boolean isManyToAny = property.isAnnotationPresent( ManyToAny.class ); + final boolean isManyToAny = property.hasAnnotationUsage( ManyToAny.class ); logManyToManySecondPass( oneToMany, isCollectionOfEntities, isManyToAny ); @@ -2202,13 +2254,15 @@ public abstract class CollectionBinder { checkConsistentColumnMutability( collection ); } - private void handleElementCollection(XClass elementType, String hqlOrderBy) { + private void handleElementCollection(TypeDetails elementType, String hqlOrderBy) { // 'propertyHolder' is the PropertyHolder for the owner of the collection // 'holder' is the CollectionPropertyHolder. // 'property' is the collection XProperty - final XClass elementClass = isPrimitive( elementType.getName() ) ? null : elementType; - final AnnotatedClassType classType = annotatedElementType( isEmbedded, property, elementType ); + final ClassDetails elementClass = isPrimitive( elementType.getName() ) + ? null + : elementType.determineRawClass(); + final AnnotatedClassType classType = annotatedElementType( isEmbedded, property, elementClass ); final boolean primitive = classType == NONE; if ( !primitive ) { propertyHolder.startingProperty( property ); @@ -2223,13 +2277,12 @@ public abstract class CollectionBinder { buildingContext ); - final Class> compositeUserType = - resolveCompositeUserType( property, elementClass, buildingContext ); + final Class> compositeUserType = resolveCompositeUserType( property, elementClass, buildingContext ); boolean isComposite = classType == EMBEDDABLE || compositeUserType != null; holder.prepare( property, isComposite ); if ( isComposite ) { - handleCompositeCollectionElement( hqlOrderBy, elementClass, holder, compositeUserType ); + handleCompositeCollectionElement( hqlOrderBy, elementType, elementClass, holder, compositeUserType ); } else { handleCollectionElement( elementType, hqlOrderBy, elementClass, holder ); @@ -2237,9 +2290,9 @@ public abstract class CollectionBinder { } private void handleCollectionElement( - XClass elementType, + TypeDetails elementType, String hqlOrderBy, - XClass elementClass, + ClassDetails elementClass, CollectionPropertyHolder holder) { final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext ); @@ -2254,7 +2307,7 @@ public abstract class CollectionBinder { elementBinder.setColumns( actualColumns ); elementBinder.setType( property, - elementClass, + elementType, collection.getOwnerEntityName(), holder.resolveElementAttributeConverterDescriptor( property, elementClass ) ); @@ -2269,7 +2322,8 @@ public abstract class CollectionBinder { private void handleCompositeCollectionElement( String hqlOrderBy, - XClass elementClass, + TypeDetails elementType, + ClassDetails elementClass, CollectionPropertyHolder holder, Class> compositeUserType) { //TODO be smart with isNullable @@ -2283,14 +2337,14 @@ public abstract class CollectionBinder { entityBinder.setPropertyAccessType( accessType ); final Component component = fillEmbeddable( holder, - getSpecialMembers( elementClass ), + getSpecialMembers( elementType ), accessType, true, entityBinder, false, false, true, - resolveCustomInstantiator( property, elementClass, buildingContext ), + resolveCustomInstantiator( property, elementType, buildingContext ), compositeUserType, null, buildingContext, @@ -2305,47 +2359,48 @@ public abstract class CollectionBinder { } } - static AccessType accessType(XProperty property, PersistentClass owner) { - final Access accessAnn = property.getAnnotation( Access.class ); + static AccessType accessType(MemberDetails property, PersistentClass owner) { + final AnnotationUsage accessAnn = property.getAnnotationUsage( Access.class ); if ( accessAnn != null ) { // the attribute is locally annotated with `@Access`, use that - return accessAnn.value() == PROPERTY + return accessAnn.getEnum( "value" ) == PROPERTY ? AccessType.PROPERTY : AccessType.FIELD; } - else if ( owner.getIdentifierProperty() != null ) { + + if ( owner.getIdentifierProperty() != null ) { // use the access for the owning entity's id attribute, if one return owner.getIdentifierProperty().getPropertyAccessorName().equals( "property" ) ? AccessType.PROPERTY : AccessType.FIELD; } - else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) { + + if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) { // use the access for the owning entity's "id mapper", if one return owner.getIdentifierMapper().getProperties().get(0).getPropertyAccessorName().equals( "property" ) ? AccessType.PROPERTY : AccessType.FIELD; } - else { - // otherwise... - throw new AssertionFailure( "Unable to guess collection property accessor name" ); - } + + // otherwise... + throw new AssertionFailure( "Unable to guess collection property accessor name" ); } private AnnotatedClassType annotatedElementType( boolean isEmbedded, - XProperty property, - XClass elementType) { - if ( isPrimitive( elementType.getName() ) ) { + MemberDetails property, + ClassDetails elementClass) { + if ( isPrimitive( elementClass.getName() ) ) { return NONE; } else { //force in case of attribute override - final boolean attributeOverride = property.isAnnotationPresent( AttributeOverride.class ) - || property.isAnnotationPresent( AttributeOverrides.class ); + final boolean attributeOverride = property.hasAnnotationUsage( AttributeOverride.class ) + || property.hasAnnotationUsage( AttributeOverrides.class ); // todo : force in the case of Convert annotation(s) with embedded paths (beyond key/value prefixes)? return isEmbedded || attributeOverride ? EMBEDDABLE - : buildingContext.getMetadataCollector().getClassType( elementType ); + : buildingContext.getMetadataCollector().getClassType( elementClass ); } } @@ -2376,7 +2431,10 @@ public abstract class CollectionBinder { return elementColumns; } - private ManyToOne handleCollectionOfEntities(XClass elementType, PersistentClass collectionEntity, String hqlOrderBy) { + private ManyToOne handleCollectionOfEntities( + TypeDetails elementType, + PersistentClass collectionEntity, + String hqlOrderBy) { final ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() ); collection.setElement( element ); element.setReferencedEntityName( elementType.getName() ); @@ -2391,23 +2449,28 @@ public abstract class CollectionBinder { collection.setManyToManyOrdering( buildOrderByClauseFromHql( hqlOrderBy, collectionEntity ) ); } - final org.hibernate.annotations.ForeignKey fk = property.getAnnotation( org.hibernate.annotations.ForeignKey.class ); - if ( fk != null && !fk.name().isEmpty() ) { - element.setForeignKeyName( fk.name() ); + final AnnotationUsage fk = property.getAnnotationUsage( org.hibernate.annotations.ForeignKey.class ); + if ( fk != null && !fk.getString( "name" ).isEmpty() ) { + element.setForeignKeyName( fk.getString( "name" ) ); } else { - final JoinTable joinTableAnn = property.getAnnotation( JoinTable.class ); + final AnnotationUsage joinTableAnn = property.getAnnotationUsage( JoinTable.class ); if ( joinTableAnn != null ) { - String foreignKeyName = joinTableAnn.inverseForeignKey().name(); - String foreignKeyDefinition = joinTableAnn.inverseForeignKey().foreignKeyDefinition(); - if ( joinTableAnn.inverseJoinColumns().length != 0 ) { - final JoinColumn joinColumnAnn = joinTableAnn.inverseJoinColumns()[0]; + final AnnotationUsage inverseForeignKey = joinTableAnn.getNestedUsage( "inverseForeignKey" ); + String foreignKeyName = inverseForeignKey.getString( "name" ); + String foreignKeyDefinition = inverseForeignKey.getString( "foreignKeyDefinition" ); + + final List> inverseJoinColumns = joinTableAnn.getList( "inverseJoinColumns" ); + if ( !inverseJoinColumns.isEmpty() ) { + final AnnotationUsage joinColumnAnn = inverseJoinColumns.get( 0); if ( foreignKeyName.isEmpty() ) { - foreignKeyName = joinColumnAnn.foreignKey().name(); - foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition(); + final AnnotationUsage inverseJoinColumnForeignKey = joinColumnAnn.getNestedUsage( "foreignKey" ); + foreignKeyName = inverseJoinColumnForeignKey.getString( "name" ); + foreignKeyDefinition = inverseJoinColumnForeignKey.getString( "foreignKeyDefinition" ); } } - final ConstraintMode constraintMode = joinTableAnn.inverseForeignKey().value(); + + final ConstraintMode constraintMode = inverseForeignKey.getEnum( "value" ); if ( constraintMode == NO_CONSTRAINT || constraintMode == PROVIDER_DEFAULT && buildingContext.getBuildingOptions().isNoConstraintByDefault() ) { @@ -2429,24 +2492,24 @@ public abstract class CollectionBinder { null, property, "unsupported", - buildingContext.getBootstrapContext().getReflectionManager() + buildingContext ); - final XProperty prop = inferredData.getProperty(); - final jakarta.persistence.Column discriminatorColumnAnn = prop.getAnnotation( jakarta.persistence.Column.class ); - final Formula discriminatorFormulaAnn = getOverridableAnnotation( prop, Formula.class, buildingContext); + final MemberDetails prop = inferredData.getAttributeMember(); + final AnnotationUsage discriminatorColumnAnn = prop.getAnnotationUsage( jakarta.persistence.Column.class ); + final AnnotationUsage discriminatorFormulaAnn = getOverridableAnnotation( prop, Formula.class, buildingContext ); //override the table inverseJoinColumns.setTable( collection.getCollectionTable() ); - final ManyToAny anyAnn = property.getAnnotation( ManyToAny.class ); + final AnnotationUsage anyAnn = property.getAnnotationUsage( ManyToAny.class ); final Any any = buildAnyValue( discriminatorColumnAnn, discriminatorFormulaAnn, inverseJoinColumns, inferredData, onDeleteAction, - anyAnn.fetch() == LAZY, + anyAnn.getEnum( "fetch" ) == LAZY, Nullability.NO_CONSTRAINT, propertyHolder, new EntityBinder(), @@ -2456,7 +2519,7 @@ public abstract class CollectionBinder { collection.setElement( any ); } - private PropertyData getSpecialMembers(XClass elementClass) { + private PropertyData getSpecialMembers(TypeDetails elementClass) { if ( isMap() ) { //"value" is the JPA 2 prefix for map values (used to be "element") if ( isHibernateExtensionMapping() ) { @@ -2502,7 +2565,7 @@ public abstract class CollectionBinder { ); } tableBinder.setJPA2ElementCollection( - !isCollectionOfEntities && property.isAnnotationPresent( ElementCollection.class ) + !isCollectionOfEntities && property.hasAnnotationUsage( ElementCollection.class ) ); final Table collectionTable = tableBinder.bind(); collection.setCollectionTable( collectionTable ); @@ -2511,23 +2574,14 @@ public abstract class CollectionBinder { } private void handleCheckConstraints(Table collectionTable) { - if ( property.isAnnotationPresent( Checks.class ) ) { - // if there are multiple annotations, they're not overrideable - for ( Check check : property.getAnnotation( Checks.class ).value() ) { - addCheckToCollection( collectionTable, check ); - } - } - else { - final Check check = getOverridableAnnotation( property, Check.class, buildingContext ); - if ( check != null ) { - addCheckToCollection( collectionTable, check ); - } - } + property.forEachAnnotationUsage( Check.class, (usage) -> { + addCheckToCollection( collectionTable, usage ); + } ); } - private static void addCheckToCollection(Table collectionTable, Check check) { - final String name = check.name(); - final String constraint = check.constraints(); + private static void addCheckToCollection(Table collectionTable, AnnotationUsage check) { + final String name = check.getString( "name" ); + final String constraint = check.getString( "constraints" ); collectionTable.addCheck( name.isEmpty() ? new CheckConstraint( constraint ) : new CheckConstraint( name, constraint ) ); @@ -2536,7 +2590,7 @@ public abstract class CollectionBinder { private void processSoftDeletes() { assert collection.getCollectionTable() != null; - final SoftDelete softDelete = extractSoftDelete( property, propertyHolder, buildingContext ); + final AnnotationUsage softDelete = extractSoftDelete( property, propertyHolder, buildingContext ); if ( softDelete == null ) { return; } @@ -2549,20 +2603,26 @@ public abstract class CollectionBinder { ); } - private static SoftDelete extractSoftDelete(XProperty property, PropertyHolder propertyHolder, MetadataBuildingContext context) { - final SoftDelete fromProperty = property.getAnnotation( SoftDelete.class ); + private static AnnotationUsage extractSoftDelete( + MemberDetails property, + PropertyHolder propertyHolder, + MetadataBuildingContext context) { + final AnnotationUsage fromProperty = property.getAnnotationUsage( SoftDelete.class ); if ( fromProperty != null ) { return fromProperty; } - return extractFromPackage( SoftDelete.class, property.getDeclaringClass(), context ); + return extractFromPackage( + SoftDelete.class, + property.getDeclaringType(), + context + ); } private void handleUnownedManyToMany( - XClass elementType, + TypeDetails elementType, PersistentClass collectionEntity, boolean isCollectionOfEntities) { - if ( !isCollectionOfEntities) { throw new AnnotationException( "Association '" + safeCollectionRole() + "'" + targetEntityMessage( elementType ) ); @@ -2588,20 +2648,20 @@ public abstract class CollectionBinder { collection.setCollectionTable( table ); processSoftDeletes(); - if ( property.isAnnotationPresent( Checks.class ) - || property.isAnnotationPresent( Check.class ) ) { + if ( property.hasAnnotationUsage( Checks.class ) + || property.hasAnnotationUsage( Check.class ) ) { throw new AnnotationException( "Association '" + safeCollectionRole() + " is an unowned collection and may not be annotated '@Check'" ); } } private void detectManyToManyProblems( - XClass elementType, + TypeDetails elementType, boolean isCollectionOfEntities, boolean isManyToAny) { if ( !isCollectionOfEntities) { - if ( property.isAnnotationPresent( ManyToMany.class ) || property.isAnnotationPresent( OneToMany.class ) ) { + if ( property.hasAnnotationUsage( ManyToMany.class ) || property.hasAnnotationUsage( OneToMany.class ) ) { throw new AnnotationException( "Association '" + safeCollectionRole() + "'" + targetEntityMessage( elementType ) ); } @@ -2612,8 +2672,8 @@ public abstract class CollectionBinder { } } else { - final JoinTable joinTableAnn = propertyHolder.getJoinTable( property ); - if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0 ) { + final AnnotationUsage joinTableAnn = propertyHolder.getJoinTable( property ); + if ( joinTableAnn != null && !joinTableAnn.getList( "inverseJoinColumns" ).isEmpty() ) { throw new AnnotationException( "Association '" + safeCollectionRole() + " has a '@JoinTable' with 'inverseJoinColumns' and" + targetEntityMessage( elementType ) ); @@ -2622,30 +2682,31 @@ public abstract class CollectionBinder { } } - static String targetEntityMessage(XClass elementType) { - final String problem = elementType.isAnnotationPresent( Entity.class ) + static String targetEntityMessage(TypeDetails elementType) { + final String problem = elementType.determineRawClass().hasAnnotationUsage( Entity.class ) ? " which does not belong to the same persistence unit" : " which is not an '@Entity' type"; return " targets the type '" + elementType.getName() + "'" + problem; } private Class resolveCustomInstantiator( - XProperty property, - XClass propertyClass, + MemberDetails property, + TypeDetails propertyClass, MetadataBuildingContext context) { - final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation - = property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final AnnotationUsage propertyAnnotation + = property.getAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( propertyAnnotation != null ) { - return propertyAnnotation.value(); + return propertyAnnotation.getClassDetails( "value" ).toJavaClass(); } - final org.hibernate.annotations.EmbeddableInstantiator classAnnotation - = propertyClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final ClassDetails rawPropertyClassDetails = propertyClass.determineRawClass(); + final AnnotationUsage classAnnotation + = rawPropertyClassDetails.getAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( classAnnotation != null ) { - return classAnnotation.value(); + return classAnnotation.getClassDetails( "value" ).toJavaClass(); } - final Class embeddableClass = context.getBootstrapContext().getReflectionManager().toClass( propertyClass ); + final Class embeddableClass = rawPropertyClassDetails.toJavaClass(); if ( embeddableClass != null ) { return context.getMetadataCollector().findRegisteredEmbeddableInstantiator( embeddableClass ); } @@ -2654,30 +2715,32 @@ public abstract class CollectionBinder { } private static Class> resolveCompositeUserType( - XProperty property, - XClass returnedClass, + MemberDetails property, + ClassDetails returnedClass, MetadataBuildingContext context) { - final CompositeType compositeType = property.getAnnotation( CompositeType.class ); + final AnnotationUsage compositeType = property.getAnnotationUsage( CompositeType.class ); if ( compositeType != null ) { - return compositeType.value(); + return compositeType.getClassDetails( "value" ).toJavaClass(); } - else if ( returnedClass != null ) { - final Class embeddableClass = context.getBootstrapContext().getReflectionManager() - .toClass( returnedClass ); - return embeddableClass == null ? null + + if ( returnedClass != null ) { + final Class embeddableClass = returnedClass.toJavaClass(); + return embeddableClass == null + ? null : context.getMetadataCollector().findRegisteredCompositeUserType( embeddableClass ); } - else { - return null; - } + + return null; } - private String extractHqlOrderBy(OrderBy jpaOrderBy) { + private String extractHqlOrderBy(AnnotationUsage jpaOrderBy) { if ( jpaOrderBy != null ) { - return jpaOrderBy.value(); // Null not possible. In case of empty expression, apply default ordering. + // Null not possible. In case of empty expression, apply default ordering. + return jpaOrderBy.getString( "value" ); } else { - return null; // @OrderBy not found. + // @OrderBy not found. + return null; } } @@ -2736,7 +2799,7 @@ public abstract class CollectionBinder { ); } - if ( property.isAnnotationPresent( ElementCollection.class ) ) { + if ( property.hasAnnotationUsage( ElementCollection.class ) ) { joinColumns.setElementCollection( true ); } @@ -2867,7 +2930,7 @@ public abstract class CollectionBinder { this.isEmbedded = annotationPresent; } - public void setProperty(XProperty property) { + public void setProperty(MemberDetails property) { this.property = property; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionPropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionPropertyHolder.java index ca42acc341..35fda16358 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionPropertyHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionPropertyHolder.java @@ -14,8 +14,6 @@ import org.hibernate.AssertionFailure; import org.hibernate.annotations.CollectionType; import org.hibernate.annotations.ManyToAny; import org.hibernate.annotations.MapKeyType; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.CoreLogging; @@ -26,9 +24,12 @@ import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import jakarta.persistence.Convert; -import jakarta.persistence.Converts; import jakarta.persistence.Enumerated; import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToMany; @@ -60,8 +61,8 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { public CollectionPropertyHolder( Collection collection, String path, - XClass clazzToProcess, - XProperty property, + ClassDetails clazzToProcess, + MemberDetails property, PropertyHolder parentPropertyHolder, MetadataBuildingContext context) { super( path, parentPropertyHolder, clazzToProcess, context ); @@ -77,7 +78,7 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { } private void buildAttributeConversionInfoMaps( - XProperty collectionProperty, + MemberDetails collectionProperty, boolean isComposite, Map elementAttributeConversionInfoMap, Map keyAttributeConversionInfoMap) { @@ -86,38 +87,20 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { return; } - { - final Convert convertAnnotation = collectionProperty.getAnnotation( Convert.class ); - if ( convertAnnotation != null ) { - applyLocalConvert( - convertAnnotation, - collectionProperty, - isComposite, - elementAttributeConversionInfoMap, - keyAttributeConversionInfoMap - ); - } - } - - { - final Converts convertsAnnotation = collectionProperty.getAnnotation( Converts.class ); - if ( convertsAnnotation != null ) { - for ( Convert convertAnnotation : convertsAnnotation.value() ) { - applyLocalConvert( - convertAnnotation, - collectionProperty, - isComposite, - elementAttributeConversionInfoMap, - keyAttributeConversionInfoMap - ); - } - } - } + collectionProperty.forEachAnnotationUsage( Convert.class, (usage) -> { + applyLocalConvert( + usage, + collectionProperty, + isComposite, + elementAttributeConversionInfoMap, + keyAttributeConversionInfoMap + ); + } ); } private void applyLocalConvert( - Convert convertAnnotation, - XProperty collectionProperty, + AnnotationUsage convertAnnotation, + MemberDetails collectionProperty, boolean isComposite, Map elementAttributeConversionInfoMap, Map keyAttributeConversionInfoMap) { @@ -241,12 +224,12 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { } @Override - public void startingProperty(XProperty property) { + public void startingProperty(MemberDetails property) { // for now, nothing to do... } @Override - protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) { + protected AttributeConversionInfo locateAttributeConversionInfo(MemberDetails attributeMember) { // nothing to do return null; } @@ -282,7 +265,7 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { } @Override - public void addProperty(Property prop, XClass declaringClass) { + public void addProperty(Property prop, MemberDetails memberDetails, ClassDetails declaringClass) { throw new AssertionFailure( "Cannot add property to a collection" ); } @@ -322,18 +305,18 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { } @Override - public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) { + public void addProperty(Property prop, MemberDetails memberDetails, AnnotatedColumns columns, ClassDetails declaringClass) { //Ejb3Column.checkPropertyConsistency( ); //already called earlier throw new AssertionFailure( "addProperty to a join table of a collection: does it make sense?" ); } @Override - public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) { + public Join addJoin(AnnotationUsage joinTableAnn, boolean noDelayInPkColumnCreation) { throw new AssertionFailure( "Add join in a second pass" ); } @Override - public Join addJoin(JoinTable joinTableAnn, Table table, boolean noDelayInPkColumnCreation) { + public Join addJoin(AnnotationUsage joinTableAnn, Table table, boolean noDelayInPkColumnCreation) { throw new AssertionFailure( "Add join in a second pass" ); } @@ -344,7 +327,7 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { boolean prepared; - public void prepare(XProperty collectionProperty, boolean isComposite) { + public void prepare(MemberDetails collectionProperty, boolean isComposite) { // fugly if ( prepared ) { return; @@ -357,16 +340,16 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { prepared = true; if ( collection.isMap() ) { - if ( collectionProperty.isAnnotationPresent( MapKeyEnumerated.class ) ) { + if ( collectionProperty.hasAnnotationUsage( MapKeyEnumerated.class ) ) { canKeyBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( MapKeyTemporal.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( MapKeyTemporal.class ) ) { canKeyBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( MapKeyClass.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( MapKeyClass.class ) ) { canKeyBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( MapKeyType.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( MapKeyType.class ) ) { canKeyBeConverted = false; } } @@ -374,22 +357,22 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { canKeyBeConverted = false; } - if ( collectionProperty.isAnnotationPresent( ManyToAny.class ) ) { + if ( collectionProperty.hasAnnotationUsage( ManyToAny.class ) ) { canElementBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( OneToMany.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( OneToMany.class ) ) { canElementBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( ManyToMany.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( ManyToMany.class ) ) { canElementBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( Enumerated.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( Enumerated.class ) ) { canElementBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( Temporal.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( Temporal.class ) ) { canElementBeConverted = false; } - else if ( collectionProperty.isAnnotationPresent( CollectionType.class ) ) { + else if ( collectionProperty.hasAnnotationUsage( CollectionType.class ) ) { canElementBeConverted = false; } @@ -405,7 +388,9 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { } } - public ConverterDescriptor resolveElementAttributeConverterDescriptor(XProperty collectionXProperty, XClass elementXClass) { + public ConverterDescriptor resolveElementAttributeConverterDescriptor( + MemberDetails memberDetails, + ClassDetails classDetails) { AttributeConversionInfo info = locateAttributeConversionInfo( "element" ); if ( info != null ) { if ( info.isConversionDisabled() ) { @@ -431,10 +416,12 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { return getContext().getMetadataCollector() .getConverterRegistry() .getAttributeConverterAutoApplyHandler() - .findAutoApplyConverterForCollectionElement( collectionXProperty, getContext() ); + .findAutoApplyConverterForCollectionElement( memberDetails, getContext() ); } - public ConverterDescriptor mapKeyAttributeConverterDescriptor(XProperty mapXProperty, XClass keyXClass) { + public ConverterDescriptor mapKeyAttributeConverterDescriptor( + MemberDetails memberDetails, + TypeDetails keyTypeDetails) { AttributeConversionInfo info = locateAttributeConversionInfo( "key" ); if ( info != null ) { if ( info.isConversionDisabled() ) { @@ -460,7 +447,7 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder { return getContext().getMetadataCollector() .getConverterRegistry() .getAttributeConverterAutoApplyHandler() - .findAutoApplyConverterForMapKey( mapXProperty, getContext() ); + .findAutoApplyConverterForMapKey( memberDetails, getContext() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java index 81dd7764b1..a5604f04e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java @@ -18,9 +18,10 @@ import org.hibernate.annotations.FractionalSeconds; import org.hibernate.annotations.JoinColumnOrFormula; import org.hibernate.annotations.JoinColumnsOrFormulas; import org.hibernate.annotations.JoinFormula; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.MemberDetails; import jakarta.persistence.Column; import jakarta.persistence.ElementCollection; @@ -33,6 +34,7 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import java.lang.annotation.Annotation; +import java.util.List; import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnFromAnnotation; import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnFromNoAnnotation; @@ -54,7 +56,7 @@ class ColumnsBuilder { private final PropertyHolder propertyHolder; private final Nullability nullability; - private final XProperty property; + private final MemberDetails property; private final PropertyData inferredData; private final EntityBinder entityBinder; private final MetadataBuildingContext buildingContext; @@ -64,7 +66,7 @@ class ColumnsBuilder { public ColumnsBuilder( PropertyHolder propertyHolder, Nullability nullability, - XProperty property, + MemberDetails property, PropertyData inferredData, EntityBinder entityBinder, MetadataBuildingContext buildingContext) { @@ -88,12 +90,13 @@ class ColumnsBuilder { columns = null; joinColumns = buildExplicitJoinColumns( property, inferredData ); - -// Comment comment = property.getAnnotation(Comment.class); - if ( property.isAnnotationPresent( Column.class ) ) { + final AnnotationUsage columnAnn = property.getAnnotationUsage( Column.class ); + final AnnotationUsage formulaAnn = property.getAnnotationUsage( Formula.class ); + final AnnotationUsage columnsAnn = property.getAnnotationUsage( Columns.class ); + if ( columnAnn != null ) { columns = buildColumnFromAnnotation( - property.getAnnotation( Column.class ), - property.getAnnotation( FractionalSeconds.class ), + property.getAnnotationUsage( Column.class ), + property.getAnnotationUsage( FractionalSeconds.class ), // comment, nullability, propertyHolder, @@ -102,10 +105,9 @@ class ColumnsBuilder { buildingContext ); } - else if ( property.isAnnotationPresent( Formula.class ) ) { + else if ( formulaAnn != null ) { columns = buildFormulaFromAnnotation( getOverridableAnnotation( property, Formula.class, buildingContext ), -// comment, nullability, propertyHolder, inferredData, @@ -113,11 +115,10 @@ class ColumnsBuilder { buildingContext ); } - else if ( property.isAnnotationPresent( Columns.class ) ) { + else if ( columnsAnn != null ) { columns = buildColumnsFromAnnotations( - property.getAnnotation( Columns.class ).columns(), + columnsAnn.getList( "columns" ), null, -// comment, nullability, propertyHolder, inferredData, @@ -128,18 +129,18 @@ class ColumnsBuilder { //set default values if needed if ( joinColumns == null - && ( property.isAnnotationPresent( ManyToOne.class ) - || property.isAnnotationPresent( OneToOne.class ) ) ) { + && ( property.hasAnnotationUsage( ManyToOne.class ) + || property.hasAnnotationUsage( OneToOne.class ) ) ) { joinColumns = buildDefaultJoinColumnsForToOne( property, inferredData ); } else if ( joinColumns == null - && ( property.isAnnotationPresent( OneToMany.class ) - || property.isAnnotationPresent( ElementCollection.class ) ) ) { - OneToMany oneToMany = property.getAnnotation( OneToMany.class ); + && ( property.hasAnnotationUsage( OneToMany.class ) + || property.hasAnnotationUsage( ElementCollection.class ) ) ) { + AnnotationUsage oneToMany = property.getAnnotationUsage( OneToMany.class ); joinColumns = AnnotatedJoinColumns.buildJoinColumns( null, // comment, - oneToMany == null ? null : nullIfEmpty( oneToMany.mappedBy() ), + oneToMany == null ? null : nullIfEmpty( oneToMany.getString( "mappedBy" ) ), entityBinder.getSecondaryTables(), propertyHolder, inferredData, @@ -147,14 +148,14 @@ class ColumnsBuilder { ); } else if ( joinColumns == null - && property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) { + && property.hasAnnotationUsage( org.hibernate.annotations.Any.class ) ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) + "' is annotated '@Any' and must declare at least one '@JoinColumn'" ); } - if ( columns == null && !property.isAnnotationPresent( ManyToMany.class ) ) { + if ( columns == null && !property.hasAnnotationUsage( ManyToMany.class ) ) { //useful for collection of embedded elements columns = buildColumnFromNoAnnotation( - property.getAnnotation( FractionalSeconds.class ), + property.getAnnotationUsage( FractionalSeconds.class ), // comment, nullability, propertyHolder, @@ -173,12 +174,14 @@ class ColumnsBuilder { return this; } - private AnnotatedJoinColumns buildDefaultJoinColumnsForToOne(XProperty property, PropertyData inferredData) { - final JoinTable joinTableAnn = propertyHolder.getJoinTable( property ); + private AnnotatedJoinColumns buildDefaultJoinColumnsForToOne( + MemberDetails property, + PropertyData inferredData) { + final AnnotationUsage joinTableAnn = propertyHolder.getJoinTable( property ); // final Comment comment = property.getAnnotation(Comment.class); if ( joinTableAnn != null ) { return AnnotatedJoinColumns.buildJoinColumns( - joinTableAnn.inverseJoinColumns(), + joinTableAnn.getList( "inverseJoinColumns" ), // comment, null, entityBinder.getSecondaryTables(), @@ -188,11 +191,11 @@ class ColumnsBuilder { ); } else { - final OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class ); + final AnnotationUsage oneToOneAnn = property.getAnnotationUsage( OneToOne.class ); return AnnotatedJoinColumns.buildJoinColumns( null, // comment, - oneToOneAnn == null ? null : nullIfEmpty( oneToOneAnn.mappedBy() ), + oneToOneAnn == null ? null : nullIfEmpty( oneToOneAnn.getString( "mappedBy" ) ), entityBinder.getSecondaryTables(), propertyHolder, inferredData, @@ -201,13 +204,12 @@ class ColumnsBuilder { } } - private AnnotatedJoinColumns buildExplicitJoinColumns(XProperty property, PropertyData inferredData) { + private AnnotatedJoinColumns buildExplicitJoinColumns(MemberDetails property, PropertyData inferredData) { // process @JoinColumns before @Columns to handle collection of entities properly - final JoinColumn[] joinColumnAnnotations = getJoinColumnAnnotations( property, inferredData ); + final List> joinColumnAnnotations = getJoinColumnAnnotations( property, inferredData ); if ( joinColumnAnnotations != null ) { return AnnotatedJoinColumns.buildJoinColumns( joinColumnAnnotations, -// property.getAnnotation( Comment.class ), null, entityBinder.getSecondaryTables(), propertyHolder, @@ -216,7 +218,7 @@ class ColumnsBuilder { ); } - final JoinColumnOrFormula[] joinColumnOrFormulaAnnotations = joinColumnOrFormulaAnnotations( property, inferredData ); + final List> joinColumnOrFormulaAnnotations = joinColumnOrFormulaAnnotations( property, inferredData ); if ( joinColumnOrFormulaAnnotations != null ) { return AnnotatedJoinColumns.buildJoinColumnsOrFormulas( joinColumnOrFormulaAnnotations, @@ -228,8 +230,8 @@ class ColumnsBuilder { ); } - if ( property.isAnnotationPresent( JoinFormula.class) ) { - final JoinFormula joinFormula = getOverridableAnnotation( property, JoinFormula.class, buildingContext ); + if ( property.hasAnnotationUsage( JoinFormula.class) ) { + final AnnotationUsage joinFormula = getOverridableAnnotation( property, JoinFormula.class, buildingContext ); return AnnotatedJoinColumns.buildJoinColumnsWithFormula( joinFormula, entityBinder.getSecondaryTables(), @@ -242,58 +244,63 @@ class ColumnsBuilder { return null; } - private JoinColumnOrFormula[] joinColumnOrFormulaAnnotations(XProperty property, PropertyData inferredData) { - if ( property.isAnnotationPresent( JoinColumnOrFormula.class ) ) { - return new JoinColumnOrFormula[] { property.getAnnotation( JoinColumnOrFormula.class ) }; + private List> joinColumnOrFormulaAnnotations(MemberDetails property, PropertyData inferredData) { + if ( property.hasAnnotationUsage( JoinColumnOrFormula.class ) ) { + return List.of( property.getAnnotationUsage( JoinColumnOrFormula.class ) ); } - else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) { - final JoinColumnsOrFormulas joinColumnsOrFormulas = property.getAnnotation( JoinColumnsOrFormulas.class ); - final JoinColumnOrFormula[] joinColumnOrFormula = joinColumnsOrFormulas.value(); - if ( joinColumnOrFormula.length == 0 ) { + + if ( property.hasAnnotationUsage( JoinColumnsOrFormulas.class ) ) { + final AnnotationUsage joinColumnsOrFormulas = property.getAnnotationUsage( JoinColumnsOrFormulas.class ); + final List> joinColumnOrFormulaList = joinColumnsOrFormulas.getList( "value" ); + if ( joinColumnOrFormulaList.isEmpty() ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData) + "' has an empty '@JoinColumnsOrFormulas' annotation" ); } - return joinColumnOrFormula; - } - else { - return null; + return joinColumnOrFormulaList; } + + return null; } - private JoinColumn[] getJoinColumnAnnotations(XProperty property, PropertyData inferredData) { - if ( property.isAnnotationPresent( JoinColumn.class ) ) { - return new JoinColumn[] { property.getAnnotation( JoinColumn.class ) }; + private List> getJoinColumnAnnotations(MemberDetails property, PropertyData inferredData) { + if ( property.hasAnnotationUsage( JoinColumn.class ) ) { + return List.of( property.getAnnotationUsage( JoinColumn.class ) ); } - else if ( property.isAnnotationPresent( JoinColumns.class ) ) { - final JoinColumns joinColumns = property.getAnnotation( JoinColumns.class ); - final JoinColumn[] joinColumn = joinColumns.value(); - if ( joinColumn.length == 0 ) { + + if ( property.hasAnnotationUsage( JoinColumns.class ) ) { + final AnnotationUsage joinColumns = property.getAnnotationUsage( JoinColumns.class ); + final List> joinColumnsList = joinColumns.getList( "value" ); + if ( joinColumnsList.isEmpty() ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData) + "' has an empty '@JoinColumns' annotation" ); } - return joinColumn; + return joinColumnsList; } - else if ( property.isAnnotationPresent( MapsId.class ) ) { + + if ( property.hasAnnotationUsage( MapsId.class ) ) { // inelegant solution to HHH-16463, let the PrimaryKeyJoinColumn // masquerade as a regular JoinColumn (when a @OneToOne maps to // the primary key of the child table, it's more elegant and more // spec-compliant to map the association with @PrimaryKeyJoinColumn) - if ( property.isAnnotationPresent( PrimaryKeyJoinColumn.class ) ) { - final PrimaryKeyJoinColumn column = property.getAnnotation( PrimaryKeyJoinColumn.class ); - return new JoinColumn[] { new JoinColumnAdapter( column ) }; + if ( property.hasAnnotationUsage( PrimaryKeyJoinColumn.class ) ) { +// final AnnotationUsage nested = property.getAnnotationUsage( PrimaryKeyJoinColumn.class ); +// return new JoinColumn[] { new JoinColumnAdapter( column ) }; + throw new UnsupportedOperationException( "Not yet implemented" ); } - else if ( property.isAnnotationPresent( PrimaryKeyJoinColumns.class ) ) { - final PrimaryKeyJoinColumns primaryKeyJoinColumns = property.getAnnotation( PrimaryKeyJoinColumns.class ); - final JoinColumn[] joinColumns = new JoinColumn[primaryKeyJoinColumns.value().length]; - final PrimaryKeyJoinColumn[] columns = primaryKeyJoinColumns.value(); - if ( columns.length == 0 ) { - throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData) - + "' has an empty '@PrimaryKeyJoinColumns' annotation" ); - } - for ( int i = 0; i < columns.length; i++ ) { - joinColumns[i] = new JoinColumnAdapter( columns[i] ); - } - return joinColumns; + else if ( property.hasAnnotationUsage( PrimaryKeyJoinColumns.class ) ) { +// final AnnotationUsage primaryKeyJoinColumns = property.getAnnotationUsage( PrimaryKeyJoinColumns.class ); +// final List nested = primaryKeyJoinColumns.getList( "value" ); +// final JoinColumn[] joinColumns = new JoinColumn[primaryKeyJoinColumns.value().length]; +// final PrimaryKeyJoinColumn[] columns = primaryKeyJoinColumns.value(); +// if ( columns.length == 0 ) { +// throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData) +// + "' has an empty '@PrimaryKeyJoinColumns' annotation" ); +// } +// for ( int i = 0; i < columns.length; i++ ) { +// joinColumns[i] = new JoinColumnAdapter( columns[i] ); +// } +// return joinColumns; + throw new UnsupportedOperationException( "Not yet implemented" ); } else { return null; @@ -311,9 +318,9 @@ class ColumnsBuilder { final PropertyData override = getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), buildingContext ); if ( override != null ) { - final AnnotatedJoinColumns joinColumns = buildExplicitJoinColumns( override.getProperty(), override ); + final AnnotatedJoinColumns joinColumns = buildExplicitJoinColumns( override.getAttributeMember(), override ); return joinColumns == null - ? buildDefaultJoinColumnsForToOne( override.getProperty(), override ) + ? buildDefaultJoinColumnsForToOne( override.getAttributeMember(), override ) : joinColumns; } else { @@ -374,11 +381,6 @@ class ColumnsBuilder { return column.options(); } - @Override - public CheckConstraint[] check() { - return new CheckConstraint[0]; - } - @Override public String comment() { return ""; @@ -389,6 +391,11 @@ class ColumnsBuilder { return column.foreignKey(); } + @Override + public CheckConstraint[] check() { + return new CheckConstraint[0]; + } + @Override public Class annotationType() { return JoinColumn.class; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java index a9ae721179..951884909c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java @@ -6,12 +6,12 @@ */ package org.hibernate.boot.model.internal; +import java.lang.annotation.Annotation; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.hibernate.AnnotationException; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.mapping.AggregateColumn; @@ -21,13 +21,15 @@ import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import jakarta.persistence.Column; import jakarta.persistence.Convert; -import jakarta.persistence.Converts; import jakarta.persistence.EmbeddedId; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import static org.hibernate.boot.model.internal.ClassPropertyHolder.addPropertyToMappedSuperclass; @@ -82,26 +84,44 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { PropertyHolder parent, MetadataBuildingContext context, Map inheritanceStatePerClass) { - super( path, parent, inferredData.getPropertyClass(), context ); - final XProperty embeddedXProperty = inferredData.getProperty(); - setCurrentProperty( embeddedXProperty ); + super( path, parent, inferredData.getPropertyType().determineRawClass(), context ); + final MemberDetails embeddedMemberDetails = inferredData.getAttributeMember(); + setCurrentProperty( embeddedMemberDetails ); this.component = component; this.isOrWithinEmbeddedId = parent.isOrWithinEmbeddedId() - || hasAnnotation( embeddedXProperty, Id.class, EmbeddedId.class ); - this.isWithinElementCollection = parent.isWithinElementCollection() || - parent instanceof CollectionPropertyHolder; + || hasAnnotation( embeddedMemberDetails, Id.class, EmbeddedId.class ); + this.isWithinElementCollection = parent.isWithinElementCollection() + || parent instanceof CollectionPropertyHolder; this.inheritanceStatePerClass = inheritanceStatePerClass; - if ( embeddedXProperty != null ) { - this.embeddedAttributeName = embeddedXProperty.getName(); - this.attributeConversionInfoMap = processAttributeConversions( embeddedXProperty ); + if ( embeddedMemberDetails != null ) { + this.embeddedAttributeName = embeddedMemberDetails.getName(); + this.attributeConversionInfoMap = processAttributeConversions( embeddedMemberDetails ); } else { this.embeddedAttributeName = ""; - this.attributeConversionInfoMap = processAttributeConversions( inferredData.getClassOrPluralElement() ); + this.attributeConversionInfoMap = processAttributeConversions( inferredData.getClassOrElementType() ); } } + private boolean hasAnnotation( + MemberDetails memberDetails, + Class annotationType) { + if ( memberDetails == null ) { + return false; + } + + return memberDetails.hasAnnotationUsage( annotationType ); + } + + private boolean hasAnnotation( + MemberDetails memberDetails, + Class annotationType1, + Class annotationType2) { + return hasAnnotation( memberDetails, annotationType1 ) + || hasAnnotation( memberDetails, annotationType2 ); + } + /** * This is called from our constructor and handles (in order):
    *
  1. @Convert annotation at the Embeddable class level
  2. @@ -115,78 +135,45 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { * {@literal @Convert/@Converts} annotations at the Embeddable attribute level are handled in the calls to * {@link #startingProperty}. Duplicates are simply ignored there. * - * @param embeddedXProperty The property that is the composite being described by this ComponentPropertyHolder + * @param embeddedMemberDetails The property that is the composite being described by this ComponentPropertyHolder */ - private Map processAttributeConversions(XProperty embeddedXProperty) { + private Map processAttributeConversions(MemberDetails embeddedMemberDetails) { final Map infoMap = new HashMap<>(); - final XClass embeddableXClass = embeddedXProperty.getType(); + final TypeDetails embeddableTypeDetails = embeddedMemberDetails.getType(); // as a baseline, we want to apply conversions from the Embeddable and then overlay conversions // from the Embedded // first apply conversions from the Embeddable... - processAttributeConversions( embeddableXClass, infoMap ); + processAttributeConversions( embeddableTypeDetails, infoMap ); // then we can overlay any conversions from the Embedded attribute - { - // @Convert annotation on the Embedded attribute - final Convert convertAnnotation = embeddedXProperty.getAnnotation( Convert.class ); - if ( convertAnnotation != null ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass ); - if ( isEmpty( info.getAttributeName() ) ) { - throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" ); - } - infoMap.put( info.getAttributeName(), info ); + embeddedMemberDetails.forEachAnnotationUsage( Convert.class, (usage) -> { + final AttributeConversionInfo info = new AttributeConversionInfo( usage, embeddedMemberDetails ); + if ( isEmpty( info.getAttributeName() ) ) { + throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" ); } - } - { - // @Converts annotation on the Embedded attribute - final Converts convertsAnnotation = embeddedXProperty.getAnnotation( Converts.class ); - if ( convertsAnnotation != null ) { - for ( Convert convertAnnotation : convertsAnnotation.value() ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass ); - if ( isEmpty( info.getAttributeName() ) ) { - throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" ); - } - infoMap.put( info.getAttributeName(), info ); - } - } - } + infoMap.put( info.getAttributeName(), info ); + } ); return infoMap; } - private void processAttributeConversions(XClass embeddableXClass, Map infoMap) { - { - // @Convert annotation on the Embeddable class level - final Convert convertAnnotation = embeddableXClass.getAnnotation( Convert.class ); - if ( convertAnnotation != null ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass ); - if ( isEmpty( info.getAttributeName() ) ) { - throw new IllegalStateException( "@Convert placed on @Embeddable must define attributeName" ); - } - infoMap.put( info.getAttributeName(), info ); + private void processAttributeConversions(TypeDetails embeddableTypeDetails, Map infoMap) { + final ClassDetails embeddableClassDetails = embeddableTypeDetails.determineRawClass(); + embeddableClassDetails.forEachAnnotationUsage( Convert.class, (usage) -> { + final AttributeConversionInfo info = new AttributeConversionInfo( usage, embeddableClassDetails ); + if ( isEmpty( info.getAttributeName() ) ) { + throw new IllegalStateException( "@Convert placed on @Embeddable must define attributeName" ); } - } - { - // @Converts annotation on the Embeddable class level - final Converts convertsAnnotation = embeddableXClass.getAnnotation( Converts.class ); - if ( convertsAnnotation != null ) { - for ( Convert convertAnnotation : convertsAnnotation.value() ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass ); - if ( isEmpty( info.getAttributeName() ) ) { - throw new IllegalStateException( "@Converts placed on @Embeddable must define attributeName" ); - } - infoMap.put( info.getAttributeName(), info ); - } - } - } + infoMap.put( info.getAttributeName(), info ); + } ); } - private Map processAttributeConversions(XClass embeddableXClass) { + private Map processAttributeConversions(TypeDetails embeddableTypeDetails) { final Map infoMap = new HashMap<>(); - processAttributeConversions( embeddableXClass, infoMap ); + processAttributeConversions( embeddableTypeDetails, infoMap ); return infoMap; } @@ -201,8 +188,8 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { } @Override - public void startingProperty(XProperty property) { - if ( property == null ) { + public void startingProperty(MemberDetails propertyMemberDetails) { + if ( propertyMemberDetails == null ) { return; } @@ -212,35 +199,21 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { // technically we should only do this for properties of "basic type" - final String path = embeddedAttributeName + '.' + property.getName(); + final String path = embeddedAttributeName + '.' + propertyMemberDetails.getName(); if ( attributeConversionInfoMap.containsKey( path ) ) { return; } - { - // @Convert annotation on the Embeddable attribute - final Convert convertAnnotation = property.getAnnotation( Convert.class ); - if ( convertAnnotation != null ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property ); - attributeConversionInfoMap.put( property.getName(), info ); - } - } - { - // @Converts annotation on the Embeddable attribute - final Converts convertsAnnotation = property.getAnnotation( Converts.class ); - if ( convertsAnnotation != null ) { - for ( Convert convertAnnotation : convertsAnnotation.value() ) { - final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property ); - attributeConversionInfoMap.put( property.getName(), info ); - } - } - } + propertyMemberDetails.forEachAnnotationUsage( Convert.class, (usage) -> { + final AttributeConversionInfo info = new AttributeConversionInfo( usage, propertyMemberDetails ); + attributeConversionInfoMap.put( propertyMemberDetails.getName(), info ); + } ); } @Override - protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) { + protected AttributeConversionInfo locateAttributeConversionInfo(MemberDetails attributeMember) { // conversions on parent would have precedence - return locateAttributeConversionInfo( property.getName() ); + return locateAttributeConversionInfo( attributeMember.getName() ); } @Override @@ -265,7 +238,7 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { } @Override - public void addProperty(Property property, AnnotatedColumns columns, XClass declaringClass) { + public void addProperty(Property property, MemberDetails attributeMemberDetails, AnnotatedColumns columns, ClassDetails declaringClass) { //Ejb3Column.checkPropertyConsistency( ); //already called earlier // Check table matches between the component and the columns // if not, change the component table if no properties are set @@ -285,16 +258,16 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { } } } - addProperty( property, declaringClass ); + addProperty( property, attributeMemberDetails, declaringClass ); } @Override - public Join addJoin(JoinTable joinTable, boolean noDelayInPkColumnCreation) { + public Join addJoin(AnnotationUsage joinTable, boolean noDelayInPkColumnCreation) { return parent.addJoin( joinTable, noDelayInPkColumnCreation ); } @Override - public Join addJoin(JoinTable joinTable, Table table, boolean noDelayInPkColumnCreation) { + public Join addJoin(AnnotationUsage joinTable, Table table, boolean noDelayInPkColumnCreation) { return parent.addJoin( joinTable, table, noDelayInPkColumnCreation ); } @@ -319,7 +292,7 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { } @Override - public void addProperty(Property prop, XClass declaringClass) { + public void addProperty(Property prop, MemberDetails attributeMemberDetails, ClassDetails declaringClass) { handleGenericComponentProperty( prop, getContext() ); if ( declaringClass != null ) { final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass ); @@ -366,17 +339,17 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { } @Override - public Column[] getOverriddenColumn(String propertyName) { + public List> getOverriddenColumn(String propertyName) { //FIXME this is yukky - Column[] result = super.getOverriddenColumn( propertyName ); + List> result = super.getOverriddenColumn( propertyName ); if ( result == null ) { - String userPropertyName = extractUserPropertyName( "id", propertyName ); + final String userPropertyName = extractUserPropertyName( "id", propertyName ); if ( userPropertyName != null ) { result = super.getOverriddenColumn( userPropertyName ); } } if ( result == null ) { - String userPropertyName = extractUserPropertyName( IDENTIFIER_MAPPER_PROPERTY, propertyName ); + final String userPropertyName = extractUserPropertyName( IDENTIFIER_MAPPER_PROPERTY, propertyName ); if ( userPropertyName != null ) { result = super.getOverriddenColumn( userPropertyName ); } @@ -397,11 +370,6 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder { return null; } - @Override - public JoinColumn[] getOverriddenJoinColumn(String propertyName) { - return super.getOverriddenJoinColumn( propertyName ); - } - @Override public String toString() { return getClass().getSimpleName() + "(" + parent.normalizeCompositePathForLogging( embeddedAttributeName ) + ")"; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java index 92243de333..3041c7972d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java @@ -19,16 +19,11 @@ import org.hibernate.AnnotationException; import org.hibernate.annotations.DiscriminatorFormula; import org.hibernate.annotations.Instantiator; import org.hibernate.annotations.TypeBinderType; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XMethod; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.binder.TypeBinder; import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.mapping.AggregateColumn; import org.hibernate.mapping.BasicValue; import org.hibernate.mapping.Component; import org.hibernate.mapping.Property; @@ -36,6 +31,12 @@ import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SingleTableSubclass; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.spi.EmbeddableInstantiator; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.property.access.internal.PropertyAccessStrategyCompositeUserTypeImpl; import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl; import org.hibernate.property.access.spi.PropertyAccessStrategy; @@ -70,7 +71,6 @@ import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNa import static org.hibernate.boot.model.internal.GeneratorBinder.buildGenerators; import static org.hibernate.boot.model.internal.GeneratorBinder.generatorType; import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; -import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotations; import static org.hibernate.boot.model.internal.PropertyBinder.addElementsOfClass; import static org.hibernate.boot.model.internal.PropertyBinder.processElementAnnotations; import static org.hibernate.boot.model.internal.PropertyHolderBuilder.buildPropertyHolder; @@ -94,10 +94,10 @@ public class EmbeddableBinder { boolean isIdentifierMapper, boolean isComponentEmbedded, MetadataBuildingContext context, - Map inheritanceStatePerClass, - XProperty property, + Map inheritanceStatePerClass, + MemberDetails property, AnnotatedColumns columns, - XClass returnedClass, + ClassDetails returnedClass, PropertyBinder propertyBinder, boolean isOverridden, Class> compositeUserType) { @@ -159,10 +159,19 @@ public class EmbeddableBinder { ); } - static boolean isEmbedded(XProperty property, XClass returnedClass) { - return property.isAnnotationPresent( Embedded.class ) - || property.isAnnotationPresent( EmbeddedId.class ) - || returnedClass.isAnnotationPresent( Embeddable.class ) && !property.isAnnotationPresent( Convert.class ); + static boolean isEmbedded(MemberDetails property, ClassDetails returnedClass) { + return property.hasAnnotationUsage( Embedded.class ) + || property.hasAnnotationUsage( EmbeddedId.class ) + || returnedClass.hasAnnotationUsage( Embeddable.class ) && !property.hasAnnotationUsage( Convert.class ); + } + + static boolean isEmbedded(MemberDetails property, TypeDetails returnedClass) { + if ( property.hasAnnotationUsage( Embedded.class ) || property.hasAnnotationUsage( EmbeddedId.class ) ) { + return true; + } + + final ClassDetails returnClassDetails = returnedClass.determineRawClass(); + return returnClassDetails.hasAnnotationUsage( Embeddable.class ) && !property.hasAnnotationUsage( Convert.class ); } public static Component bindEmbeddable( @@ -174,7 +183,7 @@ public class EmbeddableBinder { MetadataBuildingContext context, boolean isComponentEmbedded, boolean isId, //is an identifier - Map inheritanceStatePerClass, + Map inheritanceStatePerClass, String referencedEntityName, //is a component who is overridden by a @MapsId String propertyName, Class customInstantiatorImpl, @@ -220,19 +229,22 @@ public class EmbeddableBinder { component.setKey( true ); checkEmbeddedId( inferredData, propertyHolder, referencedEntityName, component ); } - callTypeBinders( component, context, inferredData.getPropertyClass() ); + callTypeBinders( component, context, inferredData.getPropertyType() ); return component; } - private static void callTypeBinders(Component component, MetadataBuildingContext context, XClass annotatedClass ) { - for ( Annotation containingAnnotation : findContainingAnnotations( annotatedClass, TypeBinderType.class) ) { - final TypeBinderType binderType = containingAnnotation.annotationType().getAnnotation( TypeBinderType.class ); + private static void callTypeBinders(Component component, MetadataBuildingContext context, TypeDetails annotatedClass ) { + final List> metaAnnotatedAnnotations = annotatedClass.determineRawClass().getMetaAnnotated( TypeBinderType.class ); + for ( AnnotationUsage metaAnnotated : metaAnnotatedAnnotations ) { + final AnnotationUsage binderType = metaAnnotated.getAnnotationDescriptor().getAnnotationUsage( TypeBinderType.class ); try { - final TypeBinder binder = binderType.binder().newInstance(); - binder.bind( containingAnnotation, context, component ); + final ClassDetails binderImpl = binderType.getClassDetails( "binder" ); + final Class> binderJavaType = binderImpl.toJavaClass(); + final TypeBinder binder = binderJavaType.getDeclaredConstructor().newInstance(); + binder.bind( metaAnnotated.toAnnotation(), context, component ); } catch ( Exception e ) { - throw new AnnotationException( "error processing @TypeBinderType annotation '" + containingAnnotation + "'", e ); + throw new AnnotationException( "error processing @TypeBinderType annotation '" + metaAnnotated + "'", e ); } } } @@ -244,13 +256,13 @@ public class EmbeddableBinder { MetadataBuildingContext context, boolean isComponentEmbedded, boolean isId, - Map inheritanceStatePerClass, + Map inheritanceStatePerClass, Component component) { final PropertyBinder binder = new PropertyBinder(); binder.setDeclaringClass( inferredData.getDeclaringClass() ); binder.setName( inferredData.getPropertyName() ); binder.setValue(component); - binder.setProperty( inferredData.getProperty() ); + binder.setMemberDetails( inferredData.getAttributeMember() ); binder.setAccessType( inferredData.getDefaultAccess() ); binder.setEmbedded(isComponentEmbedded); binder.setHolder(propertyHolder); @@ -298,7 +310,7 @@ public class EmbeddableBinder { Class> compositeUserTypeClass, AnnotatedColumns columns, MetadataBuildingContext context, - Map inheritanceStatePerClass) { + Map inheritanceStatePerClass) { return fillEmbeddable( propertyHolder, inferredData, @@ -332,7 +344,7 @@ public class EmbeddableBinder { Class> compositeUserTypeClass, AnnotatedColumns columns, MetadataBuildingContext context, - Map inheritanceStatePerClass, + Map inheritanceStatePerClass, boolean isIdClass) { // inSecondPass can only be used to apply right away the second pass of a composite-element // Because it's a value type, there is no bidirectional association, hence second pass @@ -359,19 +371,18 @@ public class EmbeddableBinder { // propertyHolder here is the owner of the component property. // Tell it we are about to start the component... - propertyHolder.startingProperty( inferredData.getProperty() ); + propertyHolder.startingProperty( inferredData.getAttributeMember() ); final CompositeUserType compositeUserType; - final XClass returnedClassOrElement; + final ClassDetails returnedClassOrElement; if ( compositeUserTypeClass == null ) { compositeUserType = null; - returnedClassOrElement = inferredData.getClassOrPluralElement(); + returnedClassOrElement = inferredData.getClassOrElementType().determineRawClass(); } else { compositeUserType = compositeUserType( compositeUserTypeClass, context ); component.setTypeName( compositeUserTypeClass.getName() ); - returnedClassOrElement = context.getBootstrapContext().getReflectionManager() - .toXClass( compositeUserType.embeddable() ); + returnedClassOrElement = context.getMetadataCollector().getSourceModelBuildingContext().getClassDetailsRegistry().resolveClassDetails( compositeUserType.embeddable().getName() ); } AggregateComponentBinder.processAggregate( component, @@ -397,15 +408,13 @@ public class EmbeddableBinder { ); } - final XClass annotatedClass = inferredData.getPropertyClass(); - final Map subclassToSuperclass = component.isPolymorphic() ? new HashMap<>() : null; + final TypeDetails annotatedType = inferredData.getPropertyType(); final List classElements = collectClassElements( propertyAccessor, context, returnedClassOrElement, - annotatedClass, - isIdClass, - subclassToSuperclass + annotatedType, + isIdClass ); if ( component.isPolymorphic() ) { @@ -429,10 +438,10 @@ public class EmbeddableBinder { } final List baseClassElements = - collectBaseClassElements( baseInferredData, propertyAccessor, context, annotatedClass ); + collectBaseClassElements( baseInferredData, propertyAccessor, context, annotatedType ); if ( baseClassElements != null //useful to avoid breaking pre JPA 2 mappings - && !hasAnnotationsOnIdClass( annotatedClass ) ) { + && !hasAnnotationsOnIdClass( annotatedType ) ) { processIdClassElements( propertyHolder, baseInferredData, classElements, baseClassElements ); } for ( PropertyData propertyAnnotatedElement : classElements ) { @@ -452,8 +461,8 @@ public class EmbeddableBinder { inheritanceStatePerClass ); - final XProperty property = propertyAnnotatedElement.getProperty(); - if ( property.isAnnotationPresent( GeneratedValue.class ) ) { + final MemberDetails property = propertyAnnotatedElement.getAttributeMember(); + if ( property.hasAnnotationUsage( GeneratedValue.class ) ) { if ( isIdClass || subholder.isOrWithinEmbeddedId() ) { processGeneratedId( context, component, property ); } @@ -489,7 +498,7 @@ public class EmbeddableBinder { private static void bindDiscriminator( Component component, - XClass componentClass, + ClassDetails componentClass, PropertyHolder parentHolder, PropertyHolder holder, PropertyData propertyData, @@ -512,14 +521,14 @@ public class EmbeddableBinder { } private static AnnotatedDiscriminatorColumn processEmbeddableDiscriminatorProperties( - XClass annotatedClass, + ClassDetails annotatedClass, PropertyData propertyData, PropertyHolder parentHolder, PropertyHolder holder, InheritanceState inheritanceState, MetadataBuildingContext context) { - final DiscriminatorColumn discriminatorColumn = annotatedClass.getAnnotation( DiscriminatorColumn.class ); - final DiscriminatorFormula discriminatorFormula = getOverridableAnnotation( + final AnnotationUsage discriminatorColumn = annotatedClass.getAnnotationUsage( DiscriminatorColumn.class ); + final AnnotationUsage discriminatorFormula = getOverridableAnnotation( annotatedClass, DiscriminatorFormula.class, context @@ -528,7 +537,7 @@ public class EmbeddableBinder { if ( inheritanceState.hasSiblings() ) { final String path = qualify( holder.getPath(), EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ); final String columnPrefix; - final Column[] overrides; + final List> overrides; if ( holder.isWithinElementCollection() ) { columnPrefix = unqualify( parentHolder.getPath() ); overrides = parentHolder.getOverriddenColumn( path ); @@ -540,7 +549,7 @@ public class EmbeddableBinder { return buildDiscriminatorColumn( discriminatorColumn, discriminatorFormula, - overrides == null ? null : overrides[0], + overrides == null ? null : overrides.get(0), columnPrefix + "_" + DEFAULT_DISCRIMINATOR_COLUMN_NAME, context ); @@ -608,8 +617,8 @@ public class EmbeddableBinder { private static List collectClassElements( AccessType propertyAccessor, MetadataBuildingContext context, - XClass returnedClassOrElement, - XClass annotatedClass, + ClassDetails returnedClassOrElement, + TypeDetails annotatedClass, boolean isIdClass, Map subclassToSuperclass) { final List classElements = new ArrayList<>(); @@ -618,12 +627,12 @@ public class EmbeddableBinder { new PropertyContainer( returnedClassOrElement, annotatedClass, propertyAccessor ); addElementsOfClass( classElements, container, context); //add elements of the embeddable's mapped superclasses - XClass subclass = returnedClassOrElement; + ClassDetails subClass = returnedClassOrElement; XClass superClass; while ( isValidSuperclass( superClass = subclass.getSuperclass(), isIdClass ) ) { //FIXME: proper support of type variables incl var resolved at upper levels final PropertyContainer superContainer = - new PropertyContainer( superClass, annotatedClass, propertyAccessor ); + new PropertyContainer( superClass, annotatedClass.determineRawClass(), propertyAccessor ); addElementsOfClass( classElements, superContainer, context ); if ( subclassToSuperclass != null ) { subclassToSuperclass.put( subclass.getName(), superClass.getName() ); @@ -636,12 +645,12 @@ public class EmbeddableBinder { private static void collectSubclassElements( AccessType propertyAccessor, MetadataBuildingContext context, - XClass superclass, + ClassDetails superclass, List classElements, BasicType discriminatorType, Map discriminatorValues, Map subclassToSuperclass) { - for ( final XClass subclass : context.getMetadataCollector().getEmbeddableSubclasses( superclass ) ) { + for ( final ClassDetails subclass : context.getMetadataCollector().getEmbeddableSubclasses( superclass ) ) { // collect the discriminator value details final String old = collectDiscriminatorValue( subclass, discriminatorType, discriminatorValues ); if ( old != null ) { @@ -670,11 +679,11 @@ public class EmbeddableBinder { } private static String collectDiscriminatorValue( - XClass annotatedClass, + ClassDetails annotatedClass, BasicType discriminatorType, Map discriminatorValues) { - final String explicitValue = annotatedClass.isAnnotationPresent( DiscriminatorValue.class ) - ? annotatedClass.getAnnotation( DiscriminatorValue.class ).value() + final String explicitValue = annotatedClass.hasAnnotationUsage( DiscriminatorValue.class ) + ? annotatedClass.getAnnotationUsage( DiscriminatorValue.class ).getString( "value" ) : null; final String discriminatorValue; if ( isEmpty( explicitValue ) ) { @@ -702,12 +711,12 @@ public class EmbeddableBinder { } - private static boolean isValidSuperclass(XClass superClass, boolean isIdClass) { + private static boolean isValidSuperclass(ClassDetails superClass, boolean isIdClass) { if ( superClass == null ) { return false; } - return superClass.isAnnotationPresent( MappedSuperclass.class ) + return superClass.hasAnnotationUsage( MappedSuperclass.class ) || ( isIdClass && !superClass.getName().equals( Object.class.getName() ) && !superClass.getName().equals( "java.lang.Record" ) ); @@ -717,17 +726,20 @@ public class EmbeddableBinder { PropertyData baseInferredData, AccessType propertyAccessor, MetadataBuildingContext context, - XClass annotatedClass) { + TypeDetails annotatedClass) { if ( baseInferredData != null ) { final List baseClassElements = new ArrayList<>(); // iterate from base returned class up hierarchy to handle cases where the @Id attributes // might be spread across the subclasses and super classes. - XClass baseReturnedClassOrElement = baseInferredData.getClassOrElement(); + TypeDetails baseReturnedClassOrElement = baseInferredData.getClassOrElementType(); while ( !Object.class.getName().equals( baseReturnedClassOrElement.getName() ) ) { - final PropertyContainer container = - new PropertyContainer( baseReturnedClassOrElement, annotatedClass, propertyAccessor ); + final PropertyContainer container = new PropertyContainer( + baseReturnedClassOrElement, + annotatedClass, + propertyAccessor + ); addElementsOfClass( baseClassElements, container, context ); - baseReturnedClassOrElement = baseReturnedClassOrElement.getSuperclass(); + baseReturnedClassOrElement = baseReturnedClassOrElement.determineRawClass().getGenericSuperType(); } return baseClassElements; } @@ -758,13 +770,16 @@ public class EmbeddableBinder { } } - private static boolean hasAnnotationsOnIdClass(XClass idClass) { - for ( XProperty property : idClass.getDeclaredProperties( XClass.ACCESS_FIELD ) ) { - if ( hasTriggeringAnnotation( property ) ) { + private static boolean hasAnnotationsOnIdClass(TypeDetails idClassType) { + return hasAnnotationsOnIdClass( idClassType.determineRawClass() ); + } + private static boolean hasAnnotationsOnIdClass(ClassDetails idClass) { + for ( FieldDetails field : idClass.getFields() ) { + if ( hasTriggeringAnnotation( field ) ) { return true; } } - for ( XMethod method : idClass.getDeclaredMethods() ) { + for ( MethodDetails method : idClass.getMethods() ) { if ( hasTriggeringAnnotation( method ) ) { return true; } @@ -772,22 +787,22 @@ public class EmbeddableBinder { return false; } - private static boolean hasTriggeringAnnotation(XAnnotatedElement property) { - return property.isAnnotationPresent(Column.class) - || property.isAnnotationPresent(OneToMany.class) - || property.isAnnotationPresent(ManyToOne.class) - || property.isAnnotationPresent(Id.class) - || property.isAnnotationPresent(GeneratedValue.class) - || property.isAnnotationPresent(OneToOne.class) - || property.isAnnotationPresent(ManyToMany.class); + private static boolean hasTriggeringAnnotation(MemberDetails property) { + return property.hasAnnotationUsage(Column.class) + || property.hasAnnotationUsage(OneToMany.class) + || property.hasAnnotationUsage(ManyToOne.class) + || property.hasAnnotationUsage(Id.class) + || property.hasAnnotationUsage(GeneratedValue.class) + || property.hasAnnotationUsage(OneToOne.class) + || property.hasAnnotationUsage(ManyToMany.class); } - private static void processGeneratedId(MetadataBuildingContext context, Component component, XProperty property) { - final GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class ); + private static void processGeneratedId(MetadataBuildingContext context, Component component, MemberDetails property) { + final AnnotationUsage generatedValue = property.getAnnotationUsage( GeneratedValue.class ); final String generatorType = generatedValue != null - ? generatorType( generatedValue, property.getType(), context ) + ? generatorType( generatedValue, property.getType().determineRawClass(), context ) : DEFAULT_ID_GEN_STRATEGY; - final String generator = generatedValue != null ? generatedValue.generator() : ""; + final String generator = generatedValue != null ? generatedValue.getString( "generator" ) : ""; if ( isGlobalGeneratorNameGlobal( context ) ) { buildGenerators( property, context ); @@ -835,12 +850,12 @@ public class EmbeddableBinder { throw new AnnotationException( "Property '" + getPath(propertyHolder, idClassPropertyData ) + "' belongs to an '@IdClass' but has no matching property in entity class '" - + baseInferredData.getPropertyClass().getName() + + baseInferredData.getPropertyType().getName() + "' (every property of the '@IdClass' must have a corresponding persistent property in the '@Entity' class)" ); } - if ( hasToOneAnnotation( entityPropertyData.getProperty() ) - && !entityPropertyData.getClassOrElement().equals( idClassPropertyData.getClassOrElement() ) ) { + if ( hasToOneAnnotation( entityPropertyData.getAttributeMember() ) + && !entityPropertyData.getClassOrElementType().equals( idClassPropertyData.getClassOrElementType() ) ) { //don't replace here as we need to use the actual original return type //the annotation overriding will be dealt with by a mechanism similar to @MapsId continue; @@ -861,19 +876,15 @@ public class EmbeddableBinder { component.setEmbedded( isComponentEmbedded ); //yuk component.setTable( propertyHolder.getTable() ); - final XClass embeddableClass; - //FIXME shouldn't identifier mapper use getClassOrElementName? Need to be checked. if ( isIdentifierMapper || isComponentEmbedded && inferredData.getPropertyName() == null ) { component.setComponentClassName( component.getOwner().getClassName() ); - embeddableClass = inferredData.getClassOrElement(); } else { - embeddableClass = inferredData.getClassOrPluralElement(); - component.setComponentClassName( embeddableClass.getName() ); + component.setComponentClassName( inferredData.getClassOrElementType().getName() ); } component.setCustomInstantiator( customInstantiatorImpl ); - final Constructor constructor = resolveInstantiator( embeddableClass, context ); + final Constructor constructor = resolveInstantiator( inferredData.getClassOrElementType(), context ); if ( constructor != null ) { component.setInstantiator( constructor, constructor.getAnnotation( Instantiator.class ).value() ); } @@ -884,11 +895,13 @@ public class EmbeddableBinder { return component; } - private static Constructor resolveInstantiator(XClass embeddableClass, MetadataBuildingContext buildingContext) { + private static Constructor resolveInstantiator(TypeDetails embeddableClass, MetadataBuildingContext buildingContext) { + return embeddableClass == null ? null : resolveInstantiator( embeddableClass.determineRawClass(), buildingContext ); + } + + private static Constructor resolveInstantiator(ClassDetails embeddableClass, MetadataBuildingContext buildingContext) { if ( embeddableClass != null ) { - final Constructor[] declaredConstructors = buildingContext.getBootstrapContext().getReflectionManager() - .toClass( embeddableClass ) - .getDeclaredConstructors(); + final Constructor[] declaredConstructors = embeddableClass.toJavaClass().getDeclaredConstructors(); Constructor constructor = null; for ( Constructor declaredConstructor : declaredConstructors ) { if ( declaredConstructor.isAnnotationPresent( Instantiator.class ) ) { @@ -905,29 +918,28 @@ public class EmbeddableBinder { } public static Class determineCustomInstantiator( - XProperty property, - XClass returnedClass, + MemberDetails property, + ClassDetails returnedClass, MetadataBuildingContext context) { - if ( property.isAnnotationPresent( EmbeddedId.class ) ) { + if ( property.hasAnnotationUsage( EmbeddedId.class ) ) { // we don't allow custom instantiators for composite ids return null; } - final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = - property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final AnnotationUsage propertyAnnotation = + property.getAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( propertyAnnotation != null ) { - return propertyAnnotation.value(); + return propertyAnnotation.getClassDetails( "value" ).toJavaClass(); } - final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = - returnedClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final AnnotationUsage classAnnotation = + returnedClass.getAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( classAnnotation != null ) { - return classAnnotation.value(); + return classAnnotation.getClassDetails( "value" ).toJavaClass(); } - final Class embeddableClass = context.getBootstrapContext().getReflectionManager().toClass( returnedClass ); - if ( embeddableClass != null ) { - return context.getMetadataCollector().findRegisteredEmbeddableInstantiator( embeddableClass ); + if ( returnedClass.getClassName() != null ) { + return context.getMetadataCollector().findRegisteredEmbeddableInstantiator( returnedClass.toJavaClass() ); } return null; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index edc1d878b0..0569a33f95 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -17,10 +17,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import jakarta.persistence.AssociationOverride; -import jakarta.persistence.AssociationOverrides; -import jakarta.persistence.AttributeOverride; -import jakarta.persistence.AttributeOverrides; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; @@ -43,7 +39,6 @@ import org.hibernate.annotations.NaturalIdCache; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OptimisticLockType; import org.hibernate.annotations.OptimisticLocking; -import org.hibernate.annotations.Persister; import org.hibernate.annotations.Polymorphism; import org.hibernate.annotations.PolymorphismType; import org.hibernate.annotations.Proxy; @@ -69,9 +64,6 @@ import org.hibernate.annotations.TypeBinderType; import org.hibernate.annotations.View; import org.hibernate.annotations.Where; import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.binder.TypeBinder; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.NamedEntityGraphDefinition; @@ -81,6 +73,7 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.ImplicitEntityNameSource; import org.hibernate.boot.model.naming.NamingStrategyHelper; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.models.HibernateAnnotations; import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -91,6 +84,7 @@ import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.jdbc.Expectation; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.mapping.BasicValue; import org.hibernate.mapping.CheckConstraint; @@ -109,12 +103,20 @@ import org.hibernate.mapping.Table; import org.hibernate.mapping.TableOwner; import org.hibernate.mapping.UnionSubclass; import org.hibernate.mapping.Value; -import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.models.internal.ClassTypeDetailsImpl; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.spi.NavigablePath; import org.jboss.logging.Logger; import jakarta.persistence.Access; +import jakarta.persistence.AssociationOverride; +import jakarta.persistence.AttributeOverride; import jakarta.persistence.Cacheable; import jakarta.persistence.ConstraintMode; import jakarta.persistence.DiscriminatorColumn; @@ -127,7 +129,6 @@ import jakarta.persistence.Inheritance; import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.NamedEntityGraph; -import jakarta.persistence.NamedEntityGraphs; import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.PrimaryKeyJoinColumns; import jakarta.persistence.SecondaryTable; @@ -142,22 +143,20 @@ import static org.hibernate.boot.model.internal.AnnotatedClassType.MAPPED_SUPERC import static org.hibernate.boot.model.internal.AnnotatedDiscriminatorColumn.DEFAULT_DISCRIMINATOR_COLUMN_NAME; import static org.hibernate.boot.model.internal.AnnotatedDiscriminatorColumn.buildDiscriminatorColumn; import static org.hibernate.boot.model.internal.AnnotatedJoinColumn.buildInheritanceJoinColumn; +import static org.hibernate.boot.model.internal.BinderHelper.extractFromPackage; import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; -import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation; +import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation; import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation; -import static org.hibernate.boot.model.internal.BinderHelper.isDefault; import static org.hibernate.boot.model.internal.BinderHelper.noConstraint; import static org.hibernate.boot.model.internal.BinderHelper.toAliasEntityMap; import static org.hibernate.boot.model.internal.BinderHelper.toAliasTableMap; import static org.hibernate.boot.model.internal.EmbeddableBinder.fillEmbeddable; import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; -import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotations; import static org.hibernate.boot.model.internal.InheritanceState.getInheritanceStateOfSuperEntity; import static org.hibernate.boot.model.internal.PropertyBinder.addElementsOfClass; import static org.hibernate.boot.model.internal.PropertyBinder.hasIdAnnotation; import static org.hibernate.boot.model.internal.PropertyBinder.processElementAnnotations; import static org.hibernate.boot.model.internal.PropertyHolderBuilder.buildPropertyHolder; -import static org.hibernate.boot.model.internal.BinderHelper.extractFromPackage; import static org.hibernate.boot.model.internal.TableBinder.bindForeignKey; import static org.hibernate.boot.model.naming.Identifier.toIdentifier; import static org.hibernate.engine.OptimisticLockStyle.fromLockType; @@ -186,11 +185,11 @@ public class EntityBinder { private MetadataBuildingContext context; private String name; - private XClass annotatedClass; + private ClassDetails annotatedClass; private PersistentClass persistentClass; private PolymorphismType polymorphismType; private boolean lazy; - private XClass proxyClass; + private ClassDetails proxyClass; private String where; // todo : we should defer to InFlightMetadataCollector.EntityTableXref for secondary table tracking; // atm we use both from here; HBM binding solely uses InFlightMetadataCollector.EntityTableXref @@ -199,7 +198,7 @@ public class EntityBinder { private final java.util.Map secondaryTablesFromAnnotation = new HashMap<>(); private final java.util.Map secondaryTableFromAnnotationJoins = new HashMap<>(); - private final List filters = new ArrayList<>(); + private final List> filters = new ArrayList<>(); private boolean ignoreIdAnnotations; private AccessType propertyAccessType = AccessType.DEFAULT; private boolean wrapIdsInEmbeddedComponents; @@ -216,8 +215,8 @@ public class EntityBinder { * Bind an entity class. This can be done in a single pass. */ public static void bindEntityClass( - XClass clazzToProcess, - Map inheritanceStates, + ClassDetails clazzToProcess, + Map inheritanceStates, Map generators, MetadataBuildingContext context) { if ( LOG.isDebugEnabled() ) { @@ -252,7 +251,7 @@ public class EntityBinder { final InFlightMetadataCollector collector = context.getMetadataCollector(); if ( persistentClass instanceof RootClass ) { collector.addSecondPass( new CreateKeySecondPass( (RootClass) persistentClass ) ); - bindSoftDelete( clazzToProcess, (RootClass) persistentClass, context ); + bindSoftDelete( clazzToProcess, (RootClass) persistentClass, inheritanceState, context ); } if ( persistentClass instanceof Subclass) { assert superEntity != null; @@ -260,8 +259,8 @@ public class EntityBinder { } collector.addEntityBinding( persistentClass ); // process secondary tables and complementary definitions (ie o.h.a.Table) - collector.addSecondPass( new SecondaryTableFromAnnotationSecondPass( entityBinder, holder, clazzToProcess ) ); - collector.addSecondPass( new SecondaryTableSecondPass( entityBinder, holder, clazzToProcess ) ); + collector.addSecondPass( new SecondaryTableFromAnnotationSecondPass( entityBinder, holder ) ); + collector.addSecondPass( new SecondaryTableSecondPass( entityBinder, holder ) ); // comment, checkConstraint, and indexes are processed here entityBinder.processComplementaryTableDefinitions(); bindCallbacks( clazzToProcess, persistentClass, context ); @@ -273,33 +272,19 @@ public class EntityBinder { handleSecondaryTables(); } - private static void checkOverrides(XClass clazzToProcess, PersistentClass superEntity) { + private static void checkOverrides(ClassDetails clazzToProcess, PersistentClass superEntity) { if ( superEntity != null ) { //TODO: correctly handle compound paths (embeddables) - { - AttributeOverrides overrides = clazzToProcess.getAnnotation(AttributeOverrides.class); - if ( overrides != null ) { - for ( AttributeOverride override : overrides.value() ) { - checkOverride( superEntity, override.name(), clazzToProcess, AttributeOverride.class ); - } - } - AttributeOverride override = clazzToProcess.getAnnotation(AttributeOverride.class); - if ( override != null ) { - checkOverride( superEntity, override.name(), clazzToProcess, AttributeOverride.class ); - } - } - { - AssociationOverrides overrides = clazzToProcess.getAnnotation(AssociationOverrides.class); - if ( overrides != null ) { - for ( AssociationOverride override : overrides.value() ) { - checkOverride( superEntity, override.name(), clazzToProcess, AssociationOverride.class ); - } - } - AssociationOverride override = clazzToProcess.getAnnotation(AssociationOverride.class); - if ( override != null ) { - checkOverride( superEntity, override.name(), clazzToProcess, AssociationOverride.class ); - } - } + clazzToProcess.forEachAnnotationUsage( AttributeOverride.class, (usage) -> checkOverride( + superEntity, + usage.getString( "name" ), + clazzToProcess, AttributeOverride.class + ) ); + clazzToProcess.forEachAnnotationUsage( AssociationOverride.class, (usage) -> checkOverride( + superEntity, + usage.getString( "name" ), + clazzToProcess, AttributeOverride.class + ) ); } } @@ -311,7 +296,7 @@ public class EntityBinder { * mapped superclass even though it cannot override any fields of the root class. */ private static void checkOverride( - PersistentClass superEntity, String name, XClass clazzToProcess, Class overrideClass) { + PersistentClass superEntity, String name, ClassDetails clazzToProcess, Class overrideClass) { if ( superEntity.hasProperty( StringHelper.root(name) ) ) { throw new AnnotationException("Property '" + name + "' is inherited from entity '" + superEntity.getEntityName() @@ -321,13 +306,14 @@ public class EntityBinder { } private static void bindSoftDelete( - XClass xClass, + ClassDetails classDetails, RootClass rootClass, + InheritanceState inheritanceState, MetadataBuildingContext context) { // todo (soft-delete) : do we assume all package-level registrations are already available? // or should this be a "second pass"? - final SoftDelete softDelete = extractSoftDelete( xClass, rootClass, context ); + final AnnotationUsage softDelete = extractSoftDelete( classDetails, inheritanceState, context ); if ( softDelete != null ) { SoftDeleteHelper.bindSoftDeleteIndicator( softDelete, @@ -338,38 +324,38 @@ public class EntityBinder { } } - private static SoftDelete extractSoftDelete( - XClass xClass, - RootClass rootClass, + private static AnnotationUsage extractSoftDelete( + ClassDetails classDetails, + InheritanceState inheritanceState, MetadataBuildingContext context) { - final SoftDelete fromClass = xClass.getAnnotation( SoftDelete.class ); + final AnnotationUsage fromClass = classDetails.getAnnotationUsage( SoftDelete.class ); if ( fromClass != null ) { return fromClass; } - MappedSuperclass mappedSuperclass = rootClass.getSuperMappedSuperclass(); - while ( mappedSuperclass != null ) { - // todo (soft-delete) : use XClass for MappedSuperclass? for the time being, just use the Java type - final SoftDelete fromMappedSuperclass = mappedSuperclass.getMappedClass().getAnnotation( SoftDelete.class ); - if ( fromMappedSuperclass != null ) { - return fromMappedSuperclass; + ClassDetails classToCheck = classDetails.getSuperClass(); + while ( classToCheck != null ) { + final AnnotationUsage fromSuper = classToCheck.getAnnotationUsage( SoftDelete.class ); + if ( fromSuper != null && classToCheck.hasAnnotationUsage( jakarta.persistence.MappedSuperclass.class ) ) { + return fromSuper; } - mappedSuperclass = mappedSuperclass.getSuperMappedSuperclass(); + classToCheck = classToCheck.getSuperClass(); } - return extractFromPackage( SoftDelete.class, xClass, context ); + return extractFromPackage( SoftDelete.class, classDetails, context ); } private void handleCheckConstraints() { - if ( annotatedClass.isAnnotationPresent( Checks.class ) ) { - // if we have more than one of them they are not overrideable :-/ - for ( Check check : annotatedClass.getAnnotation( Checks.class ).value() ) { + if ( annotatedClass.hasAnnotationUsage( Checks.class ) ) { + // if we have more than one of them they are not overrideable + final AnnotationUsage explicitUsage = annotatedClass.getAnnotationUsage( Checks.class ); + for ( AnnotationUsage check : explicitUsage.>getList( "value" ) ) { addCheckToEntity( check ); } } else { - final Check check = getOverridableAnnotation( annotatedClass, Check.class, context ); + final AnnotationUsage check = getOverridableAnnotation( annotatedClass, Check.class, context ); if ( check != null ) { addCheckToEntity( check ); } @@ -380,30 +366,42 @@ public class EntityBinder { * For now, we store it on the entity. * Later we will come back and figure out which table it belongs to. */ - private void addCheckToEntity(Check check) { - final String name = check.name(); - final String constraint = check.constraints(); + private void addCheckToEntity(AnnotationUsage check) { + final String name = check.getString( "name" ); + final String constraint = check.getString( "constraints" ); persistentClass.addCheckConstraint( name.isEmpty() ? new CheckConstraint( constraint ) : new CheckConstraint( name, constraint ) ); } private void callTypeBinders(PersistentClass persistentClass) { - for ( Annotation containingAnnotation : findContainingAnnotations( annotatedClass, TypeBinderType.class ) ) { - final TypeBinderType binderType = containingAnnotation.annotationType().getAnnotation( TypeBinderType.class ); - try { - final TypeBinder binder = binderType.binder().newInstance(); - binder.bind( containingAnnotation, context, persistentClass ); - } - catch ( Exception e ) { - throw new AnnotationException( "error processing @TypeBinderType annotation '" + containingAnnotation + "'", e ); - } + final List> metaAnnotatedList = annotatedClass.getMetaAnnotated( TypeBinderType.class ); + for ( AnnotationUsage metaAnnotated : metaAnnotatedList ) { + applyTypeBinder( metaAnnotated, persistentClass ); + } + } + + private void applyTypeBinder(AnnotationUsage metaAnnotated, PersistentClass persistentClass) { + final AnnotationUsage metaAnnotation = metaAnnotated.getAnnotationDescriptor().getAnnotationUsage( TypeBinderType.class ); + final ClassDetails binderClassDetails = metaAnnotation.getClassDetails( "binder" ); + final Class> binderClass = binderClassDetails.toJavaClass(); + + final Annotation containingAnnotation = metaAnnotated.toAnnotation(); + + try { + //noinspection rawtypes + final TypeBinder binder = binderClass.getConstructor().newInstance(); + //noinspection unchecked + binder.bind( containingAnnotation, context, persistentClass ); + } + catch ( Exception e ) { + throw new AnnotationException( "error processing @TypeBinderType annotation '" + containingAnnotation + "'", e ); } } private void handleIdentifier( PropertyHolder propertyHolder, - Map inheritanceStates, + Map inheritanceStates, Map generators, InheritanceState inheritanceState) { final ElementsToProcess elementsToProcess = inheritanceState.postProcess( persistentClass, this ); @@ -428,9 +426,27 @@ public class EntityBinder { } private void processComplementaryTableDefinitions() { - processComplementaryTableDefinitions( annotatedClass.getAnnotation( org.hibernate.annotations.Table.class ) ); - processComplementaryTableDefinitions( annotatedClass.getAnnotation( org.hibernate.annotations.Tables.class ) ); - processComplementaryTableDefinitions( annotatedClass.getAnnotation( jakarta.persistence.Table.class ) ); + annotatedClass.forEachAnnotationUsage( org.hibernate.annotations.Table.class, (usage) -> { + + final Table appliedTable = findTable( usage.getString( "appliesTo" ) ); + + final String comment = usage.getString( "comment" ); + if ( !comment.isEmpty() ) { + appliedTable.setComment( comment ); + } + + final String checkConstraint = usage.getString( "checkConstraint" ); + if ( !checkConstraint.isEmpty() ) { + //noinspection deprecation + appliedTable.addCheckConstraint( checkConstraint ); + } + + TableBinder.addIndexes( appliedTable, usage.getList( "indexes" ), context ); + } ); + + annotatedClass.forEachAnnotationUsage( jakarta.persistence.Table.class, (usage) -> { + TableBinder.addJpaIndexes( persistentClass.getTable(), usage.getList( "indexes" ), context ); + } ); } private Set handleIdClass( @@ -439,7 +455,7 @@ public class EntityBinder { MetadataBuildingContext context, PropertyHolder propertyHolder, ElementsToProcess elementsToProcess, - Map inheritanceStates) { + Map inheritanceStates) { final Set idPropertiesIfIdClass = new HashSet<>(); boolean isIdClass = mapAsIdClass( inheritanceStates, @@ -457,7 +473,7 @@ public class EntityBinder { } private boolean mapAsIdClass( - Map inheritanceStates, + Map inheritanceStates, InheritanceState inheritanceState, PersistentClass persistentClass, PropertyHolder propertyHolder, @@ -467,14 +483,16 @@ public class EntityBinder { // We are looking for @IdClass // In general we map the id class as identifier using the mapping metadata of the main entity's - // properties and we create an identifier mapper containing the id properties of the main entity - final XClass classWithIdClass = inheritanceState.getClassWithIdClass( false ); + // properties and create an identifier mapper containing the id properties of the main entity + final ClassDetails classWithIdClass = inheritanceState.getClassWithIdClass( false ); if ( classWithIdClass != null ) { - final Class idClassValue = classWithIdClass.getAnnotation( IdClass.class ).value(); - final XClass compositeClass = context.getBootstrapContext().getReflectionManager().toXClass( idClassValue ); + final Class idClassValue = classWithIdClass.getAnnotationUsage( IdClass.class ).getClassDetails( "value" ).toJavaClass(); + final ClassDetails compositeClass = context.getMetadataCollector().getSourceModelBuildingContext().getClassDetailsRegistry().resolveClassDetails( idClassValue.getName() ); + final TypeDetails compositeType = new ClassTypeDetailsImpl( compositeClass, TypeDetails.Kind.CLASS ); + final AccessType accessType = getPropertyAccessType(); - final PropertyData inferredData = new PropertyPreloadedData( accessType, "id", compositeClass ); - final PropertyData baseInferredData = new PropertyPreloadedData( accessType, "id", classWithIdClass ); + final PropertyData inferredData = new PropertyPreloadedData( accessType, "id", compositeType ); + final PropertyData baseInferredData = new PropertyPreloadedData( accessType, "id", compositeType ); final AccessType propertyAccessor = getPropertyAccessor( compositeClass ); // In JPA 2, there is a shortcut if the IdClass is the Pk of the associated class pointed to by the id @@ -509,7 +527,7 @@ public class EntityBinder { propertyHolder, context, classWithIdClass, - compositeClass, + compositeType, baseInferredData, propertyAccessor, true @@ -530,12 +548,12 @@ public class EntityBinder { } private Component createMapperProperty( - Map inheritanceStates, + Map inheritanceStates, PersistentClass persistentClass, PropertyHolder propertyHolder, MetadataBuildingContext context, - XClass classWithIdClass, - XClass compositeClass, + ClassDetails classWithIdClass, + TypeDetails compositeClass, PropertyData baseInferredData, AccessType propertyAccessor, boolean isIdClass) { @@ -561,12 +579,12 @@ public class EntityBinder { } private Component createMapper( - Map inheritanceStates, + Map inheritanceStates, PersistentClass persistentClass, PropertyHolder propertyHolder, MetadataBuildingContext context, - XClass classWithIdClass, - XClass compositeClass, + ClassDetails classWithIdClass, + TypeDetails compositeClass, PropertyData baseInferredData, AccessType propertyAccessor, boolean isIdClass) { @@ -612,8 +630,8 @@ public class EntityBinder { MetadataBuildingContext context) { final List baseClassElements = new ArrayList<>(); final PropertyContainer propContainer = new PropertyContainer( - baseInferredData.getClassOrElement(), - inferredData.getPropertyClass(), + baseInferredData.getClassOrElementType().determineRawClass(), + inferredData.getPropertyType().determineRawClass(), propertyAccessor ); addElementsOfClass( baseClassElements, propContainer, context ); @@ -623,11 +641,11 @@ public class EntityBinder { private static boolean isIdClassPkOfTheAssociatedEntity( ElementsToProcess elementsToProcess, - XClass compositeClass, + ClassDetails compositeClass, PropertyData inferredData, PropertyData baseInferredData, AccessType propertyAccessor, - Map inheritanceStates, + Map inheritanceStates, MetadataBuildingContext context) { if ( elementsToProcess.getIdPropertyCount() == 1 ) { final PropertyData idPropertyOnBaseClass = getUniqueIdPropertyFromBaseClass( @@ -636,22 +654,20 @@ public class EntityBinder { propertyAccessor, context ); - final InheritanceState state = inheritanceStates.get( idPropertyOnBaseClass.getClassOrElement() ); + final InheritanceState state = inheritanceStates.get( idPropertyOnBaseClass.getClassOrElementType() ); if ( state == null ) { return false; //while it is likely a user error, let's consider it is something that might happen } - final XClass associatedClassWithIdClass = state.getClassWithIdClass( true ); + final ClassDetails associatedClassWithIdClass = state.getClassWithIdClass( true ); if ( associatedClassWithIdClass == null ) { //we cannot know for sure here unless we try and find the @EmbeddedId //Let's not do this thorough checking but do some extra validation - return hasToOneAnnotation( idPropertyOnBaseClass.getProperty() ); + return hasToOneAnnotation( idPropertyOnBaseClass.getAttributeMember() ); } else { - final IdClass idClass = associatedClassWithIdClass.getAnnotation(IdClass.class); - //noinspection unchecked - return context.getBootstrapContext().getReflectionManager().toXClass( idClass.value() ) - .equals( compositeClass ); + final AnnotationUsage idClass = associatedClassWithIdClass.getAnnotationUsage( IdClass.class ); + return compositeClass.equals( idClass.getClassDetails( "value" ) ); } } else { @@ -665,7 +681,7 @@ public class EntityBinder { PropertyHolder propertyHolder, AccessType propertyAccessor, MetadataBuildingContext buildingContext, - Map inheritanceStates) { + Map inheritanceStates) { propertyHolder.setInIdClass( true ); // Fill simple value and property since and Id is a property @@ -707,7 +723,7 @@ public class EntityBinder { handleIdGenerator( inferredData, buildingContext, id ); - rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null ); + rootClass.setEmbeddedIdentifier( inferredData.getPropertyType() == null ); propertyHolder.setInIdClass( null ); @@ -718,7 +734,7 @@ public class EntityBinder { if ( buildingContext.getBootstrapContext().getJpaCompliance().isGlobalGeneratorScopeEnabled() ) { buildingContext.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( id, - inferredData.getProperty(), + inferredData.getAttributeMember(), DEFAULT_ID_GEN_STRATEGY, "", buildingContext @@ -727,7 +743,7 @@ public class EntityBinder { else { makeIdGenerator( id, - inferredData.getProperty(), + inferredData.getAttributeMember(), DEFAULT_ID_GEN_STRATEGY, "", buildingContext, @@ -737,38 +753,30 @@ public class EntityBinder { } private void handleSecondaryTables() { - final SecondaryTable secTable = annotatedClass.getAnnotation( SecondaryTable.class ); - final SecondaryTables secTables = annotatedClass.getAnnotation( SecondaryTables.class ); - if ( secTables != null ) { - //loop through it - for ( SecondaryTable tab : secTables.value() ) { - addJoin( tab, null, false ); - } - } - else if ( secTable != null ) { - addJoin( secTable, null, false ); - } + annotatedClass.forEachAnnotationUsage( SecondaryTable.class, (usage) -> { + addSecondaryTable( usage, null, false ); + } ); } private void handleClassTable(InheritanceState inheritanceState, PersistentClass superEntity) { final String schema; final String table; final String catalog; - final UniqueConstraint[] uniqueConstraints; - final boolean hasTableAnnotation = annotatedClass.isAnnotationPresent( jakarta.persistence.Table.class ); + final List> uniqueConstraints; + final boolean hasTableAnnotation = annotatedClass.hasAnnotationUsage( jakarta.persistence.Table.class ); if ( hasTableAnnotation ) { - final jakarta.persistence.Table tableAnnotation = annotatedClass.getAnnotation( jakarta.persistence.Table.class ); - table = tableAnnotation.name(); - schema = tableAnnotation.schema(); - catalog = tableAnnotation.catalog(); - uniqueConstraints = tableAnnotation.uniqueConstraints(); + final AnnotationUsage tableAnnotation = annotatedClass.getAnnotationUsage( jakarta.persistence.Table.class ); + table = tableAnnotation.getString( "name" ); + schema = tableAnnotation.getString( "schema" ); + catalog = tableAnnotation.getString( "catalog" ); + uniqueConstraints = tableAnnotation.getList( "uniqueConstraints" ); } else { //might be no @Table annotation on the annotated class schema = ""; table = ""; catalog = ""; - uniqueConstraints = new UniqueConstraint[0]; + uniqueConstraints = Collections.emptyList(); } if ( inheritanceState.hasTable() ) { @@ -792,16 +800,16 @@ public class EntityBinder { String schema, String table, String catalog, - UniqueConstraint[] uniqueConstraints) { - final RowId rowId = annotatedClass.getAnnotation( RowId.class ); - final View view = annotatedClass.getAnnotation( View.class ); + List> uniqueConstraints) { + final AnnotationUsage rowId = annotatedClass.getAnnotationUsage( RowId.class ); + final AnnotationUsage view = annotatedClass.getAnnotationUsage( View.class ); bindTable( schema, catalog, table, uniqueConstraints, - rowId == null ? null : rowId.value(), - view == null ? null : view.query(), + rowId == null ? null : rowId.getString( "value" ), + view == null ? null : view.getString( "query" ), inheritanceState.hasDenormalizedTable() ? context.getMetadataCollector().getEntityTableXref( superEntity.getEntityName() ) : null @@ -832,15 +840,16 @@ public class EntityBinder { bindDiscriminatorValue(); if ( !isJoinedSubclass ) { - checkNoJoinColumns(); - checkNoOnDelete(); + checkNoJoinColumns( annotatedClass ); + checkNoOnDelete( annotatedClass ); } } private void singleTableInheritance(InheritanceState inheritanceState, PropertyHolder holder) { final AnnotatedDiscriminatorColumn discriminatorColumn = processSingleTableDiscriminatorProperties( inheritanceState ); - if ( !inheritanceState.hasParents() ) { // todo : sucks that this is separate from RootClass distinction + // todo : sucks that this is separate from RootClass distinction + if ( !inheritanceState.hasParents() ) { final RootClass rootClass = (RootClass) persistentClass; if ( inheritanceState.hasSiblings() || discriminatorColumn != null && !discriminatorColumn.isImplicit() ) { @@ -859,8 +868,8 @@ public class EntityBinder { final DependantValue key = new DependantValue( context, jsc.getTable(), jsc.getIdentifier() ); jsc.setKey( key ); handleForeignKeys( annotatedClass, context, key ); - final OnDelete onDelete = annotatedClass.getAnnotation( OnDelete.class ); - key.setOnDeleteAction( onDelete == null ? null : onDelete.action() ); + final AnnotationUsage onDelete = annotatedClass.getAnnotationUsage( OnDelete.class ); + key.setOnDeleteAction( onDelete == null ? null : onDelete.getEnum( "action" ) ); //we are never in a second pass at that stage, so queue it context.getMetadataCollector() .addSecondPass( new JoinedSubclassFkSecondPass( jsc, joinColumns, key, context) ); @@ -886,54 +895,56 @@ public class EntityBinder { } } - private void checkNoJoinColumns() { - if ( annotatedClass.isAnnotationPresent( PrimaryKeyJoinColumns.class ) - || annotatedClass.isAnnotationPresent( PrimaryKeyJoinColumn.class ) ) { + private void checkNoJoinColumns(ClassDetails annotatedClass) { + if ( annotatedClass.hasAnnotationUsage( PrimaryKeyJoinColumns.class ) + || annotatedClass.hasAnnotationUsage( PrimaryKeyJoinColumn.class ) ) { throw new AnnotationException( "Entity class '" + annotatedClass.getName() + "' may not specify a '@PrimaryKeyJoinColumn'" ); } } - private void checkNoOnDelete() { - if ( annotatedClass.isAnnotationPresent( OnDelete.class ) ) { - throw new AnnotationException( "Entity class '" + annotatedClass.getName() - + "' may not be annotated '@OnDelete'" ); + private static void checkNoOnDelete(ClassDetails annotatedClass) { + if ( annotatedClass.hasAnnotationUsage( PrimaryKeyJoinColumns.class ) + || annotatedClass.hasAnnotationUsage( PrimaryKeyJoinColumn.class ) ) { + throw new AnnotationException( "Entity class '" + annotatedClass.getName() + "' may not be annotated '@OnDelete'" ); } } - private static void handleForeignKeys(XClass clazzToProcess, MetadataBuildingContext context, DependantValue key) { - final PrimaryKeyJoinColumn pkJoinColumn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ); - final PrimaryKeyJoinColumns pkJoinColumns = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class ); + private static void handleForeignKeys(ClassDetails clazzToProcess, MetadataBuildingContext context, DependantValue key) { + final AnnotationUsage pkJoinColumn = clazzToProcess.getAnnotationUsage( PrimaryKeyJoinColumn.class ); + final AnnotationUsage pkJoinColumns = clazzToProcess.getAnnotationUsage( PrimaryKeyJoinColumns.class ); final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault(); - if ( pkJoinColumn != null && noConstraint( pkJoinColumn.foreignKey(), noConstraintByDefault ) - || pkJoinColumns != null && noConstraint( pkJoinColumns.foreignKey(), noConstraintByDefault ) ) { + if ( pkJoinColumn != null && noConstraint( pkJoinColumn.getNestedUsage( "foreignKey" ), noConstraintByDefault ) + || pkJoinColumns != null && noConstraint( pkJoinColumns.getNestedUsage( "foreignKey" ), noConstraintByDefault ) ) { key.disableForeignKey(); } else { - final org.hibernate.annotations.ForeignKey fk = - clazzToProcess.getAnnotation( org.hibernate.annotations.ForeignKey.class ); - if ( fk != null && isNotEmpty( fk.name() ) ) { - key.setForeignKeyName( fk.name() ); + final AnnotationUsage fk = + clazzToProcess.getAnnotationUsage( org.hibernate.annotations.ForeignKey.class ); + if ( fk != null && isNotEmpty( fk.getString( "name" ) ) ) { + key.setForeignKeyName( fk.getString( "name" ) ); } else { - final ForeignKey foreignKey = clazzToProcess.getAnnotation( ForeignKey.class ); + final AnnotationUsage foreignKey = clazzToProcess.getAnnotationUsage( ForeignKey.class ); if ( noConstraint( foreignKey, noConstraintByDefault ) ) { key.disableForeignKey(); } else if ( foreignKey != null ) { - key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) ); + key.setForeignKeyName( nullIfEmpty( foreignKey.getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( foreignKey.getString( "foreignKeyDefinition" ) ) ); } else if ( noConstraintByDefault ) { key.disableForeignKey(); } else if ( pkJoinColumns != null ) { - key.setForeignKeyName( nullIfEmpty( pkJoinColumns.foreignKey().name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( pkJoinColumns.foreignKey().foreignKeyDefinition() ) ); + final AnnotationUsage nestedFk = pkJoinColumns.getNestedUsage( "foreignKey" ); + key.setForeignKeyName( nullIfEmpty( nestedFk.getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( nestedFk.getString( "foreignKeyDefinition" ) ) ); } else if ( pkJoinColumn != null ) { - key.setForeignKeyName( nullIfEmpty( pkJoinColumn.foreignKey().name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( pkJoinColumn.foreignKey().foreignKeyDefinition() ) ); + final AnnotationUsage nestedFk = pkJoinColumn.getNestedUsage( "foreignKey" ); + key.setForeignKeyName( nullIfEmpty( nestedFk.getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( nestedFk.getString( "foreignKeyDefinition" ) ) ); } } } @@ -971,13 +982,10 @@ public class EntityBinder { * Process all discriminator-related metadata per rules for "single table" inheritance */ private AnnotatedDiscriminatorColumn processSingleTableDiscriminatorProperties(InheritanceState inheritanceState) { + final AnnotationUsage discriminatorColumn = annotatedClass.getAnnotationUsage( DiscriminatorColumn.class ); + final AnnotationUsage discriminatorFormula = getOverridableAnnotation( annotatedClass, DiscriminatorFormula.class, context ); - final DiscriminatorColumn discriminatorColumn = annotatedClass.getAnnotation( DiscriminatorColumn.class ); - - final DiscriminatorFormula discriminatorFormula = - getOverridableAnnotation( annotatedClass, DiscriminatorFormula.class, context ); - - if ( !inheritanceState.hasParents() || annotatedClass.isAnnotationPresent( Inheritance.class ) ) { + if ( !inheritanceState.hasParents() || annotatedClass.hasAnnotationUsage( Inheritance.class ) ) { return buildDiscriminatorColumn( discriminatorColumn, discriminatorFormula, @@ -1006,13 +1014,13 @@ public class EntityBinder { * and {@value AvailableSettings#IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS}. */ private AnnotatedDiscriminatorColumn processJoinedDiscriminatorProperties(InheritanceState inheritanceState) { - if ( annotatedClass.isAnnotationPresent( DiscriminatorFormula.class ) ) { + if ( annotatedClass.hasAnnotationUsage( DiscriminatorFormula.class ) ) { throw new AnnotationException( "Entity class '" + annotatedClass.getName() + "' has 'JOINED' inheritance and is annotated '@DiscriminatorFormula'" ); } - final DiscriminatorColumn discriminatorColumn = annotatedClass.getAnnotation( DiscriminatorColumn.class ); - if ( !inheritanceState.hasParents() || annotatedClass.isAnnotationPresent( Inheritance.class ) ) { + final AnnotationUsage discriminatorColumn = annotatedClass.getAnnotationUsage( DiscriminatorColumn.class ); + if ( !inheritanceState.hasParents() || annotatedClass.hasAnnotationUsage( Inheritance.class ) ) { return useDiscriminatorColumnForJoined( discriminatorColumn ) ? buildDiscriminatorColumn( discriminatorColumn, null, null, DEFAULT_DISCRIMINATOR_COLUMN_NAME, context ) : null; @@ -1036,7 +1044,7 @@ public class EntityBinder { * implicitly via {@value AvailableSettings#IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS}. *
*/ - private boolean useDiscriminatorColumnForJoined(DiscriminatorColumn discriminatorColumn) { + private boolean useDiscriminatorColumnForJoined(AnnotationUsage discriminatorColumn) { if ( discriminatorColumn != null ) { boolean ignore = context.getBuildingOptions().ignoreExplicitDiscriminatorsForJoinedInheritance(); if ( ignore ) { @@ -1061,13 +1069,13 @@ public class EntityBinder { Map generators, Set idPropertiesIfIdClass, ElementsToProcess elementsToProcess, - Map inheritanceStates) { + Map inheritanceStates) { final Set missingIdProperties = new HashSet<>( idPropertiesIfIdClass ); final Set missingEntityProperties = new HashSet<>(); for ( PropertyData propertyAnnotatedElement : elementsToProcess.getElements() ) { final String propertyName = propertyAnnotatedElement.getPropertyName(); if ( !idPropertiesIfIdClass.contains( propertyName ) ) { - final XProperty property = propertyAnnotatedElement.getProperty(); + final MemberDetails property = propertyAnnotatedElement.getAttributeMember(); boolean hasIdAnnotation = hasIdAnnotation( property ); if ( !idPropertiesIfIdClass.isEmpty() && !isIgnoreIdAnnotations() && hasIdAnnotation ) { @@ -1077,7 +1085,7 @@ public class EntityBinder { boolean subclassAndSingleTableStrategy = inheritanceState.getType() == SINGLE_TABLE && inheritanceState.hasParents(); - if ( !hasIdAnnotation && property.isAnnotationPresent( GeneratedValue.class ) ) { + if ( !hasIdAnnotation && property.hasAnnotationUsage( GeneratedValue.class ) ) { throw new AnnotationException( "Property '" + BinderHelper.getPath( propertyHolder, propertyAnnotatedElement ) @@ -1150,17 +1158,18 @@ public class EntityBinder { } private static AnnotatedJoinColumns subclassJoinColumns( - XClass clazzToProcess, + ClassDetails clazzToProcess, PersistentClass superEntity, MetadataBuildingContext context) { //@Inheritance(JOINED) subclass need to link back to the super entity final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); joinColumns.setBuildingContext( context ); - final PrimaryKeyJoinColumns primaryKeyJoinColumns = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class ); + + final AnnotationUsage primaryKeyJoinColumns = clazzToProcess.getAnnotationUsage( PrimaryKeyJoinColumns.class ); if ( primaryKeyJoinColumns != null ) { - final PrimaryKeyJoinColumn[] columns = primaryKeyJoinColumns.value(); - if ( columns.length > 0 ) { - for ( PrimaryKeyJoinColumn column : columns ) { + final List> columns = primaryKeyJoinColumns.getList( "value" ); + if ( !columns.isEmpty() ) { + for ( AnnotationUsage column : columns ) { buildInheritanceJoinColumn( column, null, @@ -1171,8 +1180,9 @@ public class EntityBinder { } } else { + final AnnotationUsage columnAnnotation = clazzToProcess.getAnnotationUsage( PrimaryKeyJoinColumn.class ); buildInheritanceJoinColumn( - clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ), + columnAnnotation, null, superEntity.getIdentifier(), joinColumns, @@ -1182,7 +1192,7 @@ public class EntityBinder { } else { buildInheritanceJoinColumn( - clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ), + clazzToProcess.getAnnotationUsage( PrimaryKeyJoinColumn.class ), null, superEntity.getIdentifier(), joinColumns, @@ -1194,8 +1204,8 @@ public class EntityBinder { } private static PersistentClass getSuperEntity( - XClass clazzToProcess, - Map inheritanceStates, + ClassDetails clazzToProcess, + Map inheritanceStates, MetadataBuildingContext context, InheritanceState inheritanceState) { final InheritanceState superState = getInheritanceStateOfSuperEntity( clazzToProcess, inheritanceStates ); @@ -1204,17 +1214,17 @@ public class EntityBinder { } else { final PersistentClass superEntity = context.getMetadataCollector() - .getEntityBinding( superState.getClazz().getName() ); + .getEntityBinding( superState.getClassDetails().getName() ); //check if superclass is not a potential persistent class if ( superEntity == null && inheritanceState.hasParents() ) { throw new AssertionFailure( "Subclass has to be bound after its parent class: " - + superState.getClazz().getName() ); + + superState.getClassDetails().getName() ); } return superEntity; } } - private static void bindCallbacks(XClass entityClass, PersistentClass persistentClass, MetadataBuildingContext context) { + private static void bindCallbacks(ClassDetails entityClass, PersistentClass persistentClass, MetadataBuildingContext context) { final ReflectionManager reflection = context.getBootstrapContext().getReflectionManager(); for ( CallbackType callbackType : CallbackType.values() ) { persistentClass.addCallbackDefinitions( resolveEntityCallbacks( reflection, entityClass, callbackType ) ); @@ -1241,7 +1251,7 @@ public class EntityBinder { public EntityBinder() { } - public EntityBinder(XClass annotatedClass, PersistentClass persistentClass, MetadataBuildingContext context) { + public EntityBinder(ClassDetails annotatedClass, PersistentClass persistentClass, MetadataBuildingContext context) { this.context = context; this.persistentClass = persistentClass; this.annotatedClass = annotatedClass; @@ -1263,40 +1273,40 @@ public class EntityBinder { } private void bindRowManagement() { - final DynamicInsert dynamicInsertAnn = annotatedClass.getAnnotation( DynamicInsert.class ); - persistentClass.setDynamicInsert( dynamicInsertAnn != null && dynamicInsertAnn.value() ); - final DynamicUpdate dynamicUpdateAnn = annotatedClass.getAnnotation( DynamicUpdate.class ); - persistentClass.setDynamicUpdate( dynamicUpdateAnn != null && dynamicUpdateAnn.value() ); + final AnnotationUsage dynamicInsertAnn = annotatedClass.getAnnotationUsage( DynamicInsert.class ); + persistentClass.setDynamicInsert( dynamicInsertAnn != null && dynamicInsertAnn.getBoolean( "value" ) ); + final AnnotationUsage dynamicUpdateAnn = annotatedClass.getAnnotationUsage( DynamicUpdate.class ); + persistentClass.setDynamicUpdate( dynamicUpdateAnn != null && dynamicUpdateAnn.getBoolean( "value" ) ); - if ( persistentClass.useDynamicInsert() && annotatedClass.isAnnotationPresent( SQLInsert.class ) ) { + if ( persistentClass.useDynamicInsert() && annotatedClass.hasAnnotationUsage( SQLInsert.class ) ) { throw new AnnotationException( "Entity '" + name + "' is annotated both '@DynamicInsert' and '@SQLInsert'" ); } - if ( persistentClass.useDynamicUpdate() && annotatedClass.isAnnotationPresent( SQLUpdate.class ) ) { + if ( persistentClass.useDynamicUpdate() && annotatedClass.hasAnnotationUsage( SQLUpdate.class ) ) { throw new AnnotationException( "Entity '" + name + "' is annotated both '@DynamicUpdate' and '@SQLUpdate'" ); } - final SelectBeforeUpdate selectBeforeUpdateAnn = annotatedClass.getAnnotation( SelectBeforeUpdate.class ); - persistentClass.setSelectBeforeUpdate( selectBeforeUpdateAnn != null && selectBeforeUpdateAnn.value() ); + final AnnotationUsage selectBeforeUpdateAnn = annotatedClass.getAnnotationUsage( SelectBeforeUpdate.class ); + persistentClass.setSelectBeforeUpdate( selectBeforeUpdateAnn != null && selectBeforeUpdateAnn.getBoolean( "value" ) ); } private void bindOptimisticLocking() { - final OptimisticLocking optimisticLockingAnn = annotatedClass.getAnnotation( OptimisticLocking.class ); + final AnnotationUsage optimisticLockingAnn = annotatedClass.getAnnotationUsage( OptimisticLocking.class ); persistentClass.setOptimisticLockStyle( fromLockType( optimisticLockingAnn == null ? OptimisticLockType.VERSION - : optimisticLockingAnn.type() ) ); + : optimisticLockingAnn.getEnum( "type" ) ) ); } private void bindPolymorphism() { - final Polymorphism polymorphismAnn = annotatedClass.getAnnotation( Polymorphism.class ); - polymorphismType = polymorphismAnn == null ? IMPLICIT : polymorphismAnn.type(); + final AnnotationUsage polymorphismAnn = annotatedClass.getAnnotationUsage( Polymorphism.class ); + polymorphismType = polymorphismAnn == null ? IMPLICIT : polymorphismAnn.getEnum( "type" ); } private void bindEntityAnnotation() { - final Entity entity = annotatedClass.getAnnotation( Entity.class ); + final AnnotationUsage entity = annotatedClass.getAnnotationUsage( Entity.class ); if ( entity == null ) { throw new AssertionFailure( "@Entity should never be missing" ); } - final String entityName = entity.name(); + final String entityName = entity.getString( "name" ); name = entityName.isEmpty() ? unqualify( annotatedClass.getName() ) : entityName; } @@ -1340,7 +1350,6 @@ public class EntityBinder { ensureNoMutabilityPlan(); - bindCustomPersister(); bindCustomLoader(); registerImportName(); @@ -1349,13 +1358,13 @@ public class EntityBinder { } private void ensureNoMutabilityPlan() { - if ( annotatedClass.isAnnotationPresent( Mutability.class ) ) { + if ( annotatedClass.hasAnnotationUsage( Mutability.class ) ) { throw new MappingException( "@Mutability is not allowed on entity" ); } } private boolean isMutable() { - return !annotatedClass.isAnnotationPresent(Immutable.class); + return !annotatedClass.hasAnnotationUsage(Immutable.class); } private void registerImportName() { @@ -1390,65 +1399,68 @@ public class EntityBinder { private void bindCustomSql() { final String primaryTableName = persistentClass.getTable().getName(); - SQLInsert sqlInsert = findMatchingSqlAnnotation( primaryTableName, SQLInsert.class, SQLInserts.class ); + AnnotationUsage sqlInsert = findMatchingSqlAnnotation( primaryTableName, SQLInsert.class, SQLInserts.class ); if ( sqlInsert == null ) { sqlInsert = findMatchingSqlAnnotation( "", SQLInsert.class, SQLInserts.class ); } if ( sqlInsert != null ) { persistentClass.setCustomSQLInsert( - sqlInsert.sql().trim(), - sqlInsert.callable(), - fromResultCheckStyle( sqlInsert.check() ) + sqlInsert.getString( "sql" ).trim(), + sqlInsert.getBoolean( "callable" ), + fromResultCheckStyle( sqlInsert.getEnum( "check" ) ) ); - if ( sqlInsert.verify() != Expectation.class ) { - persistentClass.setInsertExpectation( getDefaultSupplier( sqlInsert.verify() ) ); + final Class expectationClass = sqlInsert.getClassDetails("verify").toJavaClass(); + if ( expectationClass != Expectation.class ) { + persistentClass.setInsertExpectation( getDefaultSupplier( expectationClass ) ); } } - SQLUpdate sqlUpdate = findMatchingSqlAnnotation( primaryTableName, SQLUpdate.class, SQLUpdates.class ); + AnnotationUsage sqlUpdate = findMatchingSqlAnnotation( primaryTableName, SQLUpdate.class, SQLUpdates.class ); if ( sqlUpdate == null ) { sqlUpdate = findMatchingSqlAnnotation( "", SQLUpdate.class, SQLUpdates.class ); } if ( sqlUpdate != null ) { persistentClass.setCustomSQLUpdate( - sqlUpdate.sql().trim(), - sqlUpdate.callable(), - fromResultCheckStyle( sqlUpdate.check() ) + sqlUpdate.getString( "sql" ).trim(), + sqlUpdate.getBoolean( "callable" ), + fromResultCheckStyle( sqlUpdate.getEnum( "check" ) ) ); - if ( sqlUpdate.verify() != Expectation.class ) { - persistentClass.setUpdateExpectation( getDefaultSupplier( sqlUpdate.verify() ) ); + final Class expectationClass = sqlUpdate.getClassDetails("verify").toJavaClass(); + if ( expectationClass != Expectation.class ) { + persistentClass.setUpdateExpectation( getDefaultSupplier( expectationClass ) ); } } - SQLDelete sqlDelete = findMatchingSqlAnnotation( primaryTableName, SQLDelete.class, SQLDeletes.class ); + AnnotationUsage sqlDelete = findMatchingSqlAnnotation( primaryTableName, SQLDelete.class, SQLDeletes.class ); if ( sqlDelete == null ) { sqlDelete = findMatchingSqlAnnotation( "", SQLDelete.class, SQLDeletes.class ); } if ( sqlDelete != null ) { persistentClass.setCustomSQLDelete( - sqlDelete.sql().trim(), - sqlDelete.callable(), - fromResultCheckStyle( sqlDelete.check() ) + sqlDelete.getString( "sql" ).trim(), + sqlDelete.getBoolean( "callable" ), + fromResultCheckStyle( sqlDelete.getEnum( "check" ) ) ); - if ( sqlDelete.verify() != Expectation.class ) { - persistentClass.setDeleteExpectation( getDefaultSupplier( sqlDelete.verify() ) ); + final Class expectationClass = sqlDelete.getClassDetails("verify").toJavaClass(); + if ( expectationClass != Expectation.class ) { + persistentClass.setDeleteExpectation( getDefaultSupplier( expectationClass ) ); } } - final SQLDeleteAll sqlDeleteAll = annotatedClass.getAnnotation( SQLDeleteAll.class ); + final AnnotationUsage sqlDeleteAll = annotatedClass.getAnnotationUsage( SQLDeleteAll.class ); if ( sqlDeleteAll != null ) { throw new AnnotationException("@SQLDeleteAll does not apply to entities: " + persistentClass.getEntityName()); } - final SQLSelect sqlSelect = getOverridableAnnotation( annotatedClass, SQLSelect.class, context ); + final AnnotationUsage sqlSelect = getOverridableAnnotation( annotatedClass, SQLSelect.class, context ); if ( sqlSelect != null ) { final String loaderName = persistentClass.getEntityName() + "$SQLSelect"; persistentClass.setLoaderName( loaderName ); QueryBinder.bindNativeQuery( loaderName, sqlSelect, annotatedClass, context ); } - final HQLSelect hqlSelect = annotatedClass.getAnnotation( HQLSelect.class ); + final AnnotationUsage hqlSelect = annotatedClass.getAnnotationUsage( HQLSelect.class ); if ( hqlSelect != null ) { final String loaderName = persistentClass.getEntityName() + "$HQLSelect"; persistentClass.setLoaderName( loaderName ); @@ -1457,31 +1469,32 @@ public class EntityBinder { } private void bindCustomLoader() { - final Loader loader = annotatedClass.getAnnotation( Loader.class ); + final AnnotationUsage loader = annotatedClass.getAnnotationUsage( Loader.class ); if ( loader != null ) { - persistentClass.setLoaderName( loader.namedQuery() ); + persistentClass.setLoaderName( loader.getString( "namedQuery" ) ); } } private void bindSubselect() { - final Subselect subselect = annotatedClass.getAnnotation( Subselect.class ); + final AnnotationUsage subselect = annotatedClass.getAnnotationUsage( Subselect.class ); if ( subselect != null ) { - this.subselect = subselect.value(); + this.subselect = subselect.getString( "value" ); } } private void bindFilters() { - for ( Filter filter : filters ) { - String condition = filter.condition(); + for ( AnnotationUsage filter : filters ) { + final String filterName = filter.getString( "name" ); + String condition = filter.getString( "condition" ); if ( condition.isEmpty() ) { - condition = getDefaultFilterCondition( filter.name() ); + condition = getDefaultFilterCondition( filterName ); } persistentClass.addFilter( - filter.name(), + filterName, condition, - filter.deduceAliasInjectionPoints(), - toAliasTableMap( filter.aliases() ), - toAliasEntityMap( filter.aliases() ) + filter.getBoolean( "deduceAliasInjectionPoints" ), + toAliasTableMap( filter.getList( "aliases" ) ), + toAliasEntityMap( filter.getList( "aliases" ) ) ); } } @@ -1502,12 +1515,13 @@ public class EntityBinder { } private void bindSynchronize() { - if ( annotatedClass.isAnnotationPresent( Synchronize.class ) ) { - final JdbcEnvironment jdbcEnvironment = - context.getMetadataCollector().getDatabase().getJdbcEnvironment(); - final Synchronize synchronize = annotatedClass.getAnnotation(Synchronize.class); - for ( String table : synchronize.value() ) { - String physicalName = synchronize.logical() ? toPhysicalName( jdbcEnvironment, table ) : table; + if ( annotatedClass.hasAnnotationUsage( Synchronize.class ) ) { + final JdbcEnvironment jdbcEnvironment = context.getMetadataCollector().getDatabase().getJdbcEnvironment(); + final AnnotationUsage synchronize = annotatedClass.getAnnotationUsage( Synchronize.class); + final boolean logical = synchronize.getBoolean( "logical" ); + final List tableNames = synchronize.getList( "value" ); + for ( String tableName : tableNames ) { + String physicalName = logical ? toPhysicalName( jdbcEnvironment, tableName ) : tableName; persistentClass.addSynchronizedTable( physicalName ); } } @@ -1521,46 +1535,26 @@ public class EntityBinder { .render( jdbcEnvironment.getDialect() ); } - @SuppressWarnings({"rawtypes", "unchecked"}) - private void bindCustomPersister() { - //set persister if needed - final Persister persisterAnn = annotatedClass.getAnnotation( Persister.class ); - if ( persisterAnn != null ) { - Class clazz = persisterAnn.impl(); - if ( !EntityPersister.class.isAssignableFrom(clazz) ) { - throw new AnnotationException( "Persister class '" + clazz.getName() - + "' does not implement 'EntityPersister'" ); - } - persistentClass.setEntityPersisterClass( clazz ); - } - } - public PersistentClass getPersistentClass() { return persistentClass; } private void processNamedEntityGraphs() { - processNamedEntityGraph( annotatedClass.getAnnotation( NamedEntityGraph.class ) ); - final NamedEntityGraphs graphs = annotatedClass.getAnnotation( NamedEntityGraphs.class ); - if ( graphs != null ) { - for ( NamedEntityGraph graph : graphs.value() ) { - processNamedEntityGraph( graph ); - } - } + annotatedClass.forEachAnnotationUsage( NamedEntityGraph.class, this::processNamedEntityGraph ); } - private void processNamedEntityGraph(NamedEntityGraph annotation) { + private void processNamedEntityGraph(AnnotationUsage annotation) { if ( annotation == null ) { return; } context.getMetadataCollector().addNamedEntityGraph( - new NamedEntityGraphDefinition( annotation, name, persistentClass.getEntityName() ) + new NamedEntityGraphDefinition( annotation.toAnnotation(), name, persistentClass.getEntityName() ) ); } public void bindDiscriminatorValue() { - final String discriminatorValue = annotatedClass.isAnnotationPresent( DiscriminatorValue.class ) - ? annotatedClass.getAnnotation( DiscriminatorValue.class ).value() + final String discriminatorValue = annotatedClass.hasAnnotationUsage( DiscriminatorValue.class ) + ? annotatedClass.getAnnotationUsage( DiscriminatorValue.class ).getString( "value" ) : null; if ( isEmpty( discriminatorValue ) ) { final Value discriminator = persistentClass.getDiscriminator(); @@ -1584,26 +1578,21 @@ public class EntityBinder { } public void bindProxy() { - final Proxy proxy = annotatedClass.getAnnotation( Proxy.class ); + final AnnotationUsage proxy = annotatedClass.getAnnotationUsage( Proxy.class ); if ( proxy != null ) { - lazy = proxy.lazy(); - proxyClass = lazy ? proxyClass( proxy ) : null; + lazy = proxy.getBoolean( "lazy" ); + proxyClass = lazy ? proxy.getClassDetails( "proxyClass" ) : null; } else { - lazy = true; //needed to allow association lazy loading. + //needed to allow association lazy loading. + lazy = true; proxyClass = annotatedClass; } } - private XClass proxyClass(Proxy proxy) { - final ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager(); - final XClass proxyClass = reflectionManager.toXClass( proxy.proxyClass() ); - return isDefault( proxyClass, context ) ? annotatedClass : proxyClass; - } - public void bindConcreteProxy() { - final ConcreteProxy concreteProxy = annotatedClass.getAnnotation( ConcreteProxy.class ); - if ( concreteProxy != null ) { + final AnnotationUsage annotationUsage = annotatedClass.getAnnotationUsage( ConcreteProxy.class ); + if ( annotationUsage != null ) { if ( persistentClass.getSuperclass() != null ) { throw new AnnotationException( "Entity class '" + persistentClass.getClassName() + "' is annotated '@ConcreteProxy' but it is not the root of the entity inheritance hierarchy" ); @@ -1613,13 +1602,13 @@ public class EntityBinder { } public void bindWhere() { - final Where where = getOverridableAnnotation( annotatedClass, Where.class, context ); + final AnnotationUsage where = getOverridableAnnotation( annotatedClass, Where.class, context ); if ( where != null ) { - this.where = where.clause(); + this.where = where.getString( "clause" ); } - final SQLRestriction restriction = getOverridableAnnotation( annotatedClass, SQLRestriction.class, context ); + final AnnotationUsage restriction = getOverridableAnnotation( annotatedClass, SQLRestriction.class, context ); if ( restriction != null ) { - this.where = restriction.value(); + this.where = restriction.getString( "value" ); } } @@ -1629,17 +1618,21 @@ public class EntityBinder { private void bindNaturalIdCache() { naturalIdCacheRegion = null; - final NaturalIdCache naturalIdCacheAnn = annotatedClass.getAnnotation( NaturalIdCache.class ); - if ( naturalIdCacheAnn != null ) { - if ( naturalIdCacheAnn.region().isEmpty() ) { - final Cache explicitCacheAnn = annotatedClass.getAnnotation( Cache.class ); - naturalIdCacheRegion = explicitCacheAnn != null && isNotEmpty( explicitCacheAnn.region() ) - ? explicitCacheAnn.region() + NATURAL_ID_CACHE_SUFFIX - : annotatedClass.getName() + NATURAL_ID_CACHE_SUFFIX; - } - else { - naturalIdCacheRegion = naturalIdCacheAnn.region(); - } + final AnnotationUsage naturalIdCacheAnn = annotatedClass.getAnnotationUsage( NaturalIdCache.class ); + if ( naturalIdCacheAnn == null ) { + return; + } + + final String region = naturalIdCacheAnn.getString( "region" ); + if ( region.isEmpty() ) { + final AnnotationUsage explicitCacheAnn = annotatedClass.getAnnotationUsage( Cache.class ); + + naturalIdCacheRegion = explicitCacheAnn != null && isNotEmpty( explicitCacheAnn.getString( "region") ) + ? explicitCacheAnn.getString( "region") + NATURAL_ID_CACHE_SUFFIX + : annotatedClass.getName() + NATURAL_ID_CACHE_SUFFIX; + } + else { + naturalIdCacheRegion = naturalIdCacheAnn.getString( "region" ); } } @@ -1659,7 +1652,7 @@ public class EntityBinder { } private void bindSubclassCache(SharedCacheMode sharedCacheMode) { - if ( annotatedClass.isAnnotationPresent( Cache.class ) ) { + if ( annotatedClass.hasAnnotationUsage( Cache.class ) ) { final String className = persistentClass.getClassName() == null ? annotatedClass.getName() : persistentClass.getClassName(); @@ -1668,7 +1661,7 @@ public class EntityBinder { +" (only root classes may define second-level caching semantics)"); } - final Cacheable cacheable = annotatedClass.getAnnotation( Cacheable.class ); + final AnnotationUsage cacheable = annotatedClass.getAnnotationUsage( Cacheable.class ); isCached = cacheable == null && persistentClass.getSuperclass() != null // we should inherit the root class caching config ? persistentClass.getSuperclass().isCached() @@ -1678,57 +1671,55 @@ public class EntityBinder { } private void bindRootClassCache(SharedCacheMode sharedCacheMode, MetadataBuildingContext context) { - final Cache cache = annotatedClass.getAnnotation( Cache.class ); - final Cacheable cacheable = annotatedClass.getAnnotation( Cacheable.class ); - final Cache effectiveCache; + final AnnotationUsage cache = annotatedClass.getAnnotationUsage( Cache.class ); + final AnnotationUsage cacheable = annotatedClass.getAnnotationUsage( Cacheable.class ); + final AnnotationUsage effectiveCache; if ( cache != null ) { // preserve legacy behavior of circumventing SharedCacheMode when Hibernate's @Cache is used. isCached = true; effectiveCache = cache; } else { - effectiveCache = buildCacheMock( annotatedClass.getName(), context ); + effectiveCache = buildCacheMock( annotatedClass, context ); isCached = isCacheable( sharedCacheMode, cacheable ); } - cacheConcurrentStrategy = resolveCacheConcurrencyStrategy( effectiveCache.usage() ); - cacheRegion = effectiveCache.region(); + cacheConcurrentStrategy = resolveCacheConcurrencyStrategy( effectiveCache.getEnum( "usage" ) ); + cacheRegion = effectiveCache.getString( "region" ); cacheLazyProperty = isCacheLazy( effectiveCache, annotatedClass ); - final QueryCacheLayout queryCache = annotatedClass.getAnnotation( QueryCacheLayout.class ); - queryCacheLayout = queryCache == null ? null : queryCache.layout(); + final AnnotationUsage queryCache = annotatedClass.getAnnotationUsage( QueryCacheLayout.class ); + queryCacheLayout = queryCache == null ? null : queryCache.getEnum( "layout" ); } - private static boolean isCacheLazy(Cache effectiveCache, XClass annotatedClass) { - if ( !effectiveCache.includeLazy() ) { + private static boolean isCacheLazy(AnnotationUsage effectiveCache, ClassDetails annotatedClass) { + if ( !effectiveCache.getBoolean( "includeLazy" ) ) { return false; } - switch ( effectiveCache.include().toLowerCase( Locale.ROOT ) ) { - case "all": - return true; - case "non-lazy": - return false; - default: - throw new AnnotationException( "Class '" + annotatedClass.getName() - + "' has a '@Cache' with undefined option 'include=\"" + effectiveCache.include() + "\"'" ); - } + return switch ( effectiveCache.getString( "include" ).toLowerCase( Locale.ROOT ) ) { + case "all" -> true; + case "non-lazy" -> false; + default -> throw new AnnotationException( + "Class '" + annotatedClass.getName() + + "' has a '@Cache' with undefined option 'include=\"" + effectiveCache.getString( "include" ) + "\"'" ); + }; } - private static boolean isCacheable(SharedCacheMode sharedCacheMode, Cacheable explicitCacheableAnn) { - switch ( sharedCacheMode ) { - case ALL: + private static boolean isCacheable(SharedCacheMode sharedCacheMode, AnnotationUsage explicitCacheableAnn) { + return switch ( sharedCacheMode ) { + case ALL -> // all entities should be cached - return true; - case ENABLE_SELECTIVE: - case UNSPECIFIED: // Hibernate defaults to ENABLE_SELECTIVE, the only sensible setting + true; + case ENABLE_SELECTIVE, UNSPECIFIED -> + // Hibernate defaults to ENABLE_SELECTIVE, the only sensible setting // only entities with @Cacheable(true) should be cached - return explicitCacheableAnn != null && explicitCacheableAnn.value(); - case DISABLE_SELECTIVE: + explicitCacheableAnn != null && explicitCacheableAnn.getBoolean( "value" ); + case DISABLE_SELECTIVE -> // only entities with @Cacheable(false) should not be cached - return explicitCacheableAnn == null || explicitCacheableAnn.value(); - default: + explicitCacheableAnn == null || explicitCacheableAnn.getBoolean( "value" ); + default -> // treat both NONE and UNSPECIFIED the same - return false; - } + false; + }; } private static String resolveCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) { @@ -1736,44 +1727,14 @@ public class EntityBinder { return accessType == null ? null : accessType.getExternalName(); } - private static Cache buildCacheMock(String region, MetadataBuildingContext context) { - return new LocalCacheAnnotationStub( region, determineCacheConcurrencyStrategy( context ) ); - } - - @SuppressWarnings("ClassExplicitlyAnnotation") - private static class LocalCacheAnnotationStub implements Cache { - private final String region; - private final CacheConcurrencyStrategy usage; - - private LocalCacheAnnotationStub(String region, CacheConcurrencyStrategy usage) { - this.region = region; - this.usage = usage; - } - - @Override - public CacheConcurrencyStrategy usage() { - return usage; - } - - @Override - public String region() { - return region; - } - - @Override - public boolean includeLazy() { - return true; - } - - @Override - public String include() { - return "all"; - } - - @Override - public Class annotationType() { - return Cache.class; - } + private static AnnotationUsage buildCacheMock(ClassDetails classDetails, MetadataBuildingContext context) { + final MutableAnnotationUsage cacheUsage = HibernateAnnotations.CACHE.createUsage( + classDetails, + context.getMetadataCollector().getSourceModelBuildingContext() + ); + cacheUsage.setAttributeValue( "region", classDetails.getName() ); + cacheUsage.setAttributeValue( "usage", determineCacheConcurrencyStrategy( context ) ); + return cacheUsage; } private static CacheConcurrencyStrategy determineCacheConcurrencyStrategy(MetadataBuildingContext context) { @@ -1866,7 +1827,7 @@ public class EntityBinder { String schema, String catalog, String tableName, - UniqueConstraint[] uniqueConstraints, + List> uniqueConstraints, String rowId, String viewQuery, InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) { @@ -1934,18 +1895,43 @@ public class EntityBinder { } private void createPrimaryColumnsToSecondaryTable(Object column, PropertyHolder propertyHolder, Join join) { - final PrimaryKeyJoinColumn[] pkColumnsAnn = - column instanceof PrimaryKeyJoinColumn[] - ? (PrimaryKeyJoinColumn[]) column - : null; - final JoinColumn[] joinColumnsAnn = - column instanceof JoinColumn[] - ? (JoinColumn[]) column - : null; - final AnnotatedJoinColumns annotatedJoinColumns = - pkColumnsAnn == null && joinColumnsAnn == null - ? createDefaultJoinColumn( propertyHolder ) - : createJoinColumns( propertyHolder, pkColumnsAnn, joinColumnsAnn ); + // `column` will be a list of some sort... + //noinspection unchecked,rawtypes + final List joinColumnSource = (List) column; + final AnnotatedJoinColumns annotatedJoinColumns; + + if ( CollectionHelper.isEmpty( joinColumnSource ) ) { + annotatedJoinColumns = createDefaultJoinColumn( propertyHolder ); + } + else { + final List> pkJoinColumns; + final List> joinColumns; + + //noinspection rawtypes + final AnnotationUsage first = joinColumnSource.get( 0 ); + if ( first.getAnnotationDescriptor().getAnnotationType() + .equals( PrimaryKeyJoinColumn.class ) ) { + //noinspection unchecked,rawtypes + pkJoinColumns = (List) joinColumnSource; + joinColumns = null; + } + else if ( first.getAnnotationDescriptor().getAnnotationType() + .equals( JoinColumn.class ) ) { + pkJoinColumns = null; + //noinspection unchecked,rawtypes + joinColumns = (List) joinColumnSource; + } + else { + throw new IllegalArgumentException( + "Expecting list of AnnotationUsages for either @JoinColumn or @PrimaryKeyJoinColumn" + + ", but got as list of AnnotationUsages for @" + + first.getAnnotationDescriptor().getAnnotationType().getName() + + ); + } + + annotatedJoinColumns = createJoinColumns( propertyHolder, pkJoinColumns, joinColumns ); + } for ( AnnotatedJoinColumn joinColumn : annotatedJoinColumns.getJoinColumns() ) { joinColumn.forceNotNull(); @@ -1970,9 +1956,9 @@ public class EntityBinder { private AnnotatedJoinColumns createJoinColumns( PropertyHolder propertyHolder, - PrimaryKeyJoinColumn[] primaryKeyJoinColumns, - JoinColumn[] joinColumns) { - final int joinColumnCount = primaryKeyJoinColumns != null ? primaryKeyJoinColumns.length : joinColumns.length; + List> primaryKeyJoinColumns, + List> joinColumns) { + final int joinColumnCount = primaryKeyJoinColumns != null ? primaryKeyJoinColumns.size() : joinColumns.size(); if ( joinColumnCount == 0 ) { return createDefaultJoinColumn( propertyHolder ); } @@ -1982,9 +1968,14 @@ public class EntityBinder { columns.setJoins( secondaryTables ); columns.setPropertyHolder( propertyHolder ); for ( int colIndex = 0; colIndex < joinColumnCount; colIndex++ ) { - final PrimaryKeyJoinColumn primaryKeyJoinColumn = - primaryKeyJoinColumns != null ? primaryKeyJoinColumns[colIndex] : null; - final JoinColumn joinColumn = joinColumns != null ? joinColumns[colIndex] : null; + final AnnotationUsage primaryKeyJoinColumn = + primaryKeyJoinColumns != null + ? primaryKeyJoinColumns.get( colIndex) + : null; + final AnnotationUsage joinColumn = + joinColumns != null + ? joinColumns.get(colIndex) + : null; buildInheritanceJoinColumn( primaryKeyJoinColumn, joinColumn, @@ -2011,55 +2002,56 @@ public class EntityBinder { private void setForeignKeyNameIfDefined(Join join) { final String tableName = join.getTable().getQuotedName(); - final org.hibernate.annotations.Table matchingTable = findMatchingComplementaryTableAnnotation( tableName ); + final AnnotationUsage matchingTable = findMatchingComplementaryTableAnnotation( tableName ); final SimpleValue key = (SimpleValue) join.getKey(); - if ( matchingTable != null && !matchingTable.foreignKey().name().isEmpty() ) { - key.setForeignKeyName( matchingTable.foreignKey().name() ); + if ( matchingTable != null && !matchingTable.getNestedUsage( "foreignKey" ).getString( "name" ).isEmpty() ) { + key.setForeignKeyName( matchingTable.getNestedUsage( "foreignKey" ).getString( "name" ) ); } else { - final SecondaryTable jpaSecondaryTable = findMatchingSecondaryTable( join ); + final AnnotationUsage jpaSecondaryTable = findMatchingSecondaryTable( join ); if ( jpaSecondaryTable != null ) { final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault(); - if ( jpaSecondaryTable.foreignKey().value() == ConstraintMode.NO_CONSTRAINT - || jpaSecondaryTable.foreignKey().value() == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) { + if ( jpaSecondaryTable.getNestedUsage( "foreignKey" ).getEnum( "value" ) == ConstraintMode.NO_CONSTRAINT + || jpaSecondaryTable.getNestedUsage( "foreignKey" ).getEnum( "value" ) == ConstraintMode.PROVIDER_DEFAULT && noConstraintByDefault ) { key.disableForeignKey(); } else { - key.setForeignKeyName( nullIfEmpty( jpaSecondaryTable.foreignKey().name() ) ); - key.setForeignKeyDefinition( nullIfEmpty( jpaSecondaryTable.foreignKey().foreignKeyDefinition() ) ); + key.setForeignKeyName( nullIfEmpty( jpaSecondaryTable.getNestedUsage( "foreignKey" ).getString( "name" ) ) ); + key.setForeignKeyDefinition( nullIfEmpty( jpaSecondaryTable.getNestedUsage( "foreignKey" ).getString( "foreignKeyDefinition" ) ) ); } } } } - private SecondaryTable findMatchingSecondaryTable(Join join) { + private AnnotationUsage findMatchingSecondaryTable(Join join) { final String nameToMatch = join.getTable().getQuotedName(); - final SecondaryTable secondaryTable = annotatedClass.getAnnotation( SecondaryTable.class ); - if ( secondaryTable != null && nameToMatch.equals( secondaryTable.name() ) ) { + final AnnotationUsage secondaryTable = annotatedClass.getSingleAnnotationUsage( SecondaryTable.class ); + if ( secondaryTable != null && nameToMatch.equals( secondaryTable.getString( "name" ) ) ) { return secondaryTable; } - final SecondaryTables secondaryTables = annotatedClass.getAnnotation( SecondaryTables.class ); + final AnnotationUsage secondaryTables = annotatedClass.getAnnotationUsage( SecondaryTables.class ); if ( secondaryTables != null ) { - for ( SecondaryTable secondaryTablesEntry : secondaryTables.value() ) { - if ( secondaryTablesEntry != null && nameToMatch.equals( secondaryTablesEntry.name() ) ) { - return secondaryTablesEntry; + final List> nestedSecondaryTableList = secondaryTables.getList( "value" ); + for ( AnnotationUsage nestedSecondaryTable : nestedSecondaryTableList ) { + if ( nestedSecondaryTable != null && nameToMatch.equals( nestedSecondaryTable.getString( "name" ) ) ) { + return nestedSecondaryTable; } } } return null; } - private org.hibernate.annotations.Table findMatchingComplementaryTableAnnotation(String tableName) { - final org.hibernate.annotations.Table table = annotatedClass.getAnnotation( org.hibernate.annotations.Table.class ); - if ( table != null && tableName.equals( table.appliesTo() ) ) { + private AnnotationUsage findMatchingComplementaryTableAnnotation(String tableName) { + final AnnotationUsage table = annotatedClass.getSingleAnnotationUsage( org.hibernate.annotations.Table.class ); + if ( table != null && tableName.equals( table.getString( "appliesTo" ) ) ) { return table; } else { - final Tables tables = annotatedClass.getAnnotation( Tables.class ); + final AnnotationUsage tables = annotatedClass.getAnnotationUsage( Tables.class ); if ( tables != null ) { - for (org.hibernate.annotations.Table current : tables.value()) { - if ( tableName.equals( current.appliesTo() ) ) { - return current; + for (AnnotationUsage nested : tables.>getList( "value" )) { + if ( tableName.equals( nested.getString( "appliesTo" ) ) ) { + return nested; } } } @@ -2067,16 +2059,17 @@ public class EntityBinder { } } - private SecondaryRow findMatchingSecondaryRowAnnotation(String tableName) { - final SecondaryRow row = annotatedClass.getAnnotation( SecondaryRow.class ); - if ( row != null && ( row.table().isEmpty() || tableName.equals( row.table() ) ) ) { + private AnnotationUsage findMatchingSecondaryRowAnnotation(String tableName) { + final AnnotationUsage row = annotatedClass.getSingleAnnotationUsage( SecondaryRow.class ); + if ( row != null && ( row.getString( "table" ).isEmpty() || tableName.equals( row.getString( "table" ) ) ) ) { return row; } else { - final SecondaryRows tables = annotatedClass.getAnnotation( SecondaryRows.class ); + final AnnotationUsage tables = annotatedClass.getAnnotationUsage( SecondaryRows.class ); if ( tables != null ) { - for ( SecondaryRow current : tables.value() ) { - if ( tableName.equals( current.table() ) ) { + final List> rowList = tables.getList( "value" ); + for ( AnnotationUsage current : rowList ) { + if ( tableName.equals( current.getString( "table" ) ) ) { return current; } } @@ -2085,24 +2078,22 @@ public class EntityBinder { } } - private T findMatchingSqlAnnotation( + private AnnotationUsage findMatchingSqlAnnotation( String tableName, Class annotationType, Class repeatableType) { - final T sqlAnnotation = getOverridableAnnotation( annotatedClass, annotationType, context ); + final AnnotationUsage sqlAnnotation = getOverridableAnnotation( annotatedClass, annotationType, context ); if ( sqlAnnotation != null ) { - if ( tableName.equals( tableMember( annotationType, sqlAnnotation ) ) ) { + if ( tableName.equals( sqlAnnotation.getString( "table" ) ) ) { return sqlAnnotation; } } //TODO: getOverridableAnnotation() does not yet handle @Repeatable annotations - final R repeatable = annotatedClass.getAnnotation(repeatableType); + final AnnotationUsage repeatable = annotatedClass.getAnnotationUsage( repeatableType ); if ( repeatable != null ) { - for ( Annotation current : valueMember( repeatableType, repeatable ) ) { - @SuppressWarnings("unchecked") - final T sqlAnn = (T) current; - if ( tableName.equals( tableMember( annotationType, sqlAnn ) ) ) { - return sqlAnn; + for ( AnnotationUsage nested : repeatable.>getList( "value" ) ) { + if ( tableName.equals( nested.getString( "table" ) ) ) { + return nested; } } } @@ -2143,32 +2134,32 @@ public class EntityBinder { } //Used for @*ToMany @JoinTable - public Join addJoin(JoinTable joinTable, PropertyHolder holder, boolean noDelayInPkColumnCreation) { + public Join addJoinTable(AnnotationUsage joinTable, PropertyHolder holder, boolean noDelayInPkColumnCreation) { return addJoin( holder, noDelayInPkColumnCreation, false, - joinTable.name(), - joinTable.schema(), - joinTable.catalog(), - joinTable.joinColumns(), - joinTable.uniqueConstraints() + joinTable.getString( "name" ), + joinTable.getString( "schema" ), + joinTable.getString( "catalog" ), + joinTable.getList( "joinColumns" ), + joinTable.getList( "uniqueConstraints" ) ); } - public Join addJoin(SecondaryTable secondaryTable, PropertyHolder holder, boolean noDelayInPkColumnCreation) { + public Join addSecondaryTable(AnnotationUsage secondaryTable, PropertyHolder holder, boolean noDelayInPkColumnCreation) { final Join join = addJoin( holder, noDelayInPkColumnCreation, true, - secondaryTable.name(), - secondaryTable.schema(), - secondaryTable.catalog(), - secondaryTable.pkJoinColumns(), - secondaryTable.uniqueConstraints() + secondaryTable.getString( "name" ), + secondaryTable.getString( "schema" ), + secondaryTable.getString( "catalog" ), + secondaryTable.getList( "pkJoinColumns" ), + secondaryTable.getList( "uniqueConstraints" ) ); final Table table = join.getTable(); - new IndexBinder( context ).bindIndexes( table, secondaryTable.indexes() ); + new IndexBinder( context ).bindIndexes( table, secondaryTable.getList( "indexes" ) ); return join; } @@ -2180,7 +2171,7 @@ public class EntityBinder { String schema, String catalog, Object joinColumns, - UniqueConstraint[] uniqueConstraints) { + List> uniqueConstraints) { final QualifiedTableName logicalName = logicalTableName( name, schema, catalog ); return createJoin( propertyHolder, @@ -2259,15 +2250,15 @@ public class EntityBinder { private void handleSecondaryRowManagement(Join join) { final String tableName = join.getTable().getQuotedName(); - final org.hibernate.annotations.Table matchingTable = findMatchingComplementaryTableAnnotation( tableName ); - final SecondaryRow matchingRow = findMatchingSecondaryRowAnnotation( tableName ); + final AnnotationUsage matchingTable = findMatchingComplementaryTableAnnotation( tableName ); + final AnnotationUsage matchingRow = findMatchingSecondaryRowAnnotation( tableName ); if ( matchingRow != null ) { - join.setInverse( !matchingRow.owned() ); - join.setOptional( matchingRow.optional() ); + join.setInverse( !matchingRow.getBoolean( "owned" ) ); + join.setOptional( matchingRow.getBoolean( "optional" ) ); } else if ( matchingTable != null ) { - join.setInverse( matchingTable.inverse() ); - join.setOptional( matchingTable.optional() ); + join.setInverse( matchingTable.getBoolean( "inverse" ) ); + join.setOptional( matchingTable.getBoolean( "optional" ) ); } else { //default @@ -2278,73 +2269,79 @@ public class EntityBinder { private void processSecondaryTableCustomSql(Join join) { final String tableName = join.getTable().getQuotedName(); - final org.hibernate.annotations.Table matchingTable = + final AnnotationUsage matchingTable = findMatchingComplementaryTableAnnotation( tableName ); - final SQLInsert sqlInsert = + final AnnotationUsage sqlInsert = findMatchingSqlAnnotation( tableName, SQLInsert.class, SQLInserts.class ); if ( sqlInsert != null ) { join.setCustomSQLInsert( - sqlInsert.sql().trim(), - sqlInsert.callable(), - fromResultCheckStyle( sqlInsert.check() ) + sqlInsert.getString( "sql" ).trim(), + sqlInsert.getBoolean( "callable" ), + fromResultCheckStyle( sqlInsert.getEnum( "check" ) ) ); - if ( sqlInsert.verify() != Expectation.class ) { - join.setInsertExpectation( getDefaultSupplier( sqlInsert.verify() ) ); + final Class expectationClass = sqlInsert.getClassDetails("verify").toJavaClass(); + if ( expectationClass != Expectation.class ) { + join.setInsertExpectation( getDefaultSupplier( expectationClass ) ); } } else if ( matchingTable != null ) { - final String insertSql = matchingTable.sqlInsert().sql(); - if ( !insertSql.isEmpty() ) { + final AnnotationUsage matchingTableInsert = matchingTable.getNestedUsage( "sqlInsert" ); + final String matchingTableInsertSql = matchingTableInsert.getString( "sql" ).trim(); + if ( !matchingTableInsertSql.isEmpty() ) { join.setCustomSQLInsert( - insertSql.trim(), - matchingTable.sqlInsert().callable(), - fromResultCheckStyle( matchingTable.sqlInsert().check() ) + matchingTableInsertSql, + matchingTableInsert.getBoolean( "callable" ), + fromResultCheckStyle( matchingTableInsert.getEnum( "check" ) ) ); } } - final SQLUpdate sqlUpdate = + final AnnotationUsage sqlUpdate = findMatchingSqlAnnotation( tableName, SQLUpdate.class, SQLUpdates.class ); if ( sqlUpdate != null ) { join.setCustomSQLUpdate( - sqlUpdate.sql().trim(), - sqlUpdate.callable(), - fromResultCheckStyle( sqlUpdate.check() ) + sqlUpdate.getString( "sql" ).trim(), + sqlUpdate.getBoolean( "callable" ), + fromResultCheckStyle( sqlUpdate.getEnum( "check" ) ) ); - if ( sqlUpdate.verify() != Expectation.class ) { - join.setUpdateExpectation( getDefaultSupplier( sqlUpdate.verify() ) ); + final Class expectationClass = sqlUpdate.getClassDetails("verify").toJavaClass(); + if ( expectationClass != Expectation.class ) { + join.setUpdateExpectation( getDefaultSupplier( expectationClass ) ); } } else if ( matchingTable != null ) { - final String updateSql = matchingTable.sqlUpdate().sql(); - if ( !updateSql.isEmpty() ) { + final AnnotationUsage matchingTableUpdate = matchingTable.getNestedUsage( "sqlUpdate" ); + final String matchingTableUpdateSql = matchingTableUpdate.getString( "sql" ).trim(); + if ( !matchingTableUpdateSql.isEmpty() ) { join.setCustomSQLUpdate( - updateSql.trim(), - matchingTable.sqlUpdate().callable(), - fromResultCheckStyle( matchingTable.sqlUpdate().check() ) + matchingTableUpdateSql, + matchingTableUpdate.getBoolean( "callable" ), + fromResultCheckStyle( matchingTableUpdate.getEnum( "check" ) ) ); } } - final SQLDelete sqlDelete = + final AnnotationUsage sqlDelete = findMatchingSqlAnnotation( tableName, SQLDelete.class, SQLDeletes.class ); if ( sqlDelete != null ) { join.setCustomSQLDelete( - sqlDelete.sql().trim(), - sqlDelete.callable(), - fromResultCheckStyle( sqlDelete.check() ) + sqlDelete.getString( "sql" ).trim(), + sqlDelete.getBoolean( "callable" ), + fromResultCheckStyle( sqlDelete.getEnum( "check" ) ) ); - if ( sqlDelete.verify() != Expectation.class ) { - join.setDeleteExpectation( getDefaultSupplier( sqlDelete.verify() ) ); + final Class expectationClass = sqlDelete.getClassDetails("verify").toJavaClass(); + if ( expectationClass != Expectation.class ) { + join.setDeleteExpectation( getDefaultSupplier( expectationClass ) ); } } else if ( matchingTable != null ) { - final String deleteSql = matchingTable.sqlDelete().sql(); + final AnnotationUsage matchingTableDelete = matchingTable.getNestedUsage( "sqlDelete" ); + final String deleteSql = matchingTableDelete.getString( "sql" ).trim(); if ( !deleteSql.isEmpty() ) { join.setCustomSQLDelete( - deleteSql.trim(), - matchingTable.sqlDelete().callable(), - fromResultCheckStyle( matchingTable.sqlDelete().check() ) + deleteSql, + matchingTableDelete.getBoolean( "callable" ), + fromResultCheckStyle( matchingTableDelete.getEnum( "check" ) ) ); } } @@ -2359,7 +2356,7 @@ public class EntityBinder { return accessType == null ? null : accessType.getExternalName(); } - public void addFilter(Filter filter) { + public void addFilter(AnnotationUsage filter) { filters.add( filter ); } @@ -2371,25 +2368,6 @@ public class EntityBinder { this.ignoreIdAnnotations = ignoreIdAnnotations; } - public void processComplementaryTableDefinitions(jakarta.persistence.Table table) { - if ( table != null ) { - new IndexBinder( context ).bindIndexes( persistentClass.getTable(), table.indexes() ); - } - } - - public void processComplementaryTableDefinitions(org.hibernate.annotations.Table table) { - if ( table != null ) { - final Table appliedTable = findTable( table.appliesTo() ); - if ( !table.comment().isEmpty() ) { - appliedTable.setComment( table.comment() ); - } - if ( !table.checkConstraint().isEmpty() ) { - appliedTable.addCheckConstraint( table.checkConstraint() ); - } - TableBinder.addIndexes( appliedTable, table.indexes(), context ); - } - } - private Table findTable(String tableName) { for ( Table table : persistentClass.getTableClosure() ) { if ( table.getQuotedName().equals( tableName ) ) { @@ -2408,14 +2386,6 @@ public class EntityBinder { + tableName + "'" ); } - public void processComplementaryTableDefinitions(Tables tables) { - if ( tables != null ) { - for ( org.hibernate.annotations.Table table : tables.value() ) { - processComplementaryTableDefinitions( table ); - } - } - } - public AccessType getPropertyAccessType() { return propertyAccessType; } @@ -2428,17 +2398,17 @@ public class EntityBinder { } } - public AccessType getPropertyAccessor(XAnnotatedElement element) { + public AccessType getPropertyAccessor(AnnotationTarget element) { final AccessType accessType = getExplicitAccessType( element ); return accessType == null ? propertyAccessType : accessType; } - public AccessType getExplicitAccessType(XAnnotatedElement element) { + public AccessType getExplicitAccessType(AnnotationTarget element) { AccessType accessType = null; if ( element != null ) { - final Access access = element.getAnnotation( Access.class ); + final AnnotationUsage access = element.getAnnotationUsage( Access.class ); if ( access != null ) { - accessType = AccessType.getAccessStrategy( access.value() ); + accessType = AccessType.getAccessStrategy( access.getEnum( "value" ) ); } } return accessType; @@ -2452,7 +2422,7 @@ public class EntityBinder { bindFilters( annotatedClass ); - XClass classToProcess = annotatedClass.getSuperclass(); + ClassDetails classToProcess = annotatedClass.getSuperClass(); while ( classToProcess != null ) { final AnnotatedClassType classType = context.getMetadataCollector().getClassType( classToProcess ); if ( classType == MAPPED_SUPERCLASS ) { @@ -2461,18 +2431,18 @@ public class EntityBinder { else { break; } - classToProcess = classToProcess.getSuperclass(); + classToProcess = classToProcess.getSuperClass(); } } - private void bindFilters(XAnnotatedElement element) { - final Filters filters = getOverridableAnnotation( element, Filters.class, context ); + private void bindFilters(AnnotationTarget element) { + final AnnotationUsage filters = getOverridableAnnotation( element, Filters.class, context ); if ( filters != null ) { - for ( Filter filter : filters.value() ) { + for ( AnnotationUsage filter : filters.>getList( "value" ) ) { addFilter( filter ); } } - final Filter filter = element.getAnnotation( Filter.class ); + final AnnotationUsage filter = element.getSingleAnnotationUsage( Filter.class ); if ( filter != null ) { addFilter( filter ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchOverrideSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchOverrideSecondPass.java index 6f1359ae4a..7a33fdaf6f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchOverrideSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchOverrideSecondPass.java @@ -12,6 +12,8 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.SecondPass; import org.hibernate.mapping.FetchProfile; import org.hibernate.mapping.PersistentClass; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import java.util.Map; @@ -20,12 +22,12 @@ import java.util.Map; */ public class FetchOverrideSecondPass implements SecondPass { private final String fetchProfileName; - private final FetchOverride fetch; + private final AnnotationUsage fetch; private final MetadataBuildingContext buildingContext; public FetchOverrideSecondPass( String fetchProfileName, - FetchOverride fetch, + AnnotationUsage fetch, MetadataBuildingContext buildingContext) { this.fetchProfileName = fetchProfileName; this.fetch = fetch; @@ -34,20 +36,21 @@ public class FetchOverrideSecondPass implements SecondPass { @Override public void doSecondPass(Map persistentClasses) throws MappingException { + final ClassDetails entityClassDetails = fetch.getClassDetails( "entity" ); + final String attributeName = fetch.getString( "association" ); + // throws MappingException in case the property does not exist buildingContext.getMetadataCollector() - .getEntityBinding( fetch.entity().getName() ) - .getProperty( fetch.association() ); + .getEntityBinding( entityClassDetails.getName() ) + .getProperty( attributeName ); final FetchProfile profile = buildingContext.getMetadataCollector().getFetchProfile( fetchProfileName ); // we already know that the FetchProfile exists and is good to use - profile.addFetch( - new FetchProfile.Fetch( - fetch.entity().getName(), - fetch.association(), - fetch.mode(), - fetch.fetch() - ) - ); + profile.addFetch( new FetchProfile.Fetch( + entityClassDetails.getName(), + attributeName, + fetch.getEnum( "mode" ), + fetch.getEnum( "fetch" ) + ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchSecondPass.java index 1c1d84c4ab..c761819e38 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FetchSecondPass.java @@ -15,6 +15,7 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.SecondPass; import org.hibernate.mapping.FetchProfile; import org.hibernate.mapping.PersistentClass; +import org.hibernate.models.spi.AnnotationUsage; import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.mapping.MetadataSource.ANNOTATIONS; @@ -23,13 +24,13 @@ import static org.hibernate.mapping.MetadataSource.ANNOTATIONS; * @author Gavin King */ public class FetchSecondPass implements SecondPass { - private final FetchProfileOverride fetch; + private final AnnotationUsage fetch; private final PropertyHolder propertyHolder; private final String propertyName; private final MetadataBuildingContext buildingContext; public FetchSecondPass( - FetchProfileOverride fetch, + AnnotationUsage fetch, PropertyHolder propertyHolder, String propertyName, MetadataBuildingContext buildingContext) { @@ -41,21 +42,20 @@ public class FetchSecondPass implements SecondPass { @Override public void doSecondPass(Map persistentClasses) throws MappingException { - - final FetchProfile profile = buildingContext.getMetadataCollector().getFetchProfile( fetch.profile() ); + final String profileName = fetch.getString( "profile" ); + final FetchProfile profile = buildingContext.getMetadataCollector().getFetchProfile( profileName ); if ( profile == null ) { throw new AnnotationException( "Property '" + qualify( propertyHolder.getPath(), propertyName ) - + "' refers to an unknown fetch profile named '" + fetch.profile() + "'" ); + + "' refers to an unknown fetch profile named '" + profileName + "'" ); } + if ( profile.getSource() == ANNOTATIONS ) { - profile.addFetch( - new FetchProfile.Fetch( - propertyHolder.getEntityName(), - propertyName, - fetch.mode(), - fetch.fetch() - ) - ); + profile.addFetch( new FetchProfile.Fetch( + propertyHolder.getEntityName(), + propertyName, + fetch.getEnum( "mode" ), + fetch.getEnum( "fetch" ) + ) ); } // otherwise, it's a fetch profile defined in XML, and it overrides // the annotations, so we simply ignore this annotation completely diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FilterDefBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FilterDefBinder.java index 1e968b41e6..55dc3337ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FilterDefBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/FilterDefBinder.java @@ -6,13 +6,17 @@ */ package org.hibernate.boot.model.internal; -import jakarta.persistence.AttributeConverter; +import java.lang.reflect.ParameterizedType; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + import org.hibernate.AnnotationException; import org.hibernate.MappingException; import org.hibernate.annotations.FilterDef; import org.hibernate.annotations.FilterDefs; import org.hibernate.annotations.ParamDef; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -20,6 +24,9 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; @@ -34,10 +41,7 @@ import org.hibernate.type.internal.ConvertedBasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.UserType; -import java.lang.reflect.ParameterizedType; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; +import jakarta.persistence.AttributeConverter; import java.util.function.Supplier; import static java.util.Collections.emptyMap; @@ -53,48 +57,53 @@ class FilterDefBinder { private static final CoreMessageLogger LOG = messageLogger( FilterDefBinder.class ); - public static void bindFilterDef(FilterDef filterDef, MetadataBuildingContext context) { - final String name = filterDef.name(); + public static void bindFilterDef(AnnotationUsage filterDef, MetadataBuildingContext context) { + final String name = filterDef.getString( "name" ); if ( context.getMetadataCollector().getFilterDefinition( name ) != null ) { throw new AnnotationException( "Multiple '@FilterDef' annotations define a filter named '" + name + "'" ); } - final Map explicitParamJaMappings; + final Map paramJdbcMappings; final Map>> parameterResolvers; - if ( filterDef.parameters().length == 0 ) { - explicitParamJaMappings = emptyMap(); + final List> explicitParameters = filterDef.getList( "parameters" ); + if ( explicitParameters.isEmpty() ) { + paramJdbcMappings = emptyMap(); parameterResolvers = emptyMap(); } else { - explicitParamJaMappings = new HashMap<>(); + paramJdbcMappings = new HashMap<>(); parameterResolvers = new HashMap<>(); - for ( ParamDef paramDef : filterDef.parameters() ) { - final JdbcMapping jdbcMapping = resolveFilterParamType( paramDef.type(), context ); + for ( AnnotationUsage explicitParameter : explicitParameters ) { + final String parameterName = explicitParameter.getString( "name" ); + final ClassDetails typeClassDetails = explicitParameter.getClassDetails( "type" ); + final JdbcMapping jdbcMapping = resolveFilterParamType( typeClassDetails.toJavaClass(), context ); if ( jdbcMapping == null ) { throw new MappingException( String.format( Locale.ROOT, "Unable to resolve type specified for parameter (%s) defined for @FilterDef (%s)", - paramDef.name(), + parameterName, name ) ); } - explicitParamJaMappings.put( paramDef.name(), jdbcMapping ); + paramJdbcMappings.put( parameterName, jdbcMapping ); if ( paramDef.resolver() != Supplier.class ) { parameterResolvers.put( paramDef.name(), resolveParamResolver( paramDef, context ) ); } } } + final FilterDefinition filterDefinition = new FilterDefinition( name, - filterDef.defaultCondition(), - explicitParamJaMappings, + filterDef.getString( "defaultCondition" ), + paramJdbcMappings, parameterResolvers, - filterDef.autoEnabled(), + filterDef.getBoolean( "autoEnabled" ), filterDef.applyToLoadByKey() ); + LOG.debugf( "Binding filter definition: %s", filterDefinition.getFilterName() ); context.getMetadataCollector().addFilterDefinition( filterDefinition ); } @@ -245,14 +254,15 @@ class FilterDefBinder { } } - public static void bindFilterDefs(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { - final FilterDef filterDef = annotatedElement.getAnnotation( FilterDef.class ); - final FilterDefs filterDefs = getOverridableAnnotation( annotatedElement, FilterDefs.class, context ); + public static void bindFilterDefs(AnnotationTarget annotatedElement, MetadataBuildingContext context) { + final AnnotationUsage filterDef = annotatedElement.getAnnotationUsage( FilterDef.class ); + final AnnotationUsage filterDefs = getOverridableAnnotation( annotatedElement, FilterDefs.class, context ); if ( filterDef != null ) { bindFilterDef( filterDef, context ); } if ( filterDefs != null ) { - for ( FilterDef def : filterDefs.value() ) { + final List> nestedDefs = filterDefs.getList( "value" ); + for ( AnnotationUsage def : nestedDefs ) { bindFilterDef( def, context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java index 8f6707d831..e9f3755713 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java @@ -18,11 +18,7 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.IdGeneratorType; -import org.hibernate.annotations.Parameter; import org.hibernate.annotations.ValueGenerationType; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.internal.GenerationStrategyInterpreter; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.relational.ExportableProducer; @@ -42,20 +38,24 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.mapping.GeneratorCreator; import org.hibernate.mapping.IdentifierGeneratorCreator; import org.hibernate.mapping.SimpleValue; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; import org.hibernate.mapping.Value; import org.hibernate.resource.beans.container.spi.BeanContainer; import org.hibernate.resource.beans.spi.BeanInstanceProducer; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.jboss.logging.Logger; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.SequenceGenerators; import jakarta.persistence.TableGenerator; -import jakarta.persistence.TableGenerators; import jakarta.persistence.Version; +import static org.hibernate.boot.model.internal.AnnotationHelper.extractParameterMap; import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId; import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal; import static org.hibernate.id.factory.internal.IdentifierGeneratorUtil.collectParameters; @@ -71,12 +71,12 @@ public class GeneratorBinder { */ public static void makeIdGenerator( SimpleValue id, - XProperty property, + MemberDetails idAttributeMember, String generatorType, String generatorName, MetadataBuildingContext buildingContext, Map localGenerators) { - LOG.debugf( "#makeIdGenerator(%s, %s, %s, %s, ...)", id, property, generatorType, generatorName ); + LOG.debugf( "#makeIdGenerator(%s, %s, %s, %s, ...)", id, idAttributeMember, generatorType, generatorName ); //generator settings id.setIdentifierGeneratorStrategy( generatorType ); @@ -97,7 +97,7 @@ public class GeneratorBinder { //we have a named generator final IdentifierGeneratorDefinition definition = makeIdentifierGeneratorDefinition( generatorName, - property, + idAttributeMember, localGenerators, buildingContext ); @@ -131,7 +131,7 @@ public class GeneratorBinder { */ public static void makeIdGenerator( SimpleValue id, - XProperty idXProperty, + MemberDetails idAttributeMember, String generatorType, String generatorName, MetadataBuildingContext buildingContext, @@ -141,12 +141,12 @@ public class GeneratorBinder { localIdentifiers = new HashMap<>(); localIdentifiers.put( foreignKGeneratorDefinition.getName(), foreignKGeneratorDefinition ); } - makeIdGenerator( id, idXProperty, generatorType, generatorName, buildingContext, localIdentifiers ); + makeIdGenerator( id, idAttributeMember, generatorType, generatorName, buildingContext, localIdentifiers ); } private static IdentifierGeneratorDefinition makeIdentifierGeneratorDefinition( String name, - XProperty idProperty, + MemberDetails idAttributeMember, Map localGenerators, MetadataBuildingContext buildingContext) { if ( localGenerators != null ) { @@ -164,7 +164,7 @@ public class GeneratorBinder { LOG.debugf( "Could not resolve explicit IdentifierGeneratorDefinition - using implicit interpretation (%s)", name ); - final GeneratedValue generatedValue = idProperty.getAnnotation( GeneratedValue.class ); + final AnnotationUsage generatedValue = idAttributeMember.getAnnotationUsage( GeneratedValue.class ); if ( generatedValue == null ) { // this should really never happen, but it's easy to protect against it... return new IdentifierGeneratorDefinition( DEFAULT_ID_GEN_STRATEGY, DEFAULT_ID_GEN_STRATEGY ); @@ -172,80 +172,54 @@ public class GeneratorBinder { return IdentifierGeneratorDefinition.createImplicit( name, - buildingContext - .getBootstrapContext() - .getReflectionManager() - .toClass( idProperty.getType() ), - generatedValue.generator(), + idAttributeMember.getType().determineRawClass().toJavaClass(), + generatedValue.getString( "generator" ), interpretGenerationType( generatedValue ) ); } - private static GenerationType interpretGenerationType(GeneratedValue generatedValueAnn) { - return generatedValueAnn.strategy() == null ? GenerationType.AUTO : generatedValueAnn.strategy(); + private static GenerationType interpretGenerationType(AnnotationUsage generatedValueAnn) { + // todo (jpa32) : when can this ever be null? + final GenerationType strategy = generatedValueAnn.getEnum( "strategy" ); + return strategy == null ? GenerationType.AUTO : strategy; } public static Map buildGenerators( - XAnnotatedElement annotatedElement, + AnnotationTarget annotatedElement, MetadataBuildingContext context) { final InFlightMetadataCollector metadataCollector = context.getMetadataCollector(); final Map generators = new HashMap<>(); - final TableGenerators tableGenerators = annotatedElement.getAnnotation( TableGenerators.class ); - if ( tableGenerators != null ) { - for ( TableGenerator tableGenerator : tableGenerators.value() ) { - IdentifierGeneratorDefinition idGenerator = buildIdGenerator( tableGenerator, context ); - generators.put( - idGenerator.getName(), - idGenerator - ); - metadataCollector.addIdentifierGenerator( idGenerator ); - } - } + annotatedElement.forEachAnnotationUsage( TableGenerator.class, (usage) -> { + IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage, context ); + generators.put( + idGenerator.getName(), + idGenerator + ); + metadataCollector.addIdentifierGenerator( idGenerator ); + } ); - final SequenceGenerators sequenceGenerators = annotatedElement.getAnnotation( SequenceGenerators.class ); - if ( sequenceGenerators != null ) { - for ( SequenceGenerator sequenceGenerator : sequenceGenerators.value() ) { - IdentifierGeneratorDefinition idGenerator = buildIdGenerator( sequenceGenerator, context ); - generators.put( - idGenerator.getName(), - idGenerator - ); - metadataCollector.addIdentifierGenerator( idGenerator ); - } - } - - final TableGenerator tableGenerator = annotatedElement.getAnnotation( TableGenerator.class ); - if ( tableGenerator != null ) { - IdentifierGeneratorDefinition idGenerator = buildIdGenerator( tableGenerator, context ); + annotatedElement.forEachAnnotationUsage( SequenceGenerator.class, (usage) -> { + IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage, context ); generators.put( idGenerator.getName(), idGenerator ); metadataCollector.addIdentifierGenerator( idGenerator ); + } ); - } - - final SequenceGenerator sequenceGenerator = annotatedElement.getAnnotation( SequenceGenerator.class ); - if ( sequenceGenerator != null ) { - IdentifierGeneratorDefinition idGenerator = buildIdGenerator( sequenceGenerator, context ); + annotatedElement.forEachAnnotationUsage( GenericGenerator.class, (usage) -> { + final IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage, context ); generators.put( idGenerator.getName(), idGenerator ); metadataCollector.addIdentifierGenerator( idGenerator ); - } - - final GenericGenerator genericGenerator = annotatedElement.getAnnotation( GenericGenerator.class ); - if ( genericGenerator != null ) { - final IdentifierGeneratorDefinition idGenerator = buildIdGenerator( genericGenerator, context ); - generators.put( idGenerator.getName(), idGenerator ); - metadataCollector.addIdentifierGenerator( idGenerator ); - } + } ); return generators; } static String generatorType( MetadataBuildingContext context, - XClass entityXClass, + ClassDetails entityXClass, boolean isComponent, - GeneratedValue generatedValue) { + AnnotationUsage generatedValue) { if ( isComponent ) { //a component must not have any generator return DEFAULT_ID_GEN_STRATEGY; @@ -255,62 +229,67 @@ public class GeneratorBinder { } } - static String generatorType(GeneratedValue generatedValue, final XClass javaClass, MetadataBuildingContext context) { + static String generatorType( + AnnotationUsage generatedValue, + final ClassDetails javaClass, + MetadataBuildingContext context) { return GenerationStrategyInterpreter.STRATEGY_INTERPRETER.determineGeneratorName( - generatedValue.strategy(), + generatedValue.getEnum( "strategy" ), new GenerationStrategyInterpreter.GeneratorNameDeterminationContext() { Class javaType = null; @Override public Class getIdType() { if ( javaType == null ) { - javaType = context.getBootstrapContext().getReflectionManager().toClass( javaClass ); + javaType = javaClass.toJavaClass(); } return javaType; } @Override public String getGeneratedValueGeneratorName() { - return generatedValue.generator(); + return generatedValue.getString( "generator" ); } } ); } static IdentifierGeneratorDefinition buildIdGenerator( - Annotation generatorAnnotation, + AnnotationUsage generatorAnnotation, MetadataBuildingContext context) { if ( generatorAnnotation == null ) { return null; } final IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder(); - if ( generatorAnnotation instanceof TableGenerator ) { + if ( TableGenerator.class.isAssignableFrom( generatorAnnotation.getAnnotationType() ) ) { + //noinspection unchecked GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretTableGenerator( - (TableGenerator) generatorAnnotation, + (AnnotationUsage) generatorAnnotation, definitionBuilder ); if ( LOG.isTraceEnabled() ) { LOG.tracev( "Add table generator with name: {0}", definitionBuilder.getName() ); } } - else if ( generatorAnnotation instanceof SequenceGenerator ) { + else if ( SequenceGenerator.class.isAssignableFrom( generatorAnnotation.getAnnotationType() ) ) { + //noinspection unchecked GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretSequenceGenerator( - (SequenceGenerator) generatorAnnotation, + (AnnotationUsage) generatorAnnotation, definitionBuilder ); if ( LOG.isTraceEnabled() ) { LOG.tracev( "Add sequence generator with name: {0}", definitionBuilder.getName() ); } } - else if ( generatorAnnotation instanceof GenericGenerator ) { - final GenericGenerator genericGenerator = (GenericGenerator) generatorAnnotation; - definitionBuilder.setName( genericGenerator.name() ); - final String strategy = genericGenerator.type().equals(Generator.class) - ? genericGenerator.strategy() - : genericGenerator.type().getName(); + else if ( GenericGenerator.class.isAssignableFrom( generatorAnnotation.getAnnotationType() ) ) { + //noinspection unchecked + final AnnotationUsage genericGenerator = (AnnotationUsage) generatorAnnotation; + definitionBuilder.setName( genericGenerator.getString( "name" ) ); + final Class generatorClass = genericGenerator.getClassDetails( "type" ).toJavaClass(); + final String strategy = generatorClass.equals(Generator.class) + ? genericGenerator.getString( "strategy" ) + : generatorClass.getName(); definitionBuilder.setStrategy( strategy ); - for ( Parameter parameter : genericGenerator.parameters() ) { - definitionBuilder.addParam( parameter.name(), parameter.value() ); - } + definitionBuilder.addParams( extractParameterMap( genericGenerator.getList( "parameters" ) ) ); if ( LOG.isTraceEnabled() ) { LOG.tracev( "Add generic generator with name: {0}", definitionBuilder.getName() ); } @@ -349,9 +328,11 @@ public class GeneratorBinder { * Instantiates the given generator annotation type, initializing it with the given instance of the corresponding * generator annotation and the property's type. */ - static GeneratorCreator generatorCreator(XProperty property, Annotation annotation) { - final Member member = HCANNHelper.getUnderlyingMember( property ); - final Class annotationType = annotation.annotationType(); + static GeneratorCreator generatorCreator( + MemberDetails memberDetails, + AnnotationUsage annotation, + MetadataBuildingContext buildingContext) { + final Class annotationType = annotation.getAnnotationType(); final ValueGenerationType generatorAnnotation = annotationType.getAnnotation( ValueGenerationType.class ); if ( generatorAnnotation == null ) { return null; @@ -360,42 +341,39 @@ public class GeneratorBinder { checkGeneratorClass( generatorClass ); checkGeneratorInterfaces( generatorClass ); return creationContext -> { - final Generator generator = - instantiateGenerator( - annotation, - member, - annotationType, - creationContext, - GeneratorCreationContext.class, - generatorClass - ); - callInitialize( annotation, member, creationContext, generator ); - checkVersionGenerationAlways( property, generator ); + final Generator generator = instantiateGenerator( + annotation, + memberDetails, + annotationType, + GeneratorCreationContext.class, + generatorClass, + creationContext + ); + callInitialize( annotation, memberDetails, creationContext, generator ); + checkVersionGenerationAlways( memberDetails, generator ); return generator; }; } static IdentifierGeneratorCreator identifierGeneratorCreator( - XProperty idProperty, - Annotation annotation, + MemberDetails idAttributeMember, + AnnotationUsage annotation, BeanContainer beanContainer) { - final Member member = HCANNHelper.getUnderlyingMember( idProperty ); - final Class annotationType = annotation.annotationType(); + final Class annotationType = annotation.getAnnotationType(); final IdGeneratorType idGeneratorType = annotationType.getAnnotation( IdGeneratorType.class ); assert idGeneratorType != null; return creationContext -> { final Class generatorClass = idGeneratorType.value(); checkGeneratorClass( generatorClass ); - final Generator generator = - instantiateGenerator( - annotation, - beanContainer, - creationContext, - generatorClass, - member, - annotationType - ); - callInitialize( annotation, member, creationContext, generator ); + final Generator generator = instantiateGenerator( + annotation, + beanContainer, + creationContext, + generatorClass, + idAttributeMember, + annotationType + ); + callInitialize( annotation, idAttributeMember, creationContext, generator ); callConfigure( creationContext, generator ); checkIdGeneratorTiming( annotationType, generator ); return generator; @@ -403,11 +381,11 @@ public class GeneratorBinder { } private static Generator instantiateGenerator( - Annotation annotation, + AnnotationUsage annotation, BeanContainer beanContainer, CustomIdGeneratorCreationContext creationContext, Class generatorClass, - Member member, + MemberDetails memberDetails, Class annotationType) { if ( beanContainer != null ) { return instantiateGeneratorAsBean( @@ -415,28 +393,28 @@ public class GeneratorBinder { beanContainer, creationContext, generatorClass, - member, + memberDetails, annotationType ); } else { return instantiateGenerator( annotation, - member, + memberDetails, annotationType, - creationContext, CustomIdGeneratorCreationContext.class, - generatorClass + generatorClass, + creationContext ); } } private static Generator instantiateGeneratorAsBean( - Annotation annotation, + AnnotationUsage annotation, BeanContainer beanContainer, CustomIdGeneratorCreationContext creationContext, Class generatorClass, - Member member, + MemberDetails memberDetails, Class annotationType) { return beanContainer.getBean( generatorClass, new BeanContainer.LifecycleOptions() { @@ -455,11 +433,11 @@ public class GeneratorBinder { public B produceBeanInstance(Class beanType) { return (B) instantiateGenerator( annotation, - member, + memberDetails, annotationType, - creationContext, CustomIdGeneratorCreationContext.class, - generatorClass + generatorClass, + creationContext ); } @Override @@ -471,30 +449,30 @@ public class GeneratorBinder { } private static G instantiateGenerator( - Annotation annotation, - Member member, + AnnotationUsage annotation, + MemberDetails memberDetails, Class annotationType, - C creationContext, Class contextClass, - Class generatorClass) { + Class generatorClass, + C creationContext) { try { try { return generatorClass .getConstructor( annotationType, Member.class, contextClass ) - .newInstance( annotation, member, creationContext); + .newInstance( annotation.toAnnotation(), memberDetails.toJavaMember(), creationContext); } catch (NoSuchMethodException ignore) { try { return generatorClass .getConstructor( annotationType ) - .newInstance( annotation ); + .newInstance( annotation.toAnnotation() ); } catch (NoSuchMethodException i) { return generatorClass.newInstance(); } } } - catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + catch (InvocationTargetException | InstantiationException | IllegalAccessException | IllegalArgumentException e ) { throw new HibernateException( "Could not instantiate generator of type '" + generatorClass.getName() + "'", e @@ -503,8 +481,8 @@ public class GeneratorBinder { } private static
void callInitialize( - A annotation, - Member member, + AnnotationUsage annotation, + MemberDetails memberDetails, GeneratorCreationContext creationContext, Generator generator) { if ( generator instanceof AnnotationBasedGenerator ) { @@ -513,12 +491,12 @@ public class GeneratorBinder { // check this explicitly; If required, this could be done e.g. using ClassMate @SuppressWarnings("unchecked") final AnnotationBasedGenerator generation = (AnnotationBasedGenerator) generator; - generation.initialize( annotation, member, creationContext ); + generation.initialize( annotation.toAnnotation(), memberDetails.toJavaMember(), creationContext ); } } - private static void checkVersionGenerationAlways(XProperty property, Generator generator) { - if ( property.isAnnotationPresent(Version.class) ) { + private static void checkVersionGenerationAlways(MemberDetails property, Generator generator) { + if ( property.hasAnnotationUsage(Version.class) ) { if ( !generator.generatesOnInsert() ) { throw new AnnotationException("Property '" + property.getName() + "' is annotated '@Version' but has a 'Generator' which does not generate on inserts" @@ -560,18 +538,18 @@ public class GeneratorBinder { SimpleValue idValue, Map classGenerators, MetadataBuildingContext context, - XClass entityClass, - XProperty idProperty) { + ClassDetails entityClass, + MemberDetails idAttributeMember) { //manage composite related metadata //guess if its a component and find id data access (property, field etc) - final GeneratedValue generatedValue = idProperty.getAnnotation( GeneratedValue.class ); - final String generatorType = generatorType( context, entityClass, isCompositeId( entityClass, idProperty ), generatedValue ); - final String generatorName = generatedValue == null ? "" : generatedValue.generator(); + final AnnotationUsage generatedValue = idAttributeMember.getAnnotationUsage( GeneratedValue.class ); + final String generatorType = generatorType( context, entityClass, isCompositeId( entityClass, idAttributeMember ), generatedValue ); + final String generatorName = generatedValue == null ? "" : generatedValue.getString( "generator" ); if ( isGlobalGeneratorNameGlobal( context ) ) { - buildGenerators( idProperty, context ); + buildGenerators( idAttributeMember, context ); context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( idValue, - idProperty, + idAttributeMember, generatorType, generatorName, context @@ -580,8 +558,8 @@ public class GeneratorBinder { else { //clone classGenerator and override with local values final Map generators = new HashMap<>( classGenerators ); - generators.putAll( buildGenerators( idProperty, context ) ); - makeIdGenerator( idValue, idProperty, generatorType, generatorName, context, generators ); + generators.putAll( buildGenerators( idAttributeMember, context ) ); + makeIdGenerator( idValue, idAttributeMember, generatorType, generatorName, context, generators ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/HCANNHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/HCANNHelper.java index f2afd5ac60..a54f8846b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/HCANNHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/HCANNHelper.java @@ -9,8 +9,6 @@ package org.hibernate.boot.model.internal; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Member; -import java.util.ArrayList; -import java.util.List; import org.hibernate.Internal; import org.hibernate.annotations.common.reflection.XAnnotatedElement; @@ -117,61 +115,4 @@ public final class HCANNHelper { return member.getMember(); } - /** - * Return an annotation of the given type which annotates the given - * annotated program element, or which meta-annotates an annotation - * of the given annotated program element. - * - * @implNote Searches only one level deep - */ - public static T findAnnotation( - XAnnotatedElement annotatedElement, - Class annotationType) { - // first, see if we can find it directly... - final T direct = annotatedElement.getAnnotation( annotationType ); - if ( direct != null ) { - return direct; - } - - // or as composed... - final Annotation[] annotations = annotatedElement.getAnnotations(); - for ( Annotation annotation : annotations ) { - if ( annotationType.equals( annotation.getClass() ) ) { - // we would have found this on the direct search, so no need - // to check its meta-annotations - continue; - } - - // we only check one level deep - final T metaAnnotation = annotation.annotationType().getAnnotation( annotationType ); - if ( metaAnnotation != null ) { - return metaAnnotation; - } - } - - return null; - } - - /** - * Return an annotation of the given annotated program element which - * is annotated by the given type of meta-annotation. - * - * @implNote Searches only one level deep - */ - public static List findContainingAnnotations( - XAnnotatedElement annotatedElement, - Class annotationType) { - - final List result = new ArrayList<>(); - - final Annotation[] annotations = annotatedElement.getAnnotations(); - for ( Annotation annotation : annotations ) { - final Annotation metaAnn = annotation.annotationType().getAnnotation( annotationType ); - if ( metaAnn != null ) { - result.add( annotation ); - } - } - - return result; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdBagBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdBagBinder.java index f112152206..17b4ca5131 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdBagBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdBagBinder.java @@ -7,6 +7,7 @@ package org.hibernate.boot.model.internal; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -21,11 +22,10 @@ import org.hibernate.mapping.IdentifierBag; import org.hibernate.mapping.IdentifierCollection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.usertype.UserCollectionType; -import jakarta.persistence.Column; - import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; /** @@ -51,7 +51,7 @@ public class IdBagBinder extends BagBinder { protected boolean bindStarToManySecondPass(Map persistentClasses) { boolean result = super.bindStarToManySecondPass( persistentClasses ); - final CollectionId collectionIdAnn = property.getAnnotation( CollectionId.class ); + final AnnotationUsage collectionIdAnn = property.getAnnotationUsage( CollectionId.class ); if ( collectionIdAnn == null ) { throw new MappingException( "idbag mapping missing '@CollectionId' annotation" ); } @@ -62,13 +62,13 @@ public class IdBagBinder extends BagBinder { property, //default access should not be useful null, - buildingContext.getBootstrapContext().getReflectionManager() + buildingContext ), "id" ); final AnnotatedColumns idColumns = AnnotatedColumn.buildColumnsFromAnnotations( - new Column[] { collectionIdAnn.column() }, + List.of( collectionIdAnn.getNestedUsage( "column" ) ), // null, null, Nullability.FORCED_NOT_NULL, @@ -100,7 +100,7 @@ public class IdBagBinder extends BagBinder { final BasicValue id = valueBinder.make(); ( (IdentifierCollection) collection ).setIdentifier( id ); - final String namedGenerator = collectionIdAnn.generator(); + final String namedGenerator = collectionIdAnn.getString( "generator" ); switch (namedGenerator) { case "identity": { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdGeneratorResolverSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdGeneratorResolverSecondPass.java index 9920feb739..523b42b107 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdGeneratorResolverSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdGeneratorResolverSecondPass.java @@ -9,12 +9,12 @@ package org.hibernate.boot.model.internal; import java.util.Map; import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.SecondPass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SimpleValue; +import org.hibernate.models.spi.MemberDetails; import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; @@ -23,7 +23,7 @@ import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; */ public class IdGeneratorResolverSecondPass implements SecondPass { private final SimpleValue id; - private final XProperty idXProperty; + private final MemberDetails idAttributeMember; private final String generatorType; private final String generatorName; private final MetadataBuildingContext buildingContext; @@ -31,12 +31,12 @@ public class IdGeneratorResolverSecondPass implements SecondPass { public IdGeneratorResolverSecondPass( SimpleValue id, - XProperty idXProperty, + MemberDetails idAttributeMember, String generatorType, String generatorName, MetadataBuildingContext buildingContext) { this.id = id; - this.idXProperty = idXProperty; + this.idAttributeMember = idAttributeMember; this.generatorType = generatorType; this.generatorName = generatorName; this.buildingContext = buildingContext; @@ -44,17 +44,17 @@ public class IdGeneratorResolverSecondPass implements SecondPass { public IdGeneratorResolverSecondPass( SimpleValue id, - XProperty idXProperty, + MemberDetails idAttributeMember, String generatorType, String generatorName, MetadataBuildingContext buildingContext, IdentifierGeneratorDefinition localIdentifierGeneratorDefinition) { - this(id,idXProperty,generatorType,generatorName,buildingContext); + this( id, idAttributeMember, generatorType, generatorName, buildingContext ); this.localIdentifierGeneratorDefinition = localIdentifierGeneratorDefinition; } @Override public void doSecondPass(Map idGeneratorDefinitionMap) throws MappingException { - makeIdGenerator( id, idXProperty, generatorType, generatorName, buildingContext, localIdentifierGeneratorDefinition ); + makeIdGenerator( id, idAttributeMember, generatorType, generatorName, buildingContext, localIdentifierGeneratorDefinition ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ImplicitToOneJoinTableSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ImplicitToOneJoinTableSecondPass.java index 831d4f6f8a..d1b2a26858 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ImplicitToOneJoinTableSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ImplicitToOneJoinTableSecondPass.java @@ -12,10 +12,12 @@ import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.boot.spi.SecondPass; +import org.hibernate.internal.util.StringHelper; import org.hibernate.mapping.Join; import org.hibernate.mapping.ManyToOne; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; import java.util.Map; @@ -36,7 +38,7 @@ public class ImplicitToOneJoinTableSecondPass implements SecondPass { private final PropertyData inferredData; private final MetadataBuildingContext context; private final AnnotatedJoinColumns joinColumns; - private final JoinTable joinTable; + private final AnnotationUsage joinTable; private final NotFoundAction notFoundAction; private final ManyToOne value; @@ -45,7 +47,7 @@ public class ImplicitToOneJoinTableSecondPass implements SecondPass { PropertyData inferredData, MetadataBuildingContext context, AnnotatedJoinColumns joinColumns, - JoinTable joinTable, + AnnotationUsage joinTable, NotFoundAction notFoundAction, ManyToOne value) { this.propertyHolder = propertyHolder; @@ -86,17 +88,25 @@ public class ImplicitToOneJoinTableSecondPass implements SecondPass { private TableBinder createTableBinder() { final TableBinder tableBinder = new TableBinder(); tableBinder.setBuildingContext( context ); - if ( !joinTable.schema().isEmpty() ) { - tableBinder.setSchema( joinTable.schema() ); + + final String schema = joinTable.getString( "schema" ); + if ( StringHelper.isNotEmpty( schema ) ) { + tableBinder.setSchema( schema ); } - if ( !joinTable.catalog().isEmpty() ) { - tableBinder.setCatalog( joinTable.catalog() ); + + final String catalog = joinTable.getString( "catalog" ); + if ( StringHelper.isNotEmpty( catalog ) ) { + tableBinder.setCatalog( catalog ); } - if ( !joinTable.name().isEmpty() ) { - tableBinder.setName( joinTable.name() ); + + final String tableName = joinTable.getString( "name" ); + if ( StringHelper.isNotEmpty( tableName ) ) { + tableBinder.setName( tableName ); } - tableBinder.setUniqueConstraints( joinTable.uniqueConstraints() ); - tableBinder.setJpaIndex( joinTable.indexes() ); + + tableBinder.setUniqueConstraints( joinTable.getList( "uniqueConstraints" ) ); + tableBinder.setJpaIndex( joinTable.getList( "indexes" ) ); + return tableBinder; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java index 1ab9cbd2bb..168a67e66a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java @@ -6,7 +6,11 @@ */ package org.hibernate.boot.model.internal; -import jakarta.persistence.UniqueConstraint; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + import org.hibernate.AnnotationException; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.ImplicitIndexNameSource; @@ -16,17 +20,16 @@ import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.dialect.Dialect; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Column; import org.hibernate.mapping.Formula; import org.hibernate.mapping.Index; import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Table; import org.hibernate.mapping.UniqueKey; +import org.hibernate.models.spi.AnnotationUsage; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.StringTokenizer; +import jakarta.persistence.UniqueConstraint; import static java.util.Collections.emptyList; import static org.hibernate.boot.model.naming.Identifier.toIdentifier; @@ -112,8 +115,8 @@ class IndexBinder { return new Column( physicalName ); } - private Selectable[] selectables(Table table, String name, final String[] columnNames) { - final int size = columnNames.length; + private Selectable[] selectables(Table table, String name, List columnNames) { + final int size = columnNames.size(); if ( size == 0 ) { throw new AnnotationException( "Index" + ( isEmpty( name ) ? "" : " '" + name + "'" ) @@ -121,7 +124,7 @@ class IndexBinder { } final Selectable[] columns = new Selectable[size]; for ( int index = 0; index < size; index++ ) { - final String columnName = columnNames[index]; + final String columnName = columnNames.get( index ); if ( isEmpty( columnName ) ) { throw new AnnotationException( "Index" + ( isEmpty( name ) ? "" : " '" + name + "'" ) @@ -132,8 +135,8 @@ class IndexBinder { return columns; } - private Column[] columns(Table table, String name, final String[] columnNames) { - final int size = columnNames.length; + private Column[] columns(Table table, String name, final List columnNames) { + final int size = columnNames.size(); if ( size == 0 ) { throw new AnnotationException( "Unique constraint" + ( isEmpty( name ) ? "" : " '" + name + "'" ) @@ -141,7 +144,7 @@ class IndexBinder { } final Column[] columns = new Column[size]; for ( int index = 0; index < size; index++ ) { - final String columnName = columnNames[index]; + final String columnName = columnNames.get( index ); if ( isEmpty( columnName ) ) { throw new AnnotationException( "Unique constraint" + ( isEmpty( name ) ? "" : " '" + name + "'" ) @@ -156,7 +159,7 @@ class IndexBinder { Table table, String originalKeyName, boolean nameExplicit, - String[] columnNames, + List columnNames, String[] orderings, boolean unique, Selectable[] columns) { @@ -187,9 +190,9 @@ class IndexBinder { } } - void bindIndexes(Table table, jakarta.persistence.Index[] indexes) { - for ( jakarta.persistence.Index index : indexes ) { - final StringTokenizer tokenizer = new StringTokenizer( index.columnList(), "," ); + void bindIndexes(Table table, List> indexes) { + for ( AnnotationUsage index : indexes ) { + final StringTokenizer tokenizer = new StringTokenizer( index.getString( "columnList" ), "," ); final List parsed = new ArrayList<>(); while ( tokenizer.hasMoreElements() ) { final String trimmed = tokenizer.nextToken().trim(); @@ -197,39 +200,53 @@ class IndexBinder { parsed.add( trimmed ) ; } } - final String[] columnExpressions = new String[parsed.size()]; + final List columnExpressions = CollectionHelper.populatedArrayList( parsed.size(), null ); final String[] ordering = new String[parsed.size()]; initializeColumns( columnExpressions, ordering, parsed ); - final String name = index.name(); - final boolean unique = index.unique(); - createIndexOrUniqueKey( table, name, !name.isEmpty(), columnExpressions, ordering, unique, - selectables( table, name, columnExpressions ) ); + final String name = index.getString( "name" ); + final boolean unique = index.getBoolean( "unique" ); + createIndexOrUniqueKey( + table, + name, + !name.isEmpty(), + columnExpressions, + ordering, + unique, + selectables( table, name, columnExpressions ) + ); } } - void bindUniqueConstraints(Table table, UniqueConstraint[] constraints) { - for ( UniqueConstraint constraint : constraints ) { - final String name = constraint.name(); - final String[] columnNames = constraint.columnNames(); - createIndexOrUniqueKey( table, name, !name.isEmpty(), columnNames, null, true, - columns( table, name, columnNames ) ); + void bindUniqueConstraints(Table table, List> constraints) { + for ( AnnotationUsage constraint : constraints ) { + final String name = constraint.getString( "name" ); + final List columnNames = constraint.getList( "columnNames" ); + createIndexOrUniqueKey( + table, + name, + !name.isEmpty(), + columnNames, + null, + true, + columns( table, name, columnNames ) + ); } } - private void initializeColumns(String[] columns, String[] ordering, List list) { + private void initializeColumns(List columns, String[] ordering, List list) { for ( int i = 0, size = list.size(); i < size; i++ ) { final String description = list.get( i ); final String tmp = description.toLowerCase(Locale.ROOT); if ( tmp.endsWith( " desc" ) ) { - columns[i] = description.substring( 0, description.length() - 5 ); + columns.set( i, description.substring( 0, description.length() - 5 ) ); ordering[i] = "desc"; } else if ( tmp.endsWith( " asc" ) ) { - columns[i] = description.substring( 0, description.length() - 4 ); + columns.set( i, description.substring( 0, description.length() - 4 ) ); ordering[i] = "asc"; } else { - columns[i] = description; + columns.set( i, description ); ordering[i] = null; } } @@ -238,10 +255,10 @@ class IndexBinder { private class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource { private final MetadataBuildingContext buildingContext; private final Table table; - private final String[] columnNames; + private final List columnNames; private final String originalKeyName; - public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) { + public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, List columnNames, String originalKeyName) { this.buildingContext = buildingContext; this.table = table; this.columnNames = columnNames; @@ -275,12 +292,12 @@ class IndexBinder { } } - private List toIdentifiers(String[] names) { + private List toIdentifiers(List names) { if ( names == null ) { return emptyList(); } - final List columnNames = arrayList( names.length ); + final List columnNames = arrayList( names.size() ); for ( String name : names ) { columnNames.add( getDatabase().toIdentifier( name ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java index f449373267..940d292208 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java @@ -12,6 +12,7 @@ import org.hibernate.annotations.ListIndexBase; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.mapping.Join; +import org.hibernate.models.spi.AnnotationUsage; import jakarta.persistence.OrderColumn; @@ -32,20 +33,20 @@ public class IndexColumn extends AnnotatedColumn { } public static IndexColumn fromAnnotations( - OrderColumn orderColumn, - org.hibernate.annotations.IndexColumn indexColumn, - ListIndexBase listIndexBase, + AnnotationUsage orderColumn, + AnnotationUsage indexColumn, + AnnotationUsage listIndexBase, PropertyHolder propertyHolder, PropertyData inferredData, Map secondaryTables, MetadataBuildingContext context) { final IndexColumn column; if ( orderColumn != null ) { - column = buildColumnFromAnnotation( orderColumn, propertyHolder, inferredData, secondaryTables, context ); + column = buildColumnFromOrderColumn( orderColumn, propertyHolder, inferredData, secondaryTables, context ); } else if ( indexColumn != null ) { - column = buildColumnFromAnnotation( indexColumn, propertyHolder, inferredData, context ); - column.setBase( indexColumn.base() ); + column = buildColumnFromIndexColumn( indexColumn, propertyHolder, inferredData, context ); + column.setBase( indexColumn.getInteger( "base" ) ); } else { column = new IndexColumn(); @@ -58,7 +59,7 @@ public class IndexColumn extends AnnotatedColumn { } if ( listIndexBase != null ) { - column.setBase( listIndexBase.value() ); + column.setBase( listIndexBase.getInteger( "value" ) ); } return column; @@ -94,24 +95,25 @@ public class IndexColumn extends AnnotatedColumn { * * @return The index column */ - public static IndexColumn buildColumnFromAnnotation( - OrderColumn orderColumn, + public static IndexColumn buildColumnFromOrderColumn( + AnnotationUsage orderColumn, PropertyHolder propertyHolder, PropertyData inferredData, Map secondaryTables, MetadataBuildingContext context) { if ( orderColumn != null ) { - final String sqlType = nullIfEmpty( orderColumn.columnDefinition() ); - final String name = orderColumn.name().isEmpty() + final String sqlType = nullIfEmpty( orderColumn.getString( "columnDefinition" ) ); + final String explicitName = orderColumn.getString( "name" ); + final String name = explicitName.isEmpty() ? inferredData.getPropertyName() + "_ORDER" - : orderColumn.name(); + : explicitName; final IndexColumn column = new IndexColumn(); column.setLogicalColumnName( name ); column.setSqlType( sqlType ); - column.setNullable( orderColumn.nullable() ); + column.setNullable( orderColumn.getBoolean( "nullable" ) ); // column.setJoins( secondaryTables ); - column.setInsertable( orderColumn.insertable() ); - column.setUpdatable( orderColumn.updatable() ); + column.setInsertable( orderColumn.getBoolean( "insertable" ) ); + column.setUpdatable( orderColumn.getBoolean( "updatable" ) ); // column.setContext( context ); // column.setPropertyHolder( propertyHolder ); createParent( propertyHolder, secondaryTables, column, context ); @@ -138,22 +140,23 @@ public class IndexColumn extends AnnotatedColumn { * * @return The index column */ - public static IndexColumn buildColumnFromAnnotation( - org.hibernate.annotations.IndexColumn indexColumn, + public static IndexColumn buildColumnFromIndexColumn( + AnnotationUsage indexColumn, PropertyHolder propertyHolder, PropertyData inferredData, MetadataBuildingContext context) { if ( indexColumn != null ) { - final String sqlType = nullIfEmpty( indexColumn.columnDefinition() ); - final String name = indexColumn.name().isEmpty() + final String explicitName = indexColumn.getString( "name" ); + final String name = explicitName.isEmpty() ? inferredData.getPropertyName() - : indexColumn.name(); + : explicitName; + final String sqlType = nullIfEmpty( indexColumn.getString( "columnDefinition" ) ); //TODO move it to a getter based system and remove the constructor final IndexColumn column = new IndexColumn(); column.setLogicalColumnName( name ); column.setSqlType( sqlType ); - column.setNullable( indexColumn.nullable() ); - column.setBase( indexColumn.base() ); + column.setNullable( indexColumn.getBoolean( "nullable" ) ); + column.setBase( indexColumn.getInteger( "base" ) ); // column.setContext( context ); // column.setPropertyHolder( propertyHolder ); createParent( propertyHolder, null, column, context ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/InheritanceState.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/InheritanceState.java index 16156c606d..4d23238f2b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/InheritanceState.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/InheritanceState.java @@ -11,15 +11,16 @@ import java.util.List; import java.util.Map; import org.hibernate.AnnotationException; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.mapping.Component; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MethodDetails; import jakarta.persistence.Access; import jakarta.persistence.EmbeddedId; @@ -40,7 +41,7 @@ import static org.hibernate.boot.model.internal.PropertyBinder.addElementsOfClas * @author Emmanuel Bernard */ public class InheritanceState { - private XClass clazz; + private ClassDetails classDetails; /** * Has sibling (either mappedsuperclass entity) @@ -53,33 +54,32 @@ public class InheritanceState { private boolean hasParents = false; private InheritanceType type; private boolean isEmbeddableSuperclass = false; - private final Map inheritanceStatePerClass; - private final List classesToProcessForMappedSuperclass = new ArrayList<>(); + private final Map inheritanceStatePerClass; + private final List classesToProcessForMappedSuperclass = new ArrayList<>(); private final MetadataBuildingContext buildingContext; private AccessType accessType; private ElementsToProcess elementsToProcess; private Boolean hasIdClassOrEmbeddedId; public InheritanceState( - XClass clazz, - Map inheritanceStatePerClass, + ClassDetails classDetails, + Map inheritanceStatePerClass, MetadataBuildingContext buildingContext) { - this.setClazz( clazz ); + this.setClassDetails( classDetails ); this.buildingContext = buildingContext; this.inheritanceStatePerClass = inheritanceStatePerClass; - extractInheritanceType(); + extractInheritanceType( classDetails ); } - private void extractInheritanceType() { - XAnnotatedElement element = getClazz(); - Inheritance inhAnn = element.getAnnotation( Inheritance.class ); - MappedSuperclass mappedSuperClass = element.getAnnotation( MappedSuperclass.class ); - if ( mappedSuperClass != null ) { + private void extractInheritanceType(ClassDetails classDetails) { + final AnnotationUsage inheritanceAnn = classDetails.getAnnotationUsage( Inheritance.class ); + final AnnotationUsage mappedSuperAnn = classDetails.getAnnotationUsage( MappedSuperclass.class ); + if ( mappedSuperAnn != null ) { setEmbeddableSuperclass( true ); - setType( inhAnn == null ? null : inhAnn.strategy() ); + setType( inheritanceAnn == null ? null : inheritanceAnn.getEnum( "strategy", InheritanceType.class ) ); } else { - setType( inhAnn == null ? SINGLE_TABLE : inhAnn.strategy() ); + setType( inheritanceAnn == null ? SINGLE_TABLE : inheritanceAnn.getEnum( "strategy", InheritanceType.class ) ); } } @@ -91,23 +91,27 @@ public class InheritanceState { return hasParents() && TABLE_PER_CLASS == getType(); } - public static InheritanceState getInheritanceStateOfSuperEntity(XClass clazz, Map states) { - XClass superclass = clazz; + public static InheritanceState getInheritanceStateOfSuperEntity( + ClassDetails classDetails, + Map states) { + ClassDetails candidate = classDetails; do { - superclass = superclass.getSuperclass(); - final InheritanceState currentState = states.get( superclass ); + candidate = candidate.getSuperClass(); + final InheritanceState currentState = states.get( candidate ); if ( currentState != null && !currentState.isEmbeddableSuperclass() ) { return currentState; } } - while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) ); + while ( candidate != null && !Object.class.getName().equals( candidate.getName() ) ); return null; } - public static InheritanceState getSuperclassInheritanceState(XClass clazz, Map states) { - XClass superclass = clazz; + public static InheritanceState getSuperclassInheritanceState( + ClassDetails classDetails, + Map states) { + ClassDetails superclass = classDetails; do { - superclass = superclass.getSuperclass(); + superclass = superclass.getSuperClass(); InheritanceState currentState = states.get( superclass ); if ( currentState != null ) { return currentState; @@ -117,12 +121,12 @@ public class InheritanceState { return null; } - public XClass getClazz() { - return clazz; + public ClassDetails getClassDetails() { + return classDetails; } - public void setClazz(XClass clazz) { - this.clazz = clazz; + public void setClassDetails(ClassDetails classDetails) { + this.classDetails = classDetails; } public boolean hasSiblings() { @@ -174,15 +178,15 @@ public class InheritanceState { addMappedSuperClassInMetadata( component ); } - public XClass getClassWithIdClass(boolean evenIfSubclass) { + public ClassDetails getClassWithIdClass(boolean evenIfSubclass) { if ( !evenIfSubclass && hasParents() ) { return null; } - else if ( clazz.isAnnotationPresent( IdClass.class ) ) { - return clazz; + else if ( classDetails.hasAnnotationUsage( IdClass.class ) ) { + return classDetails; } else { - final InheritanceState state = getSuperclassInheritanceState( clazz, inheritanceStatePerClass ); + final InheritanceState state = getSuperclassInheritanceState( classDetails, inheritanceStatePerClass ); if ( state != null ) { return state.getClassWithIdClass( true ); } @@ -201,7 +205,7 @@ public class InheritanceState { else { final ElementsToProcess process = getElementsToProcess(); for ( PropertyData property : process.getElements() ) { - if ( property.getProperty().isAnnotationPresent( EmbeddedId.class ) ) { + if ( property.getAttributeMember().hasAnnotationUsage( EmbeddedId.class ) ) { hasIdClassOrEmbeddedId = true; break; } @@ -218,7 +222,7 @@ public class InheritanceState { */ private ElementsToProcess getElementsToProcess() { if ( elementsToProcess == null ) { - InheritanceState inheritanceState = inheritanceStatePerClass.get( clazz ); + InheritanceState inheritanceState = inheritanceStatePerClass.get( classDetails ); assert !inheritanceState.isEmbeddableSuperclass(); getMappedSuperclassesTillNextEntityOrdered(); @@ -228,10 +232,10 @@ public class InheritanceState { final ArrayList elements = new ArrayList<>(); int idPropertyCount = 0; - for ( XClass classToProcessForMappedSuperclass : classesToProcessForMappedSuperclass ) { + for ( ClassDetails classToProcessForMappedSuperclass : classesToProcessForMappedSuperclass ) { PropertyContainer propertyContainer = new PropertyContainer( classToProcessForMappedSuperclass, - clazz, + classDetails, accessType ); int currentIdPropertyCount = addElementsOfClass( @@ -243,7 +247,7 @@ public class InheritanceState { } if ( idPropertyCount == 0 && !inheritanceState.hasParents() ) { - throw new AnnotationException( "Entity '" + clazz.getName() + "' has no identifier" + throw new AnnotationException( "Entity '" + classDetails.getName() + "' has no identifier" + " (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)" ); } elements.trimToSize(); @@ -253,57 +257,54 @@ public class InheritanceState { } private AccessType determineDefaultAccessType() { - for ( XClass xclass = clazz; xclass != null; xclass = xclass.getSuperclass() ) { - if ( ( xclass.getSuperclass() == null || Object.class.getName().equals( xclass.getSuperclass().getName() ) ) - && ( xclass.isAnnotationPresent( Entity.class ) || xclass.isAnnotationPresent( MappedSuperclass.class ) ) - && xclass.isAnnotationPresent( Access.class ) ) { - return AccessType.getAccessStrategy( xclass.getAnnotation( Access.class ).value() ); + for ( ClassDetails candidate = classDetails; candidate != null; candidate = candidate.getSuperClass() ) { + if ( ( candidate.getSuperClass() == null || Object.class.getName().equals( candidate.getSuperClass().getName() ) ) + && ( candidate.hasAnnotationUsage( Entity.class ) || candidate.hasAnnotationUsage( MappedSuperclass.class ) ) + && candidate.hasAnnotationUsage( Access.class ) ) { + return AccessType.getAccessStrategy( candidate.getAnnotationUsage( Access.class ).getEnum( "value" ) ); } } // Guess from identifier. // FIX: Shouldn't this be determined by the first attribute (i.e., field or property) with annotations, // but without an explicit Access annotation, according to JPA 2.0 spec 2.3.1: Default Access Type? - for ( XClass xclass = clazz; - xclass != null && !Object.class.getName().equals( xclass.getName() ); - xclass = xclass.getSuperclass() ) { - if ( xclass.isAnnotationPresent( Entity.class ) || xclass.isAnnotationPresent( MappedSuperclass.class ) ) { - for ( XProperty prop : xclass.getDeclaredProperties( AccessType.PROPERTY.getType() ) ) { - final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class ); - if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) { + for ( ClassDetails candidate = classDetails; + candidate != null && !Object.class.getName().equals( candidate.getName() ); + candidate = candidate.getSuperClass() ) { + if ( candidate.hasAnnotationUsage( Entity.class ) || candidate.hasAnnotationUsage( MappedSuperclass.class ) ) { + for ( MethodDetails method : candidate.getMethods() ) { + if ( method.getMethodKind() != MethodDetails.MethodKind.GETTER ) { + continue; + } + + if ( method.hasAnnotationUsage( Id.class ) || method.hasAnnotationUsage( EmbeddedId.class ) ) { return AccessType.PROPERTY; } } - for ( XProperty prop : xclass.getDeclaredProperties( AccessType.FIELD.getType() ) ) { - final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class ); - if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) { + + for ( FieldDetails field : candidate.getFields() ) { + if ( field.hasAnnotationUsage( Id.class ) || field.hasAnnotationUsage( EmbeddedId.class ) ) { return AccessType.FIELD; } } - for ( XProperty prop : xclass.getDeclaredProperties( AccessType.RECORD.getType() ) ) { - final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class ); - if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) { - return AccessType.RECORD; - } - } } } - throw new AnnotationException( "Entity '" + clazz.getName() + "' has no identifier" - + " (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)" ); + throw new AnnotationException( "Entity '" + classDetails.getName() + "' has no identifier" + + " (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)" ); } private void getMappedSuperclassesTillNextEntityOrdered() { //ordered to allow proper messages on properties subclassing - XClass currentClassInHierarchy = clazz; + ClassDetails currentClassInHierarchy = classDetails; InheritanceState superclassState; do { classesToProcessForMappedSuperclass.add( 0, currentClassInHierarchy ); - XClass superClass = currentClassInHierarchy; + ClassDetails superClass = currentClassInHierarchy; do { - superClass = superClass.getSuperclass(); + superClass = superClass.getSuperClass(); superclassState = inheritanceStatePerClass.get( superClass ); } while ( superClass != null - && !buildingContext.getBootstrapContext().getReflectionManager().equals( superClass, Object.class ) + && !Object.class.getName().equals( superClass.getClassName() ) && superclassState == null ); currentClassInHierarchy = superClass; @@ -328,23 +329,25 @@ public class InheritanceState { private org.hibernate.mapping.MappedSuperclass processMappedSuperclass(Table implicitTable) { //add @MappedSuperclass in the metadata // classes from 0 to n-1 are @MappedSuperclass and should be linked - final InheritanceState superEntityState = getInheritanceStateOfSuperEntity( clazz, inheritanceStatePerClass ); + final InheritanceState superEntityState = getInheritanceStateOfSuperEntity( classDetails, inheritanceStatePerClass ); final PersistentClass superEntity = superEntityState != null ? - buildingContext.getMetadataCollector().getEntityBinding( superEntityState.getClazz().getName() ) : + buildingContext.getMetadataCollector().getEntityBinding( superEntityState.getClassDetails().getName() ) : null; final int lastMappedSuperclass = classesToProcessForMappedSuperclass.size() - 1; org.hibernate.mapping.MappedSuperclass mappedSuperclass = null; for ( int index = 0; index < lastMappedSuperclass; index++ ) { org.hibernate.mapping.MappedSuperclass parentSuperclass = mappedSuperclass; - final Class type = buildingContext.getBootstrapContext().getReflectionManager() - .toClass( classesToProcessForMappedSuperclass.get( index ) ); + // todo (jpa32) : causes the mapped-superclass Class reference to be loaded... + // - but this is how it's always worked, so... + final ClassDetails mappedSuperclassDetails = classesToProcessForMappedSuperclass.get( index ); + final Class mappedSuperclassJavaType = mappedSuperclassDetails.toJavaClass(); //add MappedSuperclass if not already there - mappedSuperclass = buildingContext.getMetadataCollector().getMappedSuperclass( type ); + mappedSuperclass = buildingContext.getMetadataCollector().getMappedSuperclass( mappedSuperclassJavaType ); if ( mappedSuperclass == null ) { mappedSuperclass = new org.hibernate.mapping.MappedSuperclass( parentSuperclass, superEntity, implicitTable ); - mappedSuperclass.setMappedClass( type ); - buildingContext.getMetadataCollector().addMappedSuperclass( type, mappedSuperclass ); + mappedSuperclass.setMappedClass( mappedSuperclassJavaType ); + buildingContext.getMetadataCollector().addMappedSuperclass( mappedSuperclassJavaType, mappedSuperclass ); } } return mappedSuperclass; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/JPAXMLOverriddenAnnotationReader.java index 9d60db24de..5857611fb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/JPAXMLOverriddenAnnotationReader.java @@ -2222,7 +2222,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { List storedProcedureParameters = new ArrayList<>(); - for ( JaxbStoredProcedureParameterImpl parameterElement : element.getParameter() ) { + for ( JaxbStoredProcedureParameterImpl parameterElement : element.getProcedureParameters() ) { AnnotationDescriptor parameterDescriptor = new AnnotationDescriptor( StoredProcedureParameter.class ); copyAttribute( parameterDescriptor, "name", parameterElement.getName(), false ); ParameterMode modeValue = parameterElement.getMode(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java index 4e63684575..b2b4640bfc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ListBinder.java @@ -20,6 +20,7 @@ import org.hibernate.mapping.List; import org.hibernate.mapping.OneToMany; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SimpleValue; +import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.usertype.UserCollectionType; @@ -49,7 +50,7 @@ public class ListBinder extends CollectionBinder { } @Override - public void setSqlOrderBy(OrderBy orderByAnn) { + public void setSqlOrderBy(AnnotationUsage orderByAnn) { if ( orderByAnn != null ) { throw new AnnotationException( "A collection of type 'List' is annotated '@OrderBy'" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapBinder.java index a5b5665fdf..827fc2759d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapBinder.java @@ -14,10 +14,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; import org.hibernate.MappingException; import org.hibernate.annotations.MapKeyCompositeType; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.AccessType; -import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.SecondPass; import org.hibernate.engine.jdbc.Size; @@ -36,6 +33,11 @@ import org.hibernate.mapping.Selectable; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.Value; +import org.hibernate.models.internal.ClassTypeDetailsImpl; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.BasicType; import org.hibernate.usertype.CompositeUserType; @@ -44,6 +46,7 @@ import org.hibernate.usertype.UserCollectionType; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; import jakarta.persistence.ConstraintMode; +import jakarta.persistence.ForeignKey; import jakarta.persistence.InheritanceType; import jakarta.persistence.MapKeyClass; import jakarta.persistence.MapKeyColumn; @@ -107,11 +110,9 @@ public class MapBinder extends CollectionBinder { }; } - private void makeOneToManyMapKeyColumnNullableIfNotInProperty( - final XProperty property) { + private void makeOneToManyMapKeyColumnNullableIfNotInProperty(MemberDetails property) { final Map map = (Map) this.collection; - if ( map.isOneToMany() && - property.isAnnotationPresent( MapKeyColumn.class ) ) { + if ( map.isOneToMany() && property.hasAnnotationUsage( MapKeyColumn.class ) ) { final Value indexValue = map.getIndex(); if ( indexValue.getColumnSpan() != 1 ) { throw new AssertionFailure( "Map key mapped by @MapKeyColumn does not have 1 column" ); @@ -150,11 +151,11 @@ public class MapBinder extends CollectionBinder { } private void bindKeyFromAssociationTable( - XClass elementType, + TypeDetails elementType, java.util.Map persistentClasses, boolean hasMapKeyProperty, String mapKeyPropertyName, - XProperty property, + MemberDetails property, boolean isEmbedded, AnnotatedColumns mapKeyColumns, AnnotatedJoinColumns mapKeyManyToManyColumns) { @@ -170,7 +171,7 @@ public class MapBinder extends CollectionBinder { private void handleMapKey( java.util.Map persistentClasses, - XProperty property, + MemberDetails property, boolean isEmbedded, AnnotatedColumns mapKeyColumns, AnnotatedJoinColumns mapKeyManyToManyColumns) { @@ -184,14 +185,15 @@ public class MapBinder extends CollectionBinder { bindManyToManyInverseForeignKey( collectionEntity, mapKeyManyToManyColumns, element, false ); } else { - final XClass keyClass = mapKeyClass( mapKeyType ); + final ClassDetails keyClass = mapKeyClass( mapKeyType ); + final TypeDetails keyTypeDetails = new ClassTypeDetailsImpl( keyClass, TypeDetails.Kind.CLASS ); handleMapKey( property, mapKeyColumns, mapKeyType, - keyClass, - annotatedMapKeyType( property, isEmbedded, mapKeyType, keyClass ), - buildCollectionPropertyHolder( property, keyClass ), + keyTypeDetails, + annotatedMapKeyType( property, isEmbedded, mapKeyType, keyTypeDetails ), + buildCollectionPropertyHolder( property, keyTypeDetails ), accessType( property, collection.getOwner() ) ); } @@ -205,10 +207,10 @@ public class MapBinder extends CollectionBinder { } private AnnotatedClassType annotatedMapKeyType( - XProperty property, + MemberDetails property, boolean isEmbedded, String mapKeyType, - XClass keyClass) { + TypeDetails keyTypeDetails) { if ( isPrimitive( mapKeyType ) ) { return NONE; } @@ -216,32 +218,31 @@ public class MapBinder extends CollectionBinder { // force in case of attribute override naming the key return isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property ) ? EMBEDDABLE - : buildingContext.getMetadataCollector().getClassType( keyClass ); + : buildingContext.getMetadataCollector().getClassType( keyTypeDetails.determineRawClass() ); } } - private XClass mapKeyClass(String mapKeyType) { + private ClassDetails mapKeyClass(String mapKeyType) { if ( isPrimitive( mapKeyType ) ) { return null; } else { - final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext(); - final Class mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType ); - return bootstrapContext.getReflectionManager().toXClass( mapKeyClass ); + return buildingContext.getMetadataCollector().getSourceModelBuildingContext().getClassDetailsRegistry().resolveClassDetails( mapKeyType ); } } - private static String getKeyType(XProperty property) { + private static String getKeyType(MemberDetails property) { //target has priority over reflection for the map key type //JPA 2 has priority - final Class target = property.isAnnotationPresent( MapKeyClass.class ) - ? property.getAnnotation( MapKeyClass.class ).value() + final AnnotationUsage mapKeyClassAnn = property.getAnnotationUsage( MapKeyClass.class ); + final Class target = mapKeyClassAnn != null + ? mapKeyClassAnn.getClassDetails( "value" ).toJavaClass() : void.class; - return void.class.equals( target ) ? property.getMapKey().getName() : target.getName(); + return void.class.equals( target ) ? property.getMapKeyType().getName() : target.getName(); } private void handleMapKeyProperty( - XClass elementType, + TypeDetails elementType, java.util.Map persistentClasses, String mapKeyPropertyName) { final PersistentClass associatedClass = persistentClasses.get( elementType.getName() ); @@ -255,7 +256,7 @@ public class MapBinder extends CollectionBinder { + "' not found in target entity '" + associatedClass.getEntityName() + "'" ); } // HHH-11005 - if InheritanceType.JOINED then need to find class defining the column - final InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType ); + final InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType.determineRawClass() ); final PersistentClass targetEntity = InheritanceType.JOINED == inheritanceState.getType() ? mapProperty.getPersistentClass() : associatedClass; @@ -265,8 +266,13 @@ public class MapBinder extends CollectionBinder { } private CollectionPropertyHolder buildCollectionPropertyHolder( - XProperty property, - XClass keyClass) { + MemberDetails property, + TypeDetails keyClass) { + return buildCollectionPropertyHolder( property, keyClass.determineRawClass() ); + } + private CollectionPropertyHolder buildCollectionPropertyHolder( + MemberDetails property, + ClassDetails keyClass) { final CollectionPropertyHolder holder = buildPropertyHolder( collection, qualify( collection.getRole(), "mapkey" ), @@ -283,18 +289,17 @@ public class MapBinder extends CollectionBinder { return holder; } - private void handleForeignKey(XProperty property, ManyToOne element) { - final jakarta.persistence.ForeignKey foreignKey = getMapKeyForeignKey( property ); + private void handleForeignKey(MemberDetails property, ManyToOne element) { + final AnnotationUsage foreignKey = getMapKeyForeignKey( property ); if ( foreignKey != null ) { - final ConstraintMode constraintMode = foreignKey.value(); + final ConstraintMode constraintMode = foreignKey.getEnum( "value" ); if ( constraintMode == ConstraintMode.NO_CONSTRAINT - || constraintMode == ConstraintMode.PROVIDER_DEFAULT - && getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) { + || constraintMode == ConstraintMode.PROVIDER_DEFAULT && getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) { element.disableForeignKey(); } else { - element.setForeignKeyName( nullIfEmpty( foreignKey.name() ) ); - element.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) ); + element.setForeignKeyName( nullIfEmpty( foreignKey.getString( "name" ) ) ); + element.setForeignKeyDefinition( nullIfEmpty( foreignKey.getString( "foreignKeyDefinition" ) ) ); } } } @@ -315,28 +320,28 @@ public class MapBinder extends CollectionBinder { } private void handleMapKey( - XProperty property, + MemberDetails property, AnnotatedColumns mapKeyColumns, String mapKeyType, - XClass keyClass, + TypeDetails keyTypeDetails, AnnotatedClassType classType, CollectionPropertyHolder holder, AccessType accessType) { - final Class> compositeUserType = - resolveCompositeUserType( property, keyClass, buildingContext ); + final Class> compositeUserType + = resolveCompositeUserType( property, keyTypeDetails, buildingContext ); if ( classType == EMBEDDABLE || compositeUserType != null ) { - handleCompositeMapKey( keyClass, holder, accessType, compositeUserType ); + handleCompositeMapKey( keyTypeDetails, holder, accessType, compositeUserType ); } else { - handleMapKey( property, mapKeyColumns, mapKeyType, keyClass, holder, accessType ); + handleMapKey( property, mapKeyColumns, mapKeyType, keyTypeDetails, holder, accessType ); } } private void handleMapKey( - XProperty property, + MemberDetails property, AnnotatedColumns mapKeyColumns, String mapKeyType, - XClass keyClass, + TypeDetails keyTypeDetails, CollectionPropertyHolder holder, AccessType accessType) { final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext ); @@ -353,9 +358,9 @@ public class MapBinder extends CollectionBinder { //the algorithm generally does not apply for map key anyway elementBinder.setType( property, - keyClass, + keyTypeDetails, collection.getOwnerEntityName(), - holder.mapKeyAttributeConverterDescriptor( property, keyClass ) + holder.mapKeyAttributeConverterDescriptor( property, keyTypeDetails ) ); elementBinder.setPersistentClassName( propertyHolder.getEntityName() ); elementBinder.setAccessType( accessType ); @@ -363,13 +368,13 @@ public class MapBinder extends CollectionBinder { } private void handleCompositeMapKey( - XClass keyClass, + TypeDetails keyTypeDetails, CollectionPropertyHolder holder, AccessType accessType, Class> compositeUserType) { getMap().setIndex( fillEmbeddable( holder, - propertyPreloadedData( keyClass ), + propertyPreloadedData( keyTypeDetails ), accessType, //TODO be smart with isNullable true, @@ -385,55 +390,51 @@ public class MapBinder extends CollectionBinder { ) ); } - private PropertyPreloadedData propertyPreloadedData(XClass keyClass) { + private PropertyPreloadedData propertyPreloadedData(TypeDetails keyTypeDetails) { return isHibernateExtensionMapping() - ? new PropertyPreloadedData( AccessType.PROPERTY, "index", keyClass ) + ? new PropertyPreloadedData( AccessType.PROPERTY, "index", keyTypeDetails ) // "key" is the JPA 2 prefix for map keys - : new PropertyPreloadedData( AccessType.PROPERTY, "key", keyClass ); + : new PropertyPreloadedData( AccessType.PROPERTY, "key", keyTypeDetails ); } private static Class> resolveCompositeUserType( - XProperty property, - XClass returnedClass, + MemberDetails property, + TypeDetails returnedClass, MetadataBuildingContext context) { - final MapKeyCompositeType compositeType = property.getAnnotation( MapKeyCompositeType.class ); + final AnnotationUsage compositeType = property.getAnnotationUsage( MapKeyCompositeType.class ); if ( compositeType != null ) { - return compositeType.value(); + final ClassDetails compositeTypeImplDetails = compositeType.getClassDetails( "value" ); + return compositeTypeImplDetails.toJavaClass(); } if ( returnedClass != null ) { - final Class embeddableClass = context.getBootstrapContext() - .getReflectionManager() - .toClass( returnedClass ); - if ( embeddableClass != null ) { - return context.getMetadataCollector().findRegisteredCompositeUserType( embeddableClass ); - } + return context.getMetadataCollector().findRegisteredCompositeUserType( returnedClass.determineRawClass().toJavaClass() ); } return null; } - private jakarta.persistence.ForeignKey getMapKeyForeignKey(XProperty property) { - final MapKeyJoinColumns mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class ); - final MapKeyJoinColumn mapKeyJoinColumn = property.getAnnotation( MapKeyJoinColumn.class ); + private AnnotationUsage getMapKeyForeignKey(MemberDetails property) { + final AnnotationUsage mapKeyJoinColumns = property.getAnnotationUsage( MapKeyJoinColumns.class ); + final AnnotationUsage mapKeyJoinColumn = property.getAnnotationUsage( MapKeyJoinColumn.class ); if ( mapKeyJoinColumns != null ) { - return mapKeyJoinColumns.foreignKey(); + return mapKeyJoinColumns.getNestedUsage( "foreignKey" ); } else if ( mapKeyJoinColumn != null ) { - return mapKeyJoinColumn.foreignKey(); + return mapKeyJoinColumn.getNestedUsage( "foreignKey" ); } else { return null; } } - private boolean mappingDefinedAttributeOverrideOnMapKey(XProperty property) { - if ( property.isAnnotationPresent( AttributeOverride.class ) ) { - return namedMapKey( property.getAnnotation( AttributeOverride.class ) ); + private boolean mappingDefinedAttributeOverrideOnMapKey(MemberDetails property) { + if ( property.hasAnnotationUsage( AttributeOverride.class ) ) { + return namedMapKey( property.getAnnotationUsage( AttributeOverride.class ) ); } - if ( property.isAnnotationPresent( AttributeOverrides.class ) ) { - final AttributeOverrides annotations = property.getAnnotation( AttributeOverrides.class ); - for ( AttributeOverride attributeOverride : annotations.value() ) { + if ( property.hasAnnotationUsage( AttributeOverrides.class ) ) { + final AnnotationUsage annotations = property.getAnnotationUsage( AttributeOverrides.class ); + for ( AnnotationUsage attributeOverride : annotations.>getList( "value" ) ) { if ( namedMapKey( attributeOverride ) ) { return true; } @@ -442,8 +443,8 @@ public class MapBinder extends CollectionBinder { return false; } - private boolean namedMapKey(AttributeOverride annotation) { - return annotation.name().startsWith( "key." ); + private boolean namedMapKey(AnnotationUsage annotation) { + return annotation.getString( "name" ).startsWith( "key." ); } private Value createFormulatedValue( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyColumnDelegator.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyColumnDelegator.java deleted file mode 100644 index 9b25031dfe..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyColumnDelegator.java +++ /dev/null @@ -1,95 +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.boot.model.internal; - -import java.lang.annotation.Annotation; - -import jakarta.persistence.CheckConstraint; -import jakarta.persistence.Column; -import jakarta.persistence.MapKeyColumn; - -/** - * @author Emmanuel Bernard - */ -@SuppressWarnings({ "ClassExplicitlyAnnotation" }) -public class MapKeyColumnDelegator implements Column { - private final MapKeyColumn column; - - public MapKeyColumnDelegator(MapKeyColumn column) { - this.column = column; - } - - @Override - public String name() { - return column.name(); - } - - @Override - public boolean unique() { - return column.unique(); - } - - @Override - public boolean nullable() { - return column.nullable(); - } - - @Override - public boolean insertable() { - return column.insertable(); - } - - @Override - public boolean updatable() { - return column.updatable(); - } - - @Override - public String columnDefinition() { - return column.columnDefinition(); - } - - @Override - public String options() { - return column.options(); - } - - @Override - public String table() { - return column.table(); - } - - @Override - public int length() { - return column.length(); - } - - @Override - public int precision() { - return column.precision(); - } - - @Override - public int scale() { - return column.scale(); - } - - @Override - public CheckConstraint[] check() { - return new CheckConstraint[0]; - } - - @Override - public String comment() { - return ""; - } - - @Override - public Class annotationType() { - return Column.class; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyJoinColumnDelegator.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyJoinColumnDelegator.java index 77966aac63..e53986b015 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyJoinColumnDelegator.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/MapKeyJoinColumnDelegator.java @@ -8,6 +8,12 @@ package org.hibernate.boot.model.internal; import java.lang.annotation.Annotation; +import org.hibernate.boot.models.JpaAnnotations; +import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; + import jakarta.persistence.CheckConstraint; import jakarta.persistence.Column; import jakarta.persistence.ForeignKey; @@ -21,10 +27,37 @@ import jakarta.persistence.MapKeyJoinColumn; public class MapKeyJoinColumnDelegator implements JoinColumn { private final MapKeyJoinColumn column; + public MapKeyJoinColumnDelegator(AnnotationUsage column) { + this( column.toAnnotation() ); + } + public MapKeyJoinColumnDelegator(MapKeyJoinColumn column) { this.column = column; } + public static MutableAnnotationUsage fromMapKeyJoinColumn( + AnnotationUsage mapKeyJoinColumn, + MemberDetails attributeMember, + MetadataBuildingContext context) { + final MutableAnnotationUsage joinColumn = JpaAnnotations.JOIN_COLUMN.createUsage( + attributeMember, + context.getMetadataCollector().getSourceModelBuildingContext() + ); + + joinColumn.setAttributeValue( "name", mapKeyJoinColumn.getAttributeValue( "name" ) ); + joinColumn.setAttributeValue( "table", mapKeyJoinColumn.getAttributeValue( "table" ) ); + joinColumn.setAttributeValue( "unique", mapKeyJoinColumn.getAttributeValue( "unique" ) ); + joinColumn.setAttributeValue( "nullable", mapKeyJoinColumn.getAttributeValue( "nullable" ) ); + joinColumn.setAttributeValue( "insertable", mapKeyJoinColumn.getAttributeValue( "insertable" ) ); + joinColumn.setAttributeValue( "referencedColumnName", mapKeyJoinColumn.getAttributeValue( "referencedColumnName" ) ); + joinColumn.setAttributeValue( "columnDefinition", mapKeyJoinColumn.getAttributeValue( "columnDefinition" ) ); + joinColumn.setAttributeValue( "options", mapKeyJoinColumn.getAttributeValue( "options" ) ); +// joinColumn.setAttributeValue( "comment", mapKeyJoinColumn.getAttributeValue( "comment" ) ); + joinColumn.setAttributeValue( "foreignKey", mapKeyJoinColumn.getAttributeValue( "foreignKey" ) ); + + return joinColumn; + } + @Override public String name() { return column.name(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java index fc04221faa..a8d8d3ff3c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java @@ -13,7 +13,6 @@ import org.hibernate.MappingException; import org.hibernate.annotations.LazyGroup; import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.OnDeleteAction; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.boot.spi.SecondPass; @@ -27,6 +26,9 @@ import org.hibernate.mapping.OneToOne; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.SortableValue; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; import org.hibernate.type.ForeignKeyDirection; import jakarta.persistence.ForeignKey; @@ -45,16 +47,16 @@ import static org.hibernate.type.ForeignKeyDirection.TO_PARENT; * in a second pass. */ public class OneToOneSecondPass implements SecondPass { - private final MetadataBuildingContext buildingContext; + private final PropertyData inferredData; + private final PropertyHolder propertyHolder; private final String mappedBy; private final String ownerEntity; - private final PropertyHolder propertyHolder; private final NotFoundAction notFoundAction; - private final PropertyData inferredData; private final OnDeleteAction onDeleteAction; private final boolean optional; private final String cascadeStrategy; private final AnnotatedJoinColumns joinColumns; + private final MetadataBuildingContext buildingContext; private final String referencedEntityName; private final boolean annotatedEntity; @@ -95,7 +97,7 @@ public class OneToOneSecondPass implements SecondPass { final String propertyName = inferredData.getPropertyName(); value.setPropertyName( propertyName ); value.setReferencedEntityName( referencedEntityName ); - XProperty property = inferredData.getProperty(); + MemberDetails property = inferredData.getAttributeMember(); defineFetchingStrategy( value, property, inferredData, propertyHolder ); //value.setFetchMode( fetchMode ); value.setOnDeleteAction( onDeleteAction ); @@ -103,20 +105,20 @@ public class OneToOneSecondPass implements SecondPass { value.setConstrained( !optional ); value.setForeignKeyType( getForeignKeyDirection() ); - bindForeignKeyNameAndDefinition( value, property, property.getAnnotation( ForeignKey.class ), buildingContext ); + bindForeignKeyNameAndDefinition( value, property, property.getAnnotationUsage( ForeignKey.class ), buildingContext ); final PropertyBinder binder = new PropertyBinder(); binder.setName( propertyName ); - binder.setProperty( property ); + binder.setMemberDetails( property ); binder.setValue( value ); binder.setCascade( cascadeStrategy ); binder.setAccessType( inferredData.getDefaultAccess() ); binder.setBuildingContext( buildingContext ); binder.setHolder( propertyHolder ); - final LazyGroup lazyGroupAnnotation = property.getAnnotation( LazyGroup.class ); + final AnnotationUsage lazyGroupAnnotation = property.getAnnotationUsage( LazyGroup.class ); if ( lazyGroupAnnotation != null ) { - binder.setLazyGroup( lazyGroupAnnotation.value() ); + binder.setLazyGroup( lazyGroupAnnotation.getString( "value" ) ); } final Property result = binder.makeProperty(); @@ -148,7 +150,7 @@ public class OneToOneSecondPass implements SecondPass { } final Property targetProperty = targetProperty( oneToOne, targetEntity ); if ( targetProperty.getValue() instanceof OneToOne ) { - propertyHolder.addProperty( property, inferredData.getDeclaringClass() ); + propertyHolder.addProperty( property, inferredData.getAttributeMember(), inferredData.getDeclaringClass() ); } else if ( targetProperty.getValue() instanceof ManyToOne ) { bindTargetManyToOne( persistentClasses, oneToOne, property, targetEntity, targetProperty ); @@ -186,15 +188,7 @@ public class OneToOneSecondPass implements SecondPass { final Join mappedByJoin = buildJoinFromMappedBySide( persistentClasses.get( ownerEntity ), targetProperty, otherSideJoin ); - final ManyToOne manyToOne = new ManyToOne( buildingContext, mappedByJoin.getTable() ); - manyToOne.setNotFoundAction( notFoundAction ); - manyToOne.setOnDeleteAction( oneToOne.getOnDeleteAction() ); - manyToOne.setFetchMode( oneToOne.getFetchMode() ); - manyToOne.setLazy( oneToOne.isLazy() ); - manyToOne.setReferencedEntityName( oneToOne.getReferencedEntityName() ); - manyToOne.setReferencedPropertyName( mappedBy ); - manyToOne.setUnwrapProxy( oneToOne.isUnwrapProxy() ); - manyToOne.markAsLogicalOneToOne(); + final ManyToOne manyToOne = createManyToOne( oneToOne, mappedByJoin ); property.setValue( manyToOne ); for ( Column column: otherSideJoin.getKey().getColumns() ) { Column copy = column.clone(); @@ -204,7 +198,7 @@ public class OneToOneSecondPass implements SecondPass { mappedByJoin.addProperty( property ); } else { - propertyHolder.addProperty( property, inferredData.getDeclaringClass() ); + propertyHolder.addProperty( property, inferredData.getAttributeMember(), inferredData.getDeclaringClass() ); } oneToOne.setReferencedPropertyName( mappedBy ); @@ -225,6 +219,19 @@ public class OneToOneSecondPass implements SecondPass { } } + private ManyToOne createManyToOne(OneToOne oneToOne, Join mappedByJoin) { + final ManyToOne manyToOne = new ManyToOne( buildingContext, mappedByJoin.getTable() ); + manyToOne.setNotFoundAction( notFoundAction ); + manyToOne.setOnDeleteAction( oneToOne.getOnDeleteAction() ); + manyToOne.setFetchMode( oneToOne.getFetchMode() ); + manyToOne.setLazy( oneToOne.isLazy() ); + manyToOne.setReferencedEntityName( oneToOne.getReferencedEntityName() ); + manyToOne.setReferencedPropertyName( mappedBy ); + manyToOne.setUnwrapProxy( oneToOne.isUnwrapProxy() ); + manyToOne.markAsLogicalOneToOne(); + return manyToOne; + } + private Property targetProperty(OneToOne oneToOne, PersistentClass targetEntity) { try { Property targetProperty = findPropertyByName( targetEntity, mappedBy ); @@ -256,7 +263,7 @@ public class OneToOneSecondPass implements SecondPass { ); secondPass.doSecondPass(persistentClasses); //no column associated since it's a one to one - propertyHolder.addProperty( property, inferredData.getDeclaringClass() ); + propertyHolder.addProperty( property, inferredData.getAttributeMember(), inferredData.getDeclaringClass() ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java index 5c98e401d0..841210e13d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java @@ -11,20 +11,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.ElementCollection; -import jakarta.persistence.EmbeddedId; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.JoinColumns; -import jakarta.persistence.Lob; -import jakarta.persistence.ManyToMany; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.MapsId; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.Version; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; @@ -40,12 +26,10 @@ import org.hibernate.annotations.NaturalId; import org.hibernate.annotations.OptimisticLock; import org.hibernate.annotations.Parent; import org.hibernate.annotations.ValueGenerationType; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.binder.AttributeBinder; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.spi.AccessType; @@ -67,35 +51,52 @@ import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.Value; import org.hibernate.metamodel.spi.EmbeddableInstantiator; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.resource.beans.container.spi.BeanContainer; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.service.ServiceRegistry; import org.hibernate.usertype.CompositeUserType; + import org.jboss.logging.Logger; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Version; + import static jakarta.persistence.FetchType.LAZY; import static java.util.Collections.singletonList; import static org.hibernate.boot.model.internal.AnyBinder.bindAny; +import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; +import static org.hibernate.boot.model.internal.BinderHelper.getPath; +import static org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId; +import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation; import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId; import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal; import static org.hibernate.boot.model.internal.ClassPropertyHolder.handleGenericComponentProperty; import static org.hibernate.boot.model.internal.ClassPropertyHolder.prepareActualProperty; import static org.hibernate.boot.model.internal.CollectionBinder.bindCollection; -import static org.hibernate.boot.model.internal.GeneratorBinder.createForeignGenerator; -import static org.hibernate.boot.model.internal.GeneratorBinder.createIdGenerator; -import static org.hibernate.boot.model.internal.GeneratorBinder.generatorCreator; -import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; -import static org.hibernate.boot.model.internal.BinderHelper.getPath; -import static org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId; -import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation; -import static org.hibernate.boot.model.internal.GeneratorBinder.identifierGeneratorCreator; -import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; import static org.hibernate.boot.model.internal.EmbeddableBinder.createCompositeBinder; import static org.hibernate.boot.model.internal.EmbeddableBinder.createEmbeddable; import static org.hibernate.boot.model.internal.EmbeddableBinder.isEmbedded; -import static org.hibernate.boot.model.internal.HCANNHelper.findAnnotation; -import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotations; +import static org.hibernate.boot.model.internal.GeneratorBinder.createForeignGenerator; +import static org.hibernate.boot.model.internal.GeneratorBinder.createIdGenerator; +import static org.hibernate.boot.model.internal.GeneratorBinder.generatorCreator; +import static org.hibernate.boot.model.internal.GeneratorBinder.identifierGeneratorCreator; +import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; import static org.hibernate.boot.model.internal.TimeZoneStorageHelper.resolveTimeZoneStorageCompositeUserType; import static org.hibernate.boot.model.internal.ToOneBinder.bindManyToOne; import static org.hibernate.boot.model.internal.ToOneBinder.bindOneToOne; @@ -127,7 +128,7 @@ public class PropertyBinder { private boolean updatable = true; private String cascade; private BasicValueBinder basicValueBinder; - private XClass declaringClass; + private ClassDetails declaringClass; private boolean declaringClassSet; private boolean embedded; private EntityBinder entityBinder; @@ -148,10 +149,10 @@ public class PropertyBinder { // property can be null // prefer propertyName to property.getName() since some are overloaded - private XProperty property; - private XClass returnedClass; + private MemberDetails memberDetails; + private ClassDetails returnedClass; private boolean isId; - private Map inheritanceStatePerClass; + private Map inheritanceStatePerClass; public void setInsertable(boolean insertable) { this.insertable = insertable; @@ -206,8 +207,8 @@ public class PropertyBinder { this.buildingContext = buildingContext; } - public void setDeclaringClass(XClass declaringClass) { - this.declaringClass = declaringClass; + public void setDeclaringClass(ClassDetails declaringClassDetails) { + this.declaringClass = declaringClassDetails; this.declaringClassSet = true; } @@ -215,11 +216,11 @@ public class PropertyBinder { return value instanceof ToOne; } - public void setProperty(XProperty property) { - this.property = property; + public void setMemberDetails(MemberDetails memberDetails) { + this.memberDetails = memberDetails; } - public void setReturnedClass(XClass returnedClass) { + public void setReturnedClass(ClassDetails returnedClass) { this.returnedClass = returnedClass; } @@ -239,7 +240,7 @@ public class PropertyBinder { return isId; } - public void setInheritanceStatePerClass(Map inheritanceStatePerClass) { + public void setInheritanceStatePerClass(Map inheritanceStatePerClass) { this.inheritanceStatePerClass = inheritanceStatePerClass; } @@ -258,7 +259,7 @@ public class PropertyBinder { LOG.debugf( "MetadataSourceProcessor property %s with lazy=%s", name, lazy ); final String containerClassName = holder.getClassName(); - holder.startingProperty( property ); + holder.startingProperty( memberDetails ); basicValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ATTRIBUTE, buildingContext ); basicValueBinder.setPropertyName( name ); @@ -266,10 +267,10 @@ public class PropertyBinder { basicValueBinder.setColumns( columns ); basicValueBinder.setPersistentClassName( containerClassName ); basicValueBinder.setType( - property, - returnedClass, + memberDetails, + memberDetails.getType(), containerClassName, - holder.resolveAttributeConverterDescriptor( property ) + holder.resolveAttributeConverterDescriptor( memberDetails ) ); basicValueBinder.setReferencedEntityName( referencedEntityName ); basicValueBinder.setAccessType( accessType ); @@ -281,19 +282,17 @@ public class PropertyBinder { @SuppressWarnings({"rawtypes", "unchecked"}) private void callAttributeBinders(Property property, Map persistentClasses) { - for ( Annotation containingAnnotation : findContainingAnnotations( this.property, AttributeBinderType.class ) ) { - final AttributeBinderType binderType = - containingAnnotation.annotationType().getAnnotation( AttributeBinderType.class ); + for ( AnnotationUsage binderAnnotationUsage : memberDetails.getMetaAnnotated( AttributeBinderType.class ) ) { + final AttributeBinderType binderType = binderAnnotationUsage.getAnnotationType().getAnnotation( AttributeBinderType.class ); try { - final AttributeBinder binder = binderType.binder().newInstance(); - final PersistentClass persistentClass = - entityBinder != null - ? entityBinder.getPersistentClass() - : persistentClasses.get( holder.getEntityName() ); - binder.bind( containingAnnotation, buildingContext, persistentClass, property ); + final AttributeBinder binder = binderType.binder().getConstructor().newInstance(); + final PersistentClass persistentClass = entityBinder != null + ? entityBinder.getPersistentClass() + : persistentClasses.get( holder.getEntityName() ); + binder.bind( binderAnnotationUsage.toAnnotation(), buildingContext, persistentClass, property ); } catch ( Exception e ) { - throw new AnnotationException( "error processing @AttributeBinderType annotation '" + containingAnnotation + "'", e ); + throw new AnnotationException( "error processing @AttributeBinderType annotation '" + binderAnnotationUsage.getAnnotationType() + "'", e ); } } } @@ -317,7 +316,7 @@ public class PropertyBinder { bindId( property ); } else { - holder.addProperty( property, columns, declaringClass ); + holder.addProperty( property, memberDetails, columns, declaringClass ); } callAttributeBindersInSecondPass( property ); @@ -359,15 +358,12 @@ public class PropertyBinder { } private void setDeclaredIdentifier(RootClass rootClass, MappedSuperclass superclass, Property prop) { - handleGenericComponentProperty( prop, buildingContext ); + handleGenericComponentProperty( prop, memberDetails, buildingContext ); if ( superclass == null ) { rootClass.setDeclaredIdentifierProperty( prop ); } else { - final Class type = - buildingContext.getBootstrapContext().getReflectionManager() - .toClass( declaringClass ); - prepareActualProperty( prop, type, false, buildingContext, + prepareActualProperty( prop, memberDetails, false, buildingContext, superclass::setDeclaredIdentifierProperty ); } } @@ -380,7 +376,7 @@ public class PropertyBinder { new PropertyPreloadedData(), true, false, - resolveCustomInstantiator( property, returnedClass ), + resolveCustomInstantiator( memberDetails, returnedClass ), buildingContext ); rootClass.setIdentifier( identifier ); @@ -394,12 +390,16 @@ public class PropertyBinder { } } - private Class resolveCustomInstantiator(XProperty property, XClass embeddableClass) { - if ( property.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) { - return property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value(); + private Class resolveCustomInstantiator(MemberDetails property, ClassDetails embeddableClass) { + if ( property.hasAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ) ) { + final AnnotationUsage annotationUsage = property.getAnnotationUsage( + org.hibernate.annotations.EmbeddableInstantiator.class ); + return annotationUsage.getClassDetails( "value" ).toJavaClass(); } - else if ( embeddableClass.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) { - return embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value(); + else if ( embeddableClass.hasAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ) ) { + final AnnotationUsage annotationUsage = embeddableClass.getAnnotationUsage( + org.hibernate.annotations.EmbeddableInstantiator.class ); + return annotationUsage.getClassDetails( "value" ).toJavaClass(); } else { return null; @@ -430,22 +430,22 @@ public class PropertyBinder { } private void handleValueGeneration(Property property) { - if ( this.property != null ) { - property.setValueGeneratorCreator( getValueGenerationFromAnnotations( this.property ) ); + if ( this.memberDetails != null ) { + property.setValueGeneratorCreator( getValueGenerationFromAnnotations( this.memberDetails ) ); } } /** * Returns the value generation strategy for the given property, if any. */ - private GeneratorCreator getValueGenerationFromAnnotations(XProperty property) { + private GeneratorCreator getValueGenerationFromAnnotations(MemberDetails property) { GeneratorCreator creator = null; - for ( Annotation annotation : property.getAnnotations() ) { - final GeneratorCreator candidate = generatorCreator( property, annotation ); + for ( AnnotationUsage usage : property.getAllAnnotationUsages() ) { + final GeneratorCreator candidate = generatorCreator( property, usage, buildingContext ); if ( candidate != null ) { if ( creator != null ) { throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) - + "' has multiple '@ValueGenerationType' annotations" ); + + "' has multiple '@ValueGenerationType' annotations" ); } else { creator = candidate; @@ -456,14 +456,14 @@ public class PropertyBinder { } private void handleLob(Property property) { - if ( this.property != null ) { + if ( this.memberDetails != null ) { // HHH-4635 -- needed for dialect-specific property ordering - property.setLob( this.property.isAnnotationPresent( Lob.class ) ); + property.setLob( this.memberDetails.hasAnnotationUsage( Lob.class ) ); } } private void handleMutability(Property property) { - if ( this.property != null && this.property.isAnnotationPresent( Immutable.class ) ) { + if ( this.memberDetails != null && this.memberDetails.hasAnnotationUsage( Immutable.class ) ) { updatable = false; } property.setInsertable( insertable ); @@ -471,8 +471,8 @@ public class PropertyBinder { } private void handleOptional(Property property) { - if ( this.property != null ) { - property.setOptional( !isId && isOptional( this.property, this.holder ) ); + if ( this.memberDetails != null ) { + property.setOptional( !isId && isOptional( this.memberDetails, this.holder ) ); if ( property.isOptional() ) { final OptionalDeterminationSecondPass secondPass = persistentClasses -> { // Defer determining whether a property and its columns are nullable, @@ -501,15 +501,15 @@ public class PropertyBinder { } private void handleNaturalId(Property property) { - if ( this.property != null && entityBinder != null ) { - final NaturalId naturalId = this.property.getAnnotation( NaturalId.class ); + if ( this.memberDetails != null && entityBinder != null ) { + final AnnotationUsage naturalId = this.memberDetails.getAnnotationUsage( NaturalId.class ); if ( naturalId != null ) { if ( !entityBinder.isRootEntity() ) { throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) + "' belongs to an entity subclass and may not be annotated '@NaturalId'" + " (only a property of a root '@Entity' or a '@MappedSuperclass' may be a '@NaturalId')" ); } - if ( !naturalId.mutable() ) { + if ( !naturalId.getBoolean( "mutable" ) ) { updatable = false; } property.setNaturalIdentifier( true ); @@ -522,27 +522,28 @@ public class PropertyBinder { if ( value instanceof Collection ) { property.setOptimisticLocked( ((Collection) value).isOptimisticLocked() ); } - else if ( this.property != null && this.property.isAnnotationPresent( OptimisticLock.class ) ) { - final OptimisticLock optimisticLock = this.property.getAnnotation( OptimisticLock.class ); - validateOptimisticLock( optimisticLock ); - property.setOptimisticLocked( !optimisticLock.excluded() ); + else if ( this.memberDetails != null && this.memberDetails.hasAnnotationUsage( OptimisticLock.class ) ) { + final AnnotationUsage optimisticLock = this.memberDetails.getAnnotationUsage( OptimisticLock.class ); + final boolean excluded = optimisticLock.getBoolean( "excluded" ); + validateOptimisticLock( excluded ); + property.setOptimisticLocked( !excluded ); } else { property.setOptimisticLocked( !isToOneValue(value) || insertable ); // && updatable as well??? } } - private void validateOptimisticLock(OptimisticLock optimisticLock) { - if ( optimisticLock.excluded() ) { - if ( property.isAnnotationPresent( Version.class ) ) { + private void validateOptimisticLock(boolean excluded) { + if ( excluded ) { + if ( memberDetails.hasAnnotationUsage( Version.class ) ) { throw new AnnotationException("Property '" + qualify( holder.getPath(), name ) + "' is annotated '@OptimisticLock(excluded=true)' and '@Version'" ); } - if ( property.isAnnotationPresent( Id.class ) ) { + if ( memberDetails.hasAnnotationUsage( Id.class ) ) { throw new AnnotationException("Property '" + qualify( holder.getPath(), name ) + "' is annotated '@OptimisticLock(excluded=true)' and '@Id'" ); } - if ( property.isAnnotationPresent( EmbeddedId.class ) ) { + if ( memberDetails.hasAnnotationUsage( EmbeddedId.class ) ) { throw new AnnotationException( "Property '" + qualify( holder.getPath(), name ) + "' is annotated '@OptimisticLock(excluded=true)' and '@EmbeddedId'" ); } @@ -561,7 +562,7 @@ public class PropertyBinder { PropertyContainer propertyContainer, MetadataBuildingContext context) { int idPropertyCounter = 0; - for ( XProperty property : propertyContainer.propertyIterator() ) { + for ( MemberDetails property : propertyContainer.propertyIterator() ) { idPropertyCounter += addProperty( propertyContainer, property, elements, context ); } return idPropertyCounter; @@ -569,11 +570,11 @@ public class PropertyBinder { private static int addProperty( PropertyContainer propertyContainer, - XProperty property, + MemberDetails property, List inFlightPropertyDataList, MetadataBuildingContext context) { // see if inFlightPropertyDataList already contains a PropertyData for this name, - // and if so, skip it.. + // and if so, skip it... for ( PropertyData propertyData : inFlightPropertyDataList ) { if ( propertyData.getPropertyName().equals( property.getName() ) ) { checkIdProperty( property, propertyData ); @@ -582,19 +583,19 @@ public class PropertyBinder { } } - final XClass declaringClass = propertyContainer.getDeclaringClass(); - final XClass entity = propertyContainer.getEntityAtStake(); + final ClassDetails declaringClass = propertyContainer.getDeclaringClass(); + final ClassDetails entity = propertyContainer.getEntityAtStake(); int idPropertyCounter = 0; final PropertyData propertyAnnotatedElement = new PropertyInferredData( declaringClass, property, propertyContainer.getClassLevelAccessType().getType(), - context.getBootstrapContext().getReflectionManager() + context ); // put element annotated by @Id in front, since it has to be parsed // before any association by Hibernate - final XAnnotatedElement element = propertyAnnotatedElement.getProperty(); + final MemberDetails element = propertyAnnotatedElement.getAttributeMember(); if ( hasIdAnnotation( element ) ) { inFlightPropertyDataList.add( 0, propertyAnnotatedElement ); handleIdProperty( propertyContainer, context, declaringClass, entity, element ); @@ -606,23 +607,23 @@ public class PropertyBinder { else { inFlightPropertyDataList.add( propertyAnnotatedElement ); } - if ( element.isAnnotationPresent( MapsId.class ) ) { + if ( element.hasAnnotationUsage( MapsId.class ) ) { context.getMetadataCollector().addPropertyAnnotatedWithMapsId( entity, propertyAnnotatedElement ); } return idPropertyCounter; } - private static void checkIdProperty(XProperty property, PropertyData propertyData) { - final Id incomingIdProperty = property.getAnnotation( Id.class ); - final Id existingIdProperty = propertyData.getProperty().getAnnotation( Id.class ); + private static void checkIdProperty(MemberDetails property, PropertyData propertyData) { + final AnnotationUsage incomingIdProperty = property.getAnnotationUsage( Id.class ); + final AnnotationUsage existingIdProperty = propertyData.getAttributeMember().getAnnotationUsage( Id.class ); if ( incomingIdProperty != null && existingIdProperty == null ) { throw new MappingException( String.format( "You cannot override the [%s] non-identifier property from the [%s] base class or @MappedSuperclass and make it an identifier in the [%s] subclass", - propertyData.getProperty().getName(), - propertyData.getProperty().getDeclaringClass().getName(), - property.getDeclaringClass().getName() + propertyData.getAttributeMember().getName(), + propertyData.getAttributeMember().getDeclaringType().getName(), + property.getDeclaringType().getName() ) ); } @@ -631,58 +632,53 @@ public class PropertyBinder { private static void handleIdProperty( PropertyContainer propertyContainer, MetadataBuildingContext context, - XClass declaringClass, - XClass entity, - XAnnotatedElement element) { + ClassDetails declaringClass, + ClassDetails entity, + MemberDetails element) { // The property must be put in hibernate.properties as it's a system wide property. Fixable? //TODO support true/false/default on the property instead of present / not present //TODO is @Column mandatory? //TODO add method support if ( context.getBuildingOptions().isSpecjProprietarySyntaxEnabled() ) { - if ( element.isAnnotationPresent( Id.class ) && element.isAnnotationPresent( Column.class ) ) { - final String columnName = element.getAnnotation( Column.class ).name(); - for ( XProperty property : declaringClass.getDeclaredProperties( AccessType.FIELD.getType() ) ) { - if ( !property.isAnnotationPresent( MapsId.class ) && isJoinColumnPresent( columnName, property ) ) { + if ( element.hasAnnotationUsage( Id.class ) && element.hasAnnotationUsage( Column.class ) ) { + final String columnName = element.getAnnotationUsage( Column.class ).getString( "name" ); + declaringClass.forEachField( (index, fieldDetails) -> { + if ( !element.hasAnnotationUsage( MapsId.class ) && isJoinColumnPresent( columnName, element ) ) { //create a PropertyData for the specJ property holding the mapping context.getMetadataCollector().addPropertyAnnotatedWithMapsIdSpecj( entity, new PropertyInferredData( declaringClass, //same dec - property, + element, // the actual @XToOne property propertyContainer.getClassLevelAccessType().getType(), //TODO we should get the right accessor but the same as id would do - context.getBootstrapContext().getReflectionManager() + context ), element.toString() ); } - } + } ); } } } - private static boolean isJoinColumnPresent(String columnName, XProperty property) { + private static boolean isJoinColumnPresent(String columnName, MemberDetails property) { //The detection of a configured individual JoinColumn differs between Annotation //and XML configuration processing. - if ( property.isAnnotationPresent( JoinColumn.class ) - && property.getAnnotation( JoinColumn.class ).name().equals( columnName ) ) { - return true; - } - else if ( property.isAnnotationPresent( JoinColumns.class ) ) { - for ( JoinColumn columnAnnotation : property.getAnnotation( JoinColumns.class ).value() ) { - if ( columnName.equals( columnAnnotation.name() ) ) { - return true; - } + final List> joinColumnAnnotations = property.getRepeatedAnnotationUsages( JoinColumn.class ); + for ( AnnotationUsage joinColumnAnnotation : joinColumnAnnotations ) { + if ( joinColumnAnnotation.getString( "name" ).equals( columnName ) ) { + return true; } } return false; } - static boolean hasIdAnnotation(XAnnotatedElement element) { - return element.isAnnotationPresent( Id.class ) - || element.isAnnotationPresent( EmbeddedId.class ); + static boolean hasIdAnnotation(MemberDetails element) { + return element.hasAnnotationUsage( Id.class ) + || element.hasAnnotationUsage( EmbeddedId.class ); } /** @@ -698,7 +694,7 @@ public class PropertyBinder { boolean isComponentEmbedded, boolean inSecondPass, MetadataBuildingContext context, - Map inheritanceStatePerClass) throws MappingException { + Map inheritanceStatePerClass) throws MappingException { if ( alreadyProcessedBySuper( propertyHolder, inferredData, entityBinder ) ) { LOG.debugf( @@ -720,8 +716,8 @@ public class PropertyBinder { ); } - final XProperty property = inferredData.getProperty(); - if ( property.isAnnotationPresent( Parent.class ) ) { + final MemberDetails property = inferredData.getAttributeMember(); + if ( property.hasAnnotationUsage( Parent.class ) ) { handleParentProperty( propertyHolder, inferredData, property ); } else { @@ -737,8 +733,7 @@ public class PropertyBinder { inSecondPass, context, inheritanceStatePerClass, - property, - inferredData.getClassOrElement() + property ); } } @@ -749,7 +744,7 @@ public class PropertyBinder { && binder.isPropertyDefinedInSuperHierarchy( data.getPropertyName() ); } - private static void handleParentProperty(PropertyHolder holder, PropertyData data, XProperty property) { + private static void handleParentProperty(PropertyHolder holder, PropertyData data, MemberDetails property) { if ( holder.isComponent() ) { holder.setParentProperty( property.getName() ); } @@ -769,10 +764,12 @@ public class PropertyBinder { boolean isComponentEmbedded, boolean inSecondPass, MetadataBuildingContext context, - Map inheritanceStatePerClass, - XProperty property, - XClass returnedClass) { - + Map inheritanceStatePerClass, + MemberDetails property) { + final TypeDetails attributeTypeDetails = inferredData.getAttributeMember().isPlural() + ? inferredData.getAttributeMember().getType() + : inferredData.getClassOrElementType(); + final ClassDetails attributeClassDetails = attributeTypeDetails.determineRawClass(); final ColumnsBuilder columnsBuilder = new ColumnsBuilder( propertyHolder, nullability, @@ -787,8 +784,8 @@ public class PropertyBinder { propertyBinder.setReturnedClassName( inferredData.getTypeName() ); propertyBinder.setAccessType( inferredData.getDefaultAccess() ); propertyBinder.setHolder( propertyHolder ); - propertyBinder.setProperty( property ); - propertyBinder.setReturnedClass( inferredData.getPropertyClass() ); + propertyBinder.setMemberDetails( property ); + propertyBinder.setReturnedClass( attributeClassDetails ); propertyBinder.setBuildingContext( context ); if ( isIdentifierMapper ) { propertyBinder.setInsertable( false ); @@ -799,9 +796,9 @@ public class PropertyBinder { propertyBinder.setInheritanceStatePerClass( inheritanceStatePerClass ); propertyBinder.setId( !entityBinder.isIgnoreIdAnnotations() && hasIdAnnotation( property ) ); - final LazyGroup lazyGroupAnnotation = property.getAnnotation( LazyGroup.class ); + final AnnotationUsage lazyGroupAnnotation = property.getAnnotationUsage( LazyGroup.class ); if ( lazyGroupAnnotation != null ) { - propertyBinder.setLazyGroup( lazyGroupAnnotation.value() ); + propertyBinder.setLazyGroup( lazyGroupAnnotation.getString( "value" ) ); } final AnnotatedJoinColumns joinColumns = columnsBuilder.getJoinColumns(); @@ -817,7 +814,7 @@ public class PropertyBinder { context, inheritanceStatePerClass, property, - returnedClass, + attributeClassDetails, columnsBuilder, propertyBinder ); @@ -835,9 +832,9 @@ public class PropertyBinder { boolean isComponentEmbedded, boolean inSecondPass, MetadataBuildingContext context, - Map inheritanceStatePerClass, - XProperty property, - XClass returnedClass, + Map inheritanceStatePerClass, + MemberDetails property, + ClassDetails returnedClass, ColumnsBuilder columnsBuilder, PropertyBinder propertyBinder) { if ( isVersion( property ) ) { @@ -927,32 +924,32 @@ public class PropertyBinder { return columnsBuilder.getColumns(); } - private static boolean isVersion(XProperty property) { - return property.isAnnotationPresent( Version.class ); + private static boolean isVersion(MemberDetails property) { + return property.hasAnnotationUsage( Version.class ); } - private static boolean isOneToOne(XProperty property) { - return property.isAnnotationPresent( OneToOne.class ); + private static boolean isOneToOne(MemberDetails property) { + return property.hasAnnotationUsage( OneToOne.class ); } - private static boolean isManyToOne(XProperty property) { - return property.isAnnotationPresent( ManyToOne.class ); + private static boolean isManyToOne(MemberDetails property) { + return property.hasAnnotationUsage( ManyToOne.class ); } - private static boolean isAny(XProperty property) { - return property.isAnnotationPresent( Any.class ); + private static boolean isAny(MemberDetails property) { + return property.hasAnnotationUsage( Any.class ); } - private static boolean isCollection(XProperty property) { - return property.isAnnotationPresent( OneToMany.class ) - || property.isAnnotationPresent( ManyToMany.class ) - || property.isAnnotationPresent( ElementCollection.class ) - || property.isAnnotationPresent( ManyToAny.class ); + private static boolean isCollection(MemberDetails property) { + return property.hasAnnotationUsage( OneToMany.class ) + || property.hasAnnotationUsage( ManyToMany.class ) + || property.hasAnnotationUsage( ElementCollection.class ) + || property.hasAnnotationUsage( ManyToAny.class ); } - private static boolean isForcePersist(XProperty property) { - return property.isAnnotationPresent( MapsId.class ) - || property.isAnnotationPresent( Id.class ); + private static boolean isForcePersist(MemberDetails property) { + return property.hasAnnotationUsage( MapsId.class ) + || property.hasAnnotationUsage( Id.class ); } private static void bindVersionProperty( @@ -960,7 +957,7 @@ public class PropertyBinder { PropertyData inferredData, boolean isIdentifierMapper, MetadataBuildingContext context, - Map inheritanceStatePerClass, + Map inheritanceStatePerClass, AnnotatedColumns columns, PropertyBinder propertyBinder) { checkVersionProperty( propertyHolder, isIdentifierMapper ); @@ -974,7 +971,7 @@ public class PropertyBinder { rootClass.setVersion( property ); //If version is on a mapped superclass, update the mapping - final XClass declaringClass = inferredData.getDeclaringClass(); + final ClassDetails declaringClass = inferredData.getDeclaringClass(); final org.hibernate.mapping.MappedSuperclass superclass = getMappedSuperclassOrNull( declaringClass, inheritanceStatePerClass, context ); if ( superclass != null ) { @@ -1022,11 +1019,11 @@ public class PropertyBinder { boolean isIdentifierMapper, boolean isComponentEmbedded, MetadataBuildingContext context, - Map inheritanceStatePerClass, - XProperty property, + Map inheritanceStatePerClass, + MemberDetails property, ColumnsBuilder columnsBuilder, AnnotatedColumns columns, - XClass returnedClass, + ClassDetails returnedClass, PropertyBinder propertyBinder) { // overrides from @MapsId or @IdClass if needed @@ -1066,8 +1063,8 @@ public class PropertyBinder { resolveCompositeUserType( inferredData, context ); if ( isComposite || compositeUserType != null ) { - if ( property.isArray() && property.getElementClass() != null - && isEmbedded( property, property.getElementClass() ) ) { + if ( property.isArray() && property.getElementType() != null + && isEmbedded( property, property.getElementType() ) ) { // This is a special kind of basic aggregate component array type propertyBinder.setComponentElement( EmbeddableBinder.bindEmbeddable( @@ -1109,8 +1106,9 @@ public class PropertyBinder { ); } } - else if ( property.isCollection() && property.getElementClass() != null - && isEmbedded( property, property.getElementClass() ) ) { + else if ( property.isPlural() + && property.getElementType() != null + && isEmbedded( property, property.getElementType() ) ) { // This is a special kind of basic aggregate component array type propertyBinder.setComponentElement( EmbeddableBinder.bindEmbeddable( @@ -1125,7 +1123,7 @@ public class PropertyBinder { inheritanceStatePerClass, null, null, - EmbeddableBinder.determineCustomInstantiator( property, property.getElementClass(), context ), + EmbeddableBinder.determineCustomInstantiator( property, property.getElementType().determineRawClass(), context ), compositeUserType, null, columns @@ -1170,11 +1168,11 @@ public class PropertyBinder { } private static boolean isComposite( - Map inheritanceStatePerClass, - XProperty property, - XClass returnedClass, + Map inheritanceStatePerClass, + MemberDetails property, + ClassDetails returnedClass, PropertyData overridingProperty) { - final InheritanceState state = inheritanceStatePerClass.get( overridingProperty.getClassOrElement() ); + final InheritanceState state = inheritanceStatePerClass.get( overridingProperty.getClassOrElementType().determineRawClass() ); return state != null ? state.hasIdClassOrEmbeddedId() : isEmbedded( property, returnedClass ); } @@ -1182,7 +1180,7 @@ public class PropertyBinder { PropertyHolder propertyHolder, Map classGenerators, MetadataBuildingContext context, - XProperty property, + MemberDetails property, PropertyBinder propertyBinder) { final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId( propertyBinder.isId(), @@ -1221,11 +1219,10 @@ public class PropertyBinder { PropertyData inferredData, Nullability nullability, MetadataBuildingContext context, - XProperty property, + MemberDetails property, AnnotatedColumns columns, PropertyBinder propertyBinder, boolean isOverridden) { - if ( shouldForceNotNull( nullability, propertyBinder, isExplicitlyOptional( property ) ) ) { forceColumnsNotNull( propertyHolder, inferredData, columns, propertyBinder ); } @@ -1267,47 +1264,69 @@ public class PropertyBinder { /** * Should this property be considered optional, without considering * whether it is primitive? + * + * @apiNote Poorly named to a degree. The intention is really whether non-optional is explicit */ - private static boolean isExplicitlyOptional(XProperty property) { - return !property.isAnnotationPresent( Basic.class ) - || property.getAnnotation( Basic.class ).optional(); + private static boolean isExplicitlyOptional(MemberDetails attributeMember) { + final AnnotationUsage basicAnn = attributeMember.getAnnotationUsage( Basic.class ); + if ( basicAnn == null ) { + // things are optional (nullable) by default. If there is no annotation, that cannot be altered + return true; + } + + return basicAnn.getBoolean( "optional" ); } /** * Should this property be considered optional, taking into * account whether it is primitive? */ - public static boolean isOptional(XProperty property, PropertyHolder propertyHolder) { - return property.isAnnotationPresent( Basic.class ) - ? property.getAnnotation( Basic.class ).optional() - : property.isArray() - || propertyHolder != null && propertyHolder.isComponent() - || !property.getClassOrElementClass().isPrimitive(); + public static boolean isOptional(MemberDetails attributeMember, PropertyHolder propertyHolder) { + final AnnotationUsage basicAnn = attributeMember.getAnnotationUsage( Basic.class ); + if ( basicAnn != null ) { + return basicAnn.getBoolean( "optional" ); + } + + if ( attributeMember.isArray() ) { + return true; + } + + if ( propertyHolder != null && propertyHolder.isComponent() ) { + return true; + } + + if ( attributeMember.isPlural() ) { + return attributeMember.getElementType().getTypeKind() != TypeDetails.Kind.PRIMITIVE; + } + + return attributeMember.getType().getTypeKind() != TypeDetails.Kind.PRIMITIVE; } - private static boolean isLazy(XProperty property) { - return property.isAnnotationPresent( Basic.class ) - && property.getAnnotation( Basic.class ).fetch() == LAZY; + private static boolean isLazy(MemberDetails property) { + final AnnotationUsage annotationUsage = property.getAnnotationUsage( Basic.class ); + return annotationUsage != null && annotationUsage.getEnum( "fetch" ) == LAZY; } private static void addIndexes( boolean inSecondPass, - XProperty property, + MemberDetails property, AnnotatedColumns columns, AnnotatedJoinColumns joinColumns) { //process indexes after everything: in second pass, many to one has to be done before indexes - final Index index = property.getAnnotation( Index.class ); - if ( index != null ) { - if ( joinColumns != null ) { - for ( AnnotatedColumn column : joinColumns.getColumns() ) { - column.addIndex( index, inSecondPass); - } + final AnnotationUsage index = property.getAnnotationUsage( Index.class ); + if ( index == null ) { + return; + } + + if ( joinColumns != null ) { + for ( AnnotatedColumn column : joinColumns.getColumns() ) { + column.addIndex( index, inSecondPass ); } - else { - if ( columns != null ) { - for ( AnnotatedColumn column : columns.getColumns() ) { - column.addIndex( index, inSecondPass ); - } + } + else { + if ( columns != null ) { + for ( AnnotatedColumn column : columns.getColumns() ) { + column.addIndex( index, inSecondPass ); } } } @@ -1315,7 +1334,7 @@ public class PropertyBinder { private static void addNaturalIds( boolean inSecondPass, - XProperty property, + MemberDetails property, AnnotatedColumns columns, AnnotatedJoinColumns joinColumns, MetadataBuildingContext context) { @@ -1323,12 +1342,13 @@ public class PropertyBinder { // For now, simply ensure consistent naming. // TODO: AFAIK, there really isn't a reason for these UKs to be created // on the SecondPass. This whole area should go away... - final NaturalId naturalId = property.getAnnotation( NaturalId.class ); + final AnnotationUsage naturalId = property.getAnnotationUsage( NaturalId.class ); if ( naturalId != null ) { final Database database = context.getMetadataCollector().getDatabase(); + final ImplicitNamingStrategy implicitNamingStrategy = context.getBuildingOptions().getImplicitNamingStrategy(); if ( joinColumns != null ) { - final Identifier name = context.getBuildingOptions().getImplicitNamingStrategy() - .determineUniqueKeyName(new ImplicitUniqueKeyNameSource() { + final Identifier name = + implicitNamingStrategy.determineUniqueKeyName( new ImplicitUniqueKeyNameSource() { @Override public Identifier getTableName() { return joinColumns.getTable().getNameIdentifier(); @@ -1355,8 +1375,8 @@ public class PropertyBinder { } } else { - final Identifier name = context.getBuildingOptions().getImplicitNamingStrategy() - .determineUniqueKeyName(new ImplicitUniqueKeyNameSource() { + final Identifier name = + implicitNamingStrategy.determineUniqueKeyName(new ImplicitUniqueKeyNameSource() { @Override public Identifier getTableName() { return columns.getTable().getNameIdentifier(); @@ -1388,25 +1408,23 @@ public class PropertyBinder { private static Class> resolveCompositeUserType( PropertyData inferredData, MetadataBuildingContext context) { - final XProperty property = inferredData.getProperty(); - final XClass returnedClass = inferredData.getClassOrElement(); + final MemberDetails attributeMember = inferredData.getAttributeMember(); + final TypeDetails classOrElementType = inferredData.getClassOrElementType(); + final ClassDetails returnedClass = classOrElementType.determineRawClass(); - if ( property != null ) { - final CompositeType compositeType = findAnnotation( property, CompositeType.class ); + if ( attributeMember != null ) { + final AnnotationUsage compositeType = attributeMember.locateAnnotationUsage( CompositeType.class ); if ( compositeType != null ) { - return compositeType.value(); + return compositeType.getClassDetails( "value" ).toJavaClass(); } - final Class> compositeUserType = - resolveTimeZoneStorageCompositeUserType( property, returnedClass, context ); + final Class> compositeUserType = resolveTimeZoneStorageCompositeUserType( attributeMember, returnedClass, context ); if ( compositeUserType != null ) { return compositeUserType; } } if ( returnedClass != null ) { - final Class embeddableClass = context.getBootstrapContext() - .getReflectionManager() - .toClass( returnedClass ); + final Class embeddableClass = returnedClass.toJavaClass(); if ( embeddableClass != null ) { return context.getMetadataCollector().findRegisteredCompositeUserType( embeddableClass ); } @@ -1426,36 +1444,36 @@ public class PropertyBinder { throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData ) + "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" ); } - final XProperty idProperty = inferredData.getProperty(); - final List idGeneratorAnnotations = findContainingAnnotations( idProperty, IdGeneratorType.class ); - final List generatorAnnotations = findContainingAnnotations( idProperty, ValueGenerationType.class ); + final MemberDetails idAttributeMember = inferredData.getAttributeMember(); + final List> idGeneratorAnnotations = idAttributeMember.getMetaAnnotated( IdGeneratorType.class ); + final List> generatorAnnotations = idAttributeMember.getMetaAnnotated( ValueGenerationType.class ); removeIdGenerators( generatorAnnotations, idGeneratorAnnotations ); if ( idGeneratorAnnotations.size() + generatorAnnotations.size() > 1 ) { throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData ) + "' has too many generator annotations " + combine( idGeneratorAnnotations, generatorAnnotations ) ); } if ( !idGeneratorAnnotations.isEmpty() ) { - final Annotation annotation = idGeneratorAnnotations.get(0); + final AnnotationUsage annotation = idGeneratorAnnotations.get(0); final ServiceRegistry serviceRegistry = context.getBootstrapContext().getServiceRegistry(); final BeanContainer beanContainer = allowExtensionsInCdi( serviceRegistry ) ? serviceRegistry.requireService( ManagedBeanRegistry.class ).getBeanContainer() : null; - idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idProperty, annotation, beanContainer ) ); + idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idAttributeMember, annotation, beanContainer ) ); } else if ( !generatorAnnotations.isEmpty() ) { -// idValue.setCustomGeneratorCreator( generatorCreator( idProperty, generatorAnnotation ) ); +// idValue.setCustomGeneratorCreator( generatorCreator( idAttributeMember, generatorAnnotation ) ); throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData ) - + "' is annotated '" + generatorAnnotations.get(0).annotationType() + + "' is annotated '" + generatorAnnotations.get(0).getAnnotationType() + "' which is not an '@IdGeneratorType'" ); } else { - final XClass entityClass = inferredData.getClassOrElement(); - createIdGenerator( idValue, classGenerators, context, entityClass, idProperty ); + final ClassDetails entityClass = inferredData.getClassOrElementType().determineRawClass(); + createIdGenerator( idValue, classGenerators, context, entityClass, idAttributeMember ); if ( LOG.isTraceEnabled() ) { LOG.tracev( "Bind {0} on {1}", - isCompositeId( entityClass, idProperty ) ? "@EmbeddedId" : "@Id", + isCompositeId( entityClass, idAttributeMember ) ? "@EmbeddedId" : "@Id", inferredData.getPropertyName() ); } @@ -1466,9 +1484,18 @@ public class PropertyBinder { // collection methods as those proxies do not implement hashcode/equals and even a simple `a.equals(a)` will return `false`. // Instead, we will check the annotation types, since generator annotations should not be "repeatable" we should have only // at most one annotation for a generator: - private static void removeIdGenerators(List generatorAnnotations, List idGeneratorAnnotations) { - for ( Annotation id : idGeneratorAnnotations ) { - generatorAnnotations.removeIf( gen -> gen.annotationType().equals( id.annotationType() ) ); + // todo (jpa32) : is this still necessary with s/hibernate-common-annotations/hibernate-models? + private static void removeIdGenerators( + List> generatorAnnotations, + List> idGeneratorAnnotations) { + for ( AnnotationUsage id : idGeneratorAnnotations ) { + final Iterator> iterator = generatorAnnotations.iterator(); + while ( iterator.hasNext() ) { + final AnnotationUsage gen = iterator.next(); + if ( gen.getAnnotationType().equals( id.getAnnotationType() ) ) { + iterator.remove(); + } + } } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyContainer.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyContainer.java index 3248eee16f..09e8916d42 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyContainer.java @@ -11,27 +11,31 @@ package org.hibernate.boot.model.internal; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.hibernate.AnnotationException; +import org.hibernate.annotations.Any; import org.hibernate.annotations.JavaType; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.annotations.ManyToAny; import org.hibernate.annotations.Target; import org.hibernate.annotations.Type; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; -import org.hibernate.boot.MappingException; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.spi.AccessType; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.RecordComponentDetails; +import org.hibernate.models.spi.TypeDetails; import org.jboss.logging.Logger; @@ -44,9 +48,11 @@ import jakarta.persistence.OneToOne; import jakarta.persistence.Transient; /** - * A helper class to keep the {@code XProperty}s of a class ordered by access type. + * Access to the members of a {@linkplain ClassDetails class} which define a persistent attribute + * as defined by the JPA specification and AccessType. * * @author Hardy Ferentschik + * @author Steve Ebersole */ public class PropertyContainer { @@ -55,8 +61,8 @@ public class PropertyContainer { /** * The class for which this container is created. */ - private final XClass xClass; - private final XClass entityAtStake; + private final ClassDetails classDetails; + private final ClassDetails entityAtStake; /** * Holds the AccessType indicated for use at the class/container-level for cases where persistent attribute @@ -64,10 +70,20 @@ public class PropertyContainer { */ private final AccessType classLevelAccessType; - private final List persistentAttributes; + private final List attributeMembers; - public PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType) { - this.xClass = clazz; + public PropertyContainer(ClassDetails classDetails, TypeDetails entityAtStake, AccessType propertyAccessor) { + // todo : should use the TypeDetails, no? + this( classDetails, entityAtStake.determineRawClass(), propertyAccessor ); + } + + public PropertyContainer(TypeDetails classDetails, TypeDetails entityAtStake, AccessType propertyAccessor) { + // todo : should use the TypeDetails, no? + this( classDetails.determineRawClass(), entityAtStake.determineRawClass(), propertyAccessor ); + } + + public PropertyContainer(ClassDetails classDetails, ClassDetails entityAtStake, AccessType defaultClassLevelAccessType) { + this.classDetails = classDetails; this.entityAtStake = entityAtStake; if ( defaultClassLevelAccessType == AccessType.DEFAULT ) { @@ -85,29 +101,28 @@ public class PropertyContainer { assert classLevelAccessType == AccessType.FIELD || classLevelAccessType == AccessType.PROPERTY || classLevelAccessType == AccessType.RECORD; + attributeMembers = resolveAttributeMembers( classDetails, classLevelAccessType ); + } - final List fields = xClass.getDeclaredProperties( AccessType.FIELD.getType() ); - final List getters = xClass.getDeclaredProperties( AccessType.PROPERTY.getType() ); - final List recordComponents = xClass.getDeclaredProperties( AccessType.RECORD.getType() ); + private static List resolveAttributeMembers( + ClassDetails classDetails, + AccessType classLevelAccessType) { + final List fields = collectPotentialAttributeMembers( classDetails.getFields() ); + final List getters = collectPotentialAttributeMembers( classDetails.getMethods() ); + final List recordComponents = collectPotentialAttributeMembers( classDetails.getRecordComponents() ); - preFilter( fields, getters, recordComponents ); + final Map attributeMemberMap = buildAttributeMemberMap( + recordComponents, + fields, + getters + ); - final Map persistentAttributesFromGetters = new HashMap<>(); - final Map persistentAttributesFromComponents = new HashMap<>(); + final Map persistentAttributesFromGetters = new HashMap<>(); + final Map persistentAttributesFromComponents = new HashMap<>(); - final Map localAttributeMap; - // If the record class has only record components which match up with fields and no additional getters, - // we can retain the property order, to match up with the record component order - if ( !recordComponents.isEmpty() && recordComponents.size() == fields.size() && getters.isEmpty() ) { - localAttributeMap = new LinkedHashMap<>(); - } - //otherwise we sort them in alphabetical order, since this is at least deterministic - else { - localAttributeMap = new TreeMap<>(); - } collectPersistentAttributesUsingLocalAccessType( - xClass, - localAttributeMap, + classDetails, + attributeMemberMap, persistentAttributesFromGetters, persistentAttributesFromComponents, fields, @@ -115,125 +130,121 @@ public class PropertyContainer { recordComponents ); collectPersistentAttributesUsingClassLevelAccessType( - xClass, + classDetails, classLevelAccessType, - localAttributeMap, + attributeMemberMap, persistentAttributesFromGetters, persistentAttributesFromComponents, fields, getters, recordComponents ); - this.persistentAttributes = verifyAndInitializePersistentAttributes( xClass, localAttributeMap ); + return verifyAndInitializePersistentAttributes( classDetails, attributeMemberMap ); } - private void preFilter(List fields, List getters, List recordComponents) { - Iterator propertyIterator = fields.iterator(); - while ( propertyIterator.hasNext() ) { - final XProperty property = propertyIterator.next(); - if ( mustBeSkipped( property ) ) { - propertyIterator.remove(); - } + private static Map buildAttributeMemberMap( + List recordComponents, + List fields, + List getters) { + final Map attributeMemberMap; + // If the record class has only record components which match up with fields and no additional getters, + // we can retain the property order, to match up with the record component order + if ( !recordComponents.isEmpty() && recordComponents.size() == fields.size() && getters.isEmpty() ) { + attributeMemberMap = new LinkedHashMap<>(); } + //otherwise we sort them in alphabetical order, since this is at least deterministic + else { + attributeMemberMap = new TreeMap<>(); + } + return attributeMemberMap; + } - propertyIterator = getters.iterator(); - while ( propertyIterator.hasNext() ) { - final XProperty property = propertyIterator.next(); - if ( mustBeSkipped( property ) ) { - propertyIterator.remove(); - } - } - - propertyIterator = recordComponents.iterator(); - while ( propertyIterator.hasNext() ) { - final XProperty property = propertyIterator.next(); - if ( mustBeSkipped( property ) ) { - propertyIterator.remove(); + private static List collectPotentialAttributeMembers(List source) { + final List results = new ArrayList<>(); + for ( int i = 0; i < source.size(); i++ ) { + final E possible = source.get( i ); + if ( possible.isPersistable() ) { + if ( !mustBeSkipped( possible ) ) { + results.add( possible ); + } } } + return results; } private static void collectPersistentAttributesUsingLocalAccessType( - XClass xClass, - Map persistentAttributeMap, - Map persistentAttributesFromGetters, - Map persistentAttributesFromComponents, - List fields, - List getters, - List recordComponents) { + ClassDetails classDetails, + Map persistentAttributeMap, + Map persistentAttributesFromGetters, + Map persistentAttributesFromComponents, + List fields, + List getters, + List recordComponents) { // Check fields... - Iterator propertyIterator = fields.iterator(); - while ( propertyIterator.hasNext() ) { - final XProperty xProperty = propertyIterator.next(); - final Access localAccessAnnotation = xProperty.getAnnotation( Access.class ); + for ( int i = 0; i < fields.size(); i++ ) { + final FieldDetails fieldDetails = fields.get( i ); + final AnnotationUsage localAccessAnnotation = fieldDetails.getAnnotationUsage( Access.class ); if ( localAccessAnnotation == null - || localAccessAnnotation.value() != jakarta.persistence.AccessType.FIELD ) { + || localAccessAnnotation.getEnum( "value" ) != jakarta.persistence.AccessType.FIELD ) { continue; } - - propertyIterator.remove(); - persistentAttributeMap.put( xProperty.getName(), xProperty ); + persistentAttributeMap.put( fieldDetails.getName(), fieldDetails ); } // Check getters... - propertyIterator = getters.iterator(); - while ( propertyIterator.hasNext() ) { - final XProperty xProperty = propertyIterator.next(); - final Access localAccessAnnotation = xProperty.getAnnotation( Access.class ); + for ( int i = 0; i < getters.size(); i++ ) { + final MethodDetails getterDetails = getters.get( i ); + final AnnotationUsage localAccessAnnotation = getterDetails.getAnnotationUsage( Access.class ); if ( localAccessAnnotation == null - || localAccessAnnotation.value() != jakarta.persistence.AccessType.PROPERTY ) { + || localAccessAnnotation.getEnum( "value" ) != jakarta.persistence.AccessType.PROPERTY ) { continue; } - propertyIterator.remove(); - - final String name = xProperty.getName(); + final String name = getterDetails.resolveAttributeName(); // HHH-10242 detect registration of the same property getter twice - eg boolean isId() + UUID getId() - final XProperty previous = persistentAttributesFromGetters.get( name ); + final MethodDetails previous = persistentAttributesFromGetters.get( name ); if ( previous != null ) { throw new org.hibernate.boot.MappingException( LOG.ambiguousPropertyMethods( - xClass.getName(), - HCANNHelper.annotatedElementSignature( previous ), - HCANNHelper.annotatedElementSignature( xProperty ) + classDetails.getName(), + previous.getName(), + getterDetails.getName() ), - new Origin( SourceType.ANNOTATION, xClass.getName() ) + new Origin( SourceType.ANNOTATION, classDetails.getName() ) ); } - persistentAttributeMap.put( name, xProperty ); - persistentAttributesFromGetters.put( name, xProperty ); + persistentAttributeMap.put( name, getterDetails ); + persistentAttributesFromGetters.put( name, getterDetails ); } // Check record components... - propertyIterator = recordComponents.iterator(); - while ( propertyIterator.hasNext() ) { - final XProperty xProperty = propertyIterator.next(); - final Access localAccessAnnotation = xProperty.getAnnotation( Access.class ); + for ( int i = 0; i < recordComponents.size(); i++ ) { + final RecordComponentDetails componentDetails = recordComponents.get( i ); + final AnnotationUsage localAccessAnnotation = componentDetails.getAnnotationUsage( Access.class ); if ( localAccessAnnotation == null ) { continue; } - - propertyIterator.remove(); - final String name = xProperty.getName(); - persistentAttributeMap.put( name, xProperty ); - persistentAttributesFromComponents.put( name, xProperty ); + final String name = componentDetails.getName(); + persistentAttributeMap.put( name, componentDetails ); + persistentAttributesFromComponents.put( name, componentDetails ); } } private static void collectPersistentAttributesUsingClassLevelAccessType( - XClass xClass, + ClassDetails classDetails, AccessType classLevelAccessType, - Map persistentAttributeMap, - Map persistentAttributesFromGetters, - Map persistentAttributesFromComponents, - List fields, - List getters, - List recordComponents) { + Map persistentAttributeMap, + Map persistentAttributesFromGetters, + Map persistentAttributesFromComponents, + List fields, + List getters, + List recordComponents) { if ( classLevelAccessType == AccessType.FIELD ) { - for ( XProperty field : fields ) { + for ( int i = 0; i < fields.size(); i++ ) { + final FieldDetails field = fields.get( i ); final String name = field.getName(); if ( persistentAttributeMap.containsKey( name ) ) { continue; @@ -243,19 +254,20 @@ public class PropertyContainer { } } else { - for ( XProperty getter : getters ) { - final String name = getter.getName(); + for ( int i = 0; i < getters.size(); i++ ) { + final MethodDetails getterDetails = getters.get( i ); + final String name = getterDetails.getName(); // HHH-10242 detect registration of the same property getter twice - eg boolean isId() + UUID getId() - final XProperty previous = persistentAttributesFromGetters.get( name ); + final MethodDetails previous = persistentAttributesFromGetters.get( name ); if ( previous != null ) { - throw new MappingException( + throw new org.hibernate.boot.MappingException( LOG.ambiguousPropertyMethods( - xClass.getName(), - HCANNHelper.annotatedElementSignature( previous ), - HCANNHelper.annotatedElementSignature( getter ) + classDetails.getName(), + previous.getName(), + getterDetails.getName() ), - new Origin( SourceType.ANNOTATION, xClass.getName() ) + new Origin( SourceType.ANNOTATION, classDetails.getName() ) ); } @@ -263,192 +275,131 @@ public class PropertyContainer { continue; } - persistentAttributeMap.put( getter.getName(), getter ); - persistentAttributesFromGetters.put( name, getter ); + persistentAttributeMap.put( getterDetails.getName(), getterDetails ); + persistentAttributesFromGetters.put( name, getterDetails ); } + // When a user uses the `property` access strategy for the entity owning an embeddable, // we also have to add the attributes for record components, // because record classes usually don't have getters, but just the record component accessors - for ( XProperty recordComponent : recordComponents ) { - final String name = recordComponent.getName(); + for ( int i = 0; i < recordComponents.size(); i++ ) { + final RecordComponentDetails componentDetails = recordComponents.get( i ); + final String name = componentDetails.getName(); if ( persistentAttributeMap.containsKey( name ) ) { continue; } - persistentAttributeMap.put( name, recordComponent ); - persistentAttributesFromComponents.put( name, recordComponent ); + persistentAttributeMap.put( name, componentDetails ); + persistentAttributesFromComponents.put( name, componentDetails ); + } } } - public XClass getEntityAtStake() { - return entityAtStake; + public ClassDetails getDeclaringClass() { + return classDetails; } - public XClass getDeclaringClass() { - return xClass; + public ClassDetails getEntityAtStake() { + return entityAtStake; } public AccessType getClassLevelAccessType() { return classLevelAccessType; } - public Iterable propertyIterator() { - return persistentAttributes; + public Iterable propertyIterator() { + return attributeMembers; } - private static List verifyAndInitializePersistentAttributes(XClass xClass, Map localAttributeMap) { - ArrayList output = new ArrayList<>( localAttributeMap.size() ); - for ( XProperty xProperty : localAttributeMap.values() ) { - if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xClass, xProperty ) ) { - String msg = "Property '" + StringHelper.qualify( xClass.getName(), xProperty.getName() ) + + private static List verifyAndInitializePersistentAttributes( + ClassDetails classDetails, + Map attributeMemberMap) { + ArrayList output = new ArrayList<>( attributeMemberMap.size() ); + for ( MemberDetails attributeMemberDetails : attributeMemberMap.values() ) { + final TypeDetails memberType = attributeMemberDetails.getType(); + if ( !memberType.isResolved() + && !discoverTypeWithoutReflection( classDetails, attributeMemberDetails ) ) { + final String msg = "Property '" + StringHelper.qualify( classDetails.getName(), attributeMemberDetails.getName() ) + "' has an unbound type and no explicit target entity (resolve this generics usage issue" + " or set an explicit target attribute with '@OneToMany(target=)' or use an explicit '@Type')"; throw new AnnotationException( msg ); } - output.add( xProperty ); + output.add( attributeMemberDetails ); } return CollectionHelper.toSmallList( output ); } -// -// private void considerExplicitFieldAndPropertyAccess() { -// for ( XProperty property : fieldAccessMap.values() ) { -// Access access = property.getAnnotation( Access.class ); -// if ( access == null ) { -// continue; -// } -// -// // see "2.3.2 Explicit Access Type" of JPA 2 spec -// // the access type for this property is explicitly set to AccessType.FIELD, hence we have to -// // use field access for this property even if the default access type for the class is AccessType.PROPERTY -// AccessType accessType = AccessType.getAccessStrategy( access.value() ); -// if (accessType == AccessType.FIELD) { -// propertyAccessMap.put(property.getName(), property); -// } -// else { -// LOG.debug( "Placing @Access(AccessType.FIELD) on a field does not have any effect." ); -// } -// } -// -// for ( XProperty property : propertyAccessMap.values() ) { -// Access access = property.getAnnotation( Access.class ); -// if ( access == null ) { -// continue; -// } -// -// AccessType accessType = AccessType.getAccessStrategy( access.value() ); -// -// // see "2.3.2 Explicit Access Type" of JPA 2 spec -// // the access type for this property is explicitly set to AccessType.PROPERTY, hence we have to -// // return use method access even if the default class access type is AccessType.FIELD -// if (accessType == AccessType.PROPERTY) { -// fieldAccessMap.put(property.getName(), property); -// } -// else { -// LOG.debug( "Placing @Access(AccessType.PROPERTY) on a field does not have any effect." ); -// } -// } -// } - -// /** -// * Retrieves all properties from the {@code xClass} with the specified access type. This method does not take -// * any jpa access rules/annotations into account yet. -// * -// * @param access The access type - {@code AccessType.FIELD} or {@code AccessType.Property} -// * -// * @return A maps of the properties with the given access type keyed against their property name -// */ -// private TreeMap initProperties(AccessType access) { -// if ( !( AccessType.PROPERTY.equals( access ) || AccessType.FIELD.equals( access ) ) ) { -// throw new IllegalArgumentException( "Access type has to be AccessType.FIELD or AccessType.Property" ); -// } -// -// //order so that property are used in the same order when binding native query -// TreeMap propertiesMap = new TreeMap(); -// List properties = xClass.getDeclaredProperties( access.getType() ); -// for ( XProperty property : properties ) { -// if ( mustBeSkipped( property ) ) { -// continue; -// } -// // HHH-10242 detect registration of the same property twice eg boolean isId() + UUID getId() -// XProperty oldProperty = propertiesMap.get( property.getName() ); -// if ( oldProperty != null ) { -// throw new org.hibernate.boot.MappingException( -// LOG.ambiguousPropertyMethods( -// xClass.getName(), -// HCANNHelper.annotatedElementSignature( oldProperty ), -// HCANNHelper.annotatedElementSignature( property ) -// ), -// new Origin( SourceType.ANNOTATION, xClass.getName() ) -// ); -// } -// -// propertiesMap.put( property.getName(), property ); -// } -// return propertiesMap; -// } private AccessType determineLocalClassDefinedAccessStrategy() { AccessType classDefinedAccessType = AccessType.DEFAULT; - Access access = xClass.getAnnotation( Access.class ); + final AnnotationUsage access = classDetails.getAnnotationUsage( Access.class ); if ( access != null ) { - classDefinedAccessType = AccessType.getAccessStrategy( access.value() ); + classDefinedAccessType = AccessType.getAccessStrategy( access.getEnum( "value" ) ); } return classDefinedAccessType; } - private static boolean discoverTypeWithoutReflection(XClass clazz, XProperty property) { - if ( property.isAnnotationPresent( OneToOne.class ) && !property.getAnnotation( OneToOne.class ) - .targetEntity() - .equals( void.class ) ) { + private static boolean discoverTypeWithoutReflection(ClassDetails classDetails, MemberDetails memberDetails) { + if ( memberDetails.hasAnnotationUsage( Target.class ) ) { return true; } - else if ( property.isAnnotationPresent( OneToMany.class ) && !property.getAnnotation( OneToMany.class ) - .targetEntity() - .equals( void.class ) ) { + + if ( memberDetails.hasAnnotationUsage( Basic.class ) ) { return true; } - else if ( property.isAnnotationPresent( ManyToOne.class ) && !property.getAnnotation( ManyToOne.class ) - .targetEntity() - .equals( void.class ) ) { + + if ( memberDetails.hasAnnotationUsage( Type.class ) ) { return true; } - else if ( property.isAnnotationPresent( ManyToMany.class ) && !property.getAnnotation( ManyToMany.class ) - .targetEntity() - .equals( void.class ) ) { + + if ( memberDetails.hasAnnotationUsage( JavaType.class ) ) { return true; } - else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) { + + final AnnotationUsage oneToOneAnn = memberDetails.getAnnotationUsage( OneToOne.class ); + if ( oneToOneAnn != null ) { + final ClassDetails targetEntity = oneToOneAnn.getClassDetails( "targetEntity" ); + return targetEntity != ClassDetails.VOID_CLASS_DETAILS; + } + + + final AnnotationUsage oneToManyAnn = memberDetails.getAnnotationUsage( OneToMany.class ); + if ( oneToManyAnn != null ) { + final ClassDetails targetEntity = oneToManyAnn.getClassDetails( "targetEntity" ); + return targetEntity != ClassDetails.VOID_CLASS_DETAILS; + } + + + final AnnotationUsage manToOneAnn = memberDetails.getAnnotationUsage( ManyToOne.class ); + if ( manToOneAnn != null ) { + final ClassDetails targetEntity = manToOneAnn.getClassDetails( "targetEntity" ); + return targetEntity != ClassDetails.VOID_CLASS_DETAILS; + } + + final AnnotationUsage manToManyAnn = memberDetails.getAnnotationUsage( ManyToMany.class ); + if ( manToManyAnn != null ) { + final ClassDetails targetEntity = manToManyAnn.getClassDetails( "targetEntity" ); + return targetEntity != ClassDetails.VOID_CLASS_DETAILS; + } + + if ( memberDetails.hasAnnotationUsage( Any.class ) ) { return true; } - else if ( property.isAnnotationPresent( ManyToAny.class ) ) { - if ( !property.isCollection() && !property.isArray() ) { - throw new AnnotationException( "Property '" + StringHelper.qualify( clazz.getName(), property.getName() ) - + "' annotated '@ManyToAny' is neither a collection nor an array" ); - } + + final AnnotationUsage manToAnyAnn = memberDetails.getAnnotationUsage( ManyToAny.class ); + if ( manToAnyAnn != null ) { return true; } - else if ( property.isAnnotationPresent( Basic.class ) ) { - return true; - } - else if ( property.isAnnotationPresent( Type.class ) ) { - return true; - } - else if ( property.isAnnotationPresent( JavaType.class ) ) { - return true; - } - else if ( property.isAnnotationPresent( JdbcTypeCode.class ) ) { - return true; - } - else if ( property.isAnnotationPresent( Target.class ) ) { + else if ( memberDetails.hasAnnotationUsage( JdbcTypeCode.class ) ) { return true; } + return false; } - private static boolean mustBeSkipped(XProperty property) { + private static boolean mustBeSkipped(MemberDetails memberDetails) { //TODO make those hardcoded tests more portable (through the bytecode provider?) - return property.isAnnotationPresent( Transient.class ) - || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() ); + return memberDetails.hasAnnotationUsage( Transient.class ) + || (memberDetails.getType() != null && "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( memberDetails.getType().getName() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolder.java index ec486bef20..047ed2342f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolder.java @@ -6,15 +6,18 @@ */ package org.hibernate.boot.model.internal; +import java.util.List; + import org.hibernate.annotations.ColumnTransformer; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.mapping.Join; import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Table; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; import jakarta.persistence.Column; import jakarta.persistence.ForeignKey; @@ -33,9 +36,9 @@ public interface PropertyHolder { Table getTable(); - void addProperty(Property prop, XClass declaringClass); + void addProperty(Property prop, MemberDetails memberDetails, ClassDetails declaringClass); - void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass); + void addProperty(Property prop, MemberDetails memberDetails, AnnotatedColumns columns, ClassDetails declaringClass); KeyValue getIdentifier(); @@ -62,36 +65,36 @@ public interface PropertyHolder { /** * return null if the column is not overridden, or an array of column if true */ - Column[] getOverriddenColumn(String propertyName); + List> getOverriddenColumn(String propertyName); /** * return null if the column is not overridden, or an array of column if true */ - JoinColumn[] getOverriddenJoinColumn(String propertyName); + List> getOverriddenJoinColumn(String propertyName); /** * return null if hte foreign key is not overridden, or the foreign key if true */ - default ForeignKey getOverriddenForeignKey(String propertyName) { + default AnnotationUsage getOverriddenForeignKey(String propertyName) { // todo: does this necessarily need to be a default method? return null; } - ColumnTransformer getOverriddenColumnTransformer(String logicalColumnName); + AnnotationUsage getOverriddenColumnTransformer(String logicalColumnName); /** * return - * - null if no join table is present, - * - the join table if not overridden, - * - the overridden join table otherwise + * - null if no join table is present, + * - the join table if not overridden, + * - the overridden join table otherwise */ - JoinTable getJoinTable(XProperty property); + AnnotationUsage getJoinTable(MemberDetails attributeMember); String getEntityName(); - Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation); + Join addJoin(AnnotationUsage joinTableAnn, boolean noDelayInPkColumnCreation); - Join addJoin(JoinTable joinTable, Table table, boolean noDelayInPkColumnCreation); + Join addJoin(AnnotationUsage joinTable, Table table, boolean noDelayInPkColumnCreation); boolean isInIdClass(); @@ -103,12 +106,12 @@ public interface PropertyHolder { * * @param property The property */ - void startingProperty(XProperty property); + void startingProperty(MemberDetails property); /** * Determine the AttributeConverter to use for the given property. * * @return The ConverterDescriptor */ - ConverterDescriptor resolveAttributeConverterDescriptor(XProperty property); + ConverterDescriptor resolveAttributeConverterDescriptor(MemberDetails property); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolderBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolderBuilder.java index ee45564cc2..851b2856f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolderBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyHolderBuilder.java @@ -8,14 +8,14 @@ package org.hibernate.boot.model.internal; import java.util.Map; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Component; import org.hibernate.mapping.Join; import org.hibernate.mapping.PersistentClass; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; /** * This factory is here to build a PropertyHolder and prevent .mapping interface adding @@ -27,11 +27,11 @@ public final class PropertyHolderBuilder { } public static PropertyHolder buildPropertyHolder( - XClass clazzToProcess, + ClassDetails clazzToProcess, PersistentClass persistentClass, EntityBinder entityBinder, MetadataBuildingContext context, - Map inheritanceStatePerClass) { + Map inheritanceStatePerClass) { return new ClassPropertyHolder( persistentClass, clazzToProcess, @@ -65,8 +65,8 @@ public final class PropertyHolderBuilder { public static CollectionPropertyHolder buildPropertyHolder( Collection collection, String path, - XClass clazzToProcess, - XProperty property, + ClassDetails clazzToProcess, + MemberDetails property, PropertyHolder parentPropertyHolder, MetadataBuildingContext context) { return new CollectionPropertyHolder( @@ -87,7 +87,7 @@ public final class PropertyHolderBuilder { PersistentClass persistentClass, Map joins, MetadataBuildingContext context, - Map inheritanceStatePerClass) { + Map inheritanceStatePerClass) { return new ClassPropertyHolder( persistentClass, null, joins, context, inheritanceStatePerClass ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java index f9175b4493..69c472dae3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java @@ -6,13 +6,18 @@ */ package org.hibernate.boot.model.internal; +import java.util.Collection; + import org.hibernate.MappingException; import org.hibernate.annotations.Target; -import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.AccessType; +import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; +import org.hibernate.models.internal.ClassTypeDetailsImpl; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import jakarta.persistence.Access; @@ -25,23 +30,27 @@ import jakarta.persistence.Access; public class PropertyInferredData implements PropertyData { private final AccessType defaultAccess; - private final XProperty property; - private final ReflectionManager reflectionManager; - private final XClass declaringClass; + private final ClassDetails declaringClass; + private final MemberDetails propertyMember; + private final MetadataBuildingContext buildingContext; /** * Take the annotated element for lazy process */ - public PropertyInferredData(XClass declaringClass, XProperty property, String propertyAccessor, ReflectionManager reflectionManager) { + public PropertyInferredData( + ClassDetails declaringClass, + MemberDetails propertyMember, + String propertyAccessor, + MetadataBuildingContext buildingContext) { this.declaringClass = declaringClass; - this.property = property; + this.propertyMember = propertyMember; this.defaultAccess = AccessType.getAccessStrategy( propertyAccessor ); - this.reflectionManager = reflectionManager; + this.buildingContext = buildingContext; } @Override public String toString() { - return String.format( "PropertyInferredData{property=%s, declaringClass=%s}", property, declaringClass ); + return String.format( "PropertyInferredData{property=%s, declaringClass=%s}", propertyMember, declaringClass ); } @Override @@ -50,9 +59,9 @@ public class PropertyInferredData implements PropertyData { AccessType jpaAccessType = AccessType.DEFAULT; - Access access = property.getAnnotation( Access.class ); + AnnotationUsage access = propertyMember.getAnnotationUsage( Access.class ); if ( access != null ) { - jpaAccessType = AccessType.getAccessStrategy( access.value() ); + jpaAccessType = AccessType.getAccessStrategy( access.getEnum( "value" ) ); } if ( jpaAccessType != AccessType.DEFAULT ) { @@ -63,59 +72,164 @@ public class PropertyInferredData implements PropertyData { @Override public String getPropertyName() throws MappingException { - return property.getName(); + return propertyMember.resolveAttributeName(); } @Override - public XClass getPropertyClass() throws MappingException { - if ( property.isAnnotationPresent( Target.class ) ) { - return reflectionManager.toXClass( property.getAnnotation( Target.class ).value() ); + public TypeDetails getPropertyType() throws MappingException { + final AnnotationUsage targetAnnotation = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class ); + if ( targetAnnotation != null ) { + return new ClassTypeDetailsImpl( targetAnnotation.getClassDetails( "value" ), TypeDetails.Kind.CLASS ); } - else { - return property.getType(); + + final AnnotationUsage legacyTargetAnnotation = propertyMember.getAnnotationUsage( Target.class ); + if ( legacyTargetAnnotation != null ) { + return new ClassTypeDetailsImpl( legacyTargetAnnotation.getClassDetails( "value" ), TypeDetails.Kind.CLASS ); } + + return propertyMember.getType(); } @Override - public XClass getClassOrElement() throws MappingException { - if ( property.isAnnotationPresent( Target.class ) ) { - return reflectionManager.toXClass( property.getAnnotation( Target.class ).value() ); + public TypeDetails getClassOrElementType() throws MappingException { + final AnnotationUsage annotationUsage = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class ); + if ( annotationUsage != null ) { + return new ClassTypeDetailsImpl( annotationUsage.getClassDetails( "value" ), TypeDetails.Kind.CLASS ); } - else { - return property.getClassOrElementClass(); + + final AnnotationUsage legacyAnnotationUsage = propertyMember.getAnnotationUsage( Target.class ); + if ( legacyAnnotationUsage != null ) { + return new ClassTypeDetailsImpl( legacyAnnotationUsage.getClassDetails( "value" ), TypeDetails.Kind.CLASS ); } + + return propertyMember.getAssociatedType(); + +// final TypeDetails memberType = propertyMember.getType(); +// +// if ( !propertyMember.isPlural() ) { +// return memberType; +// } +// +// if ( propertyMember.isArray() ) { +// return memberType.asArrayType().getConstituentType(); +// } +// +// if ( memberType.isImplementor( Collection.class ) ) { +// if ( memberType.getTypeKind() == TypeDetails.Kind.PARAMETERIZED_TYPE ) { +// final ParameterizedTypeDetails parameterizedType = memberType.asParameterizedType(); +// final List typeArguments = parameterizedType.getArguments(); +// if ( CollectionHelper.size( typeArguments ) == 1 ) { +// return typeArguments.get( 0 ); +// } +// return ClassBasedTypeDetails.OBJECT_TYPE_DETAILS; +// } +// if ( memberType.getTypeKind() == TypeDetails.Kind.TYPE_VARIABLE ) { +// // something like - +// // class TheEntity> { +// // L stuff; +// // } +// final TypeVariableDetails typeVariable = memberType.asTypeVariable(); +// if ( CollectionHelper.size( typeVariable.getBounds() ) == 1 ) { +// return typeVariable.getBounds().get( 0 ); +// } +// return ClassBasedTypeDetails.OBJECT_TYPE_DETAILS; +// } +// if ( memberType.getTypeKind() == TypeDetails.Kind.CLASS ) { +// // something like - +// // class LongList extends java.util.ArrayList {...} +// // +// // LongList values; +// return extractCollectionElementTypeFromClass( memberType.asClassType().getClassDetails() ); +// } +// if ( memberType.getTypeKind() == TypeDetails.Kind.WILDCARD_TYPE ) { +// // todo : this is not correct, though can this ever happen in persistence models? +// final WildcardTypeDetails wildcardType = memberType.asWildcardType(); +// return wildcardType.getBound(); +// } +// } +// +// if ( memberType.isImplementor( Map.class ) ) { +// if ( memberType.getTypeKind() == TypeDetails.Kind.PARAMETERIZED_TYPE ) { +// final ParameterizedTypeDetails parameterizedType = memberType.asParameterizedType(); +// final List typeArguments = parameterizedType.getArguments(); +// if ( CollectionHelper.size( typeArguments ) == 2 ) { +// return typeArguments.get( 1 ); +// } +// return ClassBasedTypeDetails.OBJECT_TYPE_DETAILS; +// } +// if ( memberType.getTypeKind() == TypeDetails.Kind.TYPE_VARIABLE ) { +// final TypeVariableDetails typeVariable = memberType.asTypeVariable(); +// if ( CollectionHelper.size( typeVariable.getBounds() ) == 2 ) { +// return typeVariable.getBounds().get( 1 ); +// } +// return ClassBasedTypeDetails.OBJECT_TYPE_DETAILS; +// } +// if ( memberType.getTypeKind() == TypeDetails.Kind.CLASS ) { +// // something like - +// // class LongList extends java.util.ArrayList {...} +// // +// // LongList values; +// return extractMapValueTypeFromClass( memberType.asClassType().getClassDetails() ); +// } +// if ( memberType.getTypeKind() == TypeDetails.Kind.WILDCARD_TYPE ) { +// final WildcardTypeDetails wildcardType = memberType.asWildcardType(); +// wildcardType.getBound(); +// } +// } +// +// throw new MappingException( +// String.format( +// Locale.ROOT, +// "Unable to determine class/element type - %s#%s (%s)", +// declaringClass.getName(), +// propertyMember.getName(), +// memberType +// ) +// ); + } + + private TypeDetails extractCollectionElementTypeFromClass(ClassDetails classDetails) { + if ( classDetails.getSuperClass() != null && classDetails.isImplementor( Collection.class ) ) { + // the class extends a class implementing the Collection contract + } + return null; + } + + private TypeDetails extractMapValueTypeFromClass(ClassDetails classDetails) { + return null; } @Override - public XClass getClassOrPluralElement() throws MappingException { - if ( property.isAnnotationPresent( Target.class ) ) { - return reflectionManager.toXClass( property.getAnnotation( Target.class ).value() ); + public ClassDetails getClassOrPluralElement() throws MappingException { + final AnnotationUsage targetAnnotationUsage = propertyMember.getAnnotationUsage( Target.class ); + if ( targetAnnotationUsage != null ) { + return targetAnnotationUsage.getClassDetails( "value" ); } - else if ( property.isCollection() ) { - return property.getElementClass(); - } - else { - return property.getClassOrElementClass(); + + if ( propertyMember.isPlural() ) { + return propertyMember.getElementType().determineRawClass(); } + + return propertyMember.getAssociatedType().determineRawClass(); } @Override public String getClassOrElementName() throws MappingException { - return getClassOrElement().getName(); + return getClassOrElementType().getName(); } @Override public String getTypeName() throws MappingException { - return getPropertyClass().getName(); + return getPropertyType().getName(); } @Override - public XProperty getProperty() { - return property; + public MemberDetails getAttributeMember() { + return propertyMember; } @Override - public XClass getDeclaringClass() { + public ClassDetails getDeclaringClass() { return declaringClass; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyPreloadedData.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyPreloadedData.java index 74e30121a0..4c391df75f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyPreloadedData.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyPreloadedData.java @@ -7,19 +7,20 @@ package org.hibernate.boot.model.internal; import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.PropertyData; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; public class PropertyPreloadedData implements PropertyData { private final AccessType defaultAccess; private final String propertyName; - private final XClass returnedClass; + private final TypeDetails returnedClass; - public PropertyPreloadedData(AccessType defaultAccess, String propertyName, XClass returnedClass) { + public PropertyPreloadedData(AccessType defaultAccess, String propertyName, TypeDetails returnedClass) { this.defaultAccess = defaultAccess; this.propertyName = propertyName; this.returnedClass = returnedClass; @@ -40,17 +41,17 @@ public class PropertyPreloadedData implements PropertyData { } @Override - public XClass getClassOrElement() throws MappingException { - return getPropertyClass(); + public TypeDetails getClassOrElementType() throws MappingException { + return getPropertyType(); } @Override - public XClass getClassOrPluralElement() throws MappingException { - return getPropertyClass(); + public ClassDetails getClassOrPluralElement() throws MappingException { + return getPropertyType().determineRawClass(); } @Override - public XClass getPropertyClass() throws MappingException { + public TypeDetails getPropertyType() throws MappingException { return returnedClass; } @@ -65,12 +66,12 @@ public class PropertyPreloadedData implements PropertyData { } @Override - public XProperty getProperty() { + public MemberDetails getAttributeMember() { return null; //instead of UnsupportedOperationException } @Override - public XClass getDeclaringClass() { + public ClassDetails getDeclaringClass() { //Preloaded properties are artificial wrapper for collection element accesses //and idClass creation, ignore. return null; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java index 081f52ebbe..b62dbe49e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java @@ -7,6 +7,7 @@ package org.hibernate.boot.model.internal; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.function.Supplier; @@ -33,6 +34,8 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.jpa.HibernateHints; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.query.sql.internal.ParameterParser; import org.hibernate.query.sql.spi.ParameterRecognizer; import org.hibernate.type.BasicType; @@ -50,7 +53,9 @@ import jakarta.persistence.SqlResultSetMapping; import jakarta.persistence.SqlResultSetMappings; import jakarta.persistence.StoredProcedureParameter; +import static java.lang.Boolean.TRUE; import static org.hibernate.internal.util.StringHelper.nullIfEmpty; +import static org.hibernate.internal.util.collections.CollectionHelper.determineProperSizing; import static org.hibernate.internal.util.collections.CollectionHelper.setOf; /** @@ -65,15 +70,15 @@ public abstract class QueryBinder { private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, QueryBinder.class.getName()); public static void bindQuery( - NamedQuery namedQuery, + AnnotationUsage namedQuery, MetadataBuildingContext context, boolean isDefault) { if ( namedQuery == null ) { return; } - final String queryName = namedQuery.name(); - final String queryString = namedQuery.query(); + final String queryName = namedQuery.getString( "name" ); + final String queryString = namedQuery.getString( "query" ); if ( queryName.isEmpty() ) { throw new AnnotationException( "Class or package level '@NamedQuery' annotation must specify a 'name'" ); @@ -83,7 +88,7 @@ public abstract class QueryBinder { LOG.debugf( "Binding named query: %s => %s", queryName, queryString ); } - final QueryHintDefinition hints = new QueryHintDefinition( queryName, namedQuery.hints() ); + final QueryHintDefinition hints = new QueryHintDefinition( queryName, namedQuery.getList( "hints" ) ); final NamedHqlQueryDefinition queryMapping = new NamedHqlQueryDefinitionImpl.Builder( queryName ) .setHqlString( queryString ) @@ -108,26 +113,27 @@ public abstract class QueryBinder { public static void bindNativeQuery( - NamedNativeQuery namedNativeQuery, + AnnotationUsage namedNativeQuery, MetadataBuildingContext context, boolean isDefault) { if ( namedNativeQuery == null ) { return; } - final String registrationName = namedNativeQuery.name(); - final String queryString = namedNativeQuery.query(); + final String registrationName = namedNativeQuery.getString( "name" ); + final String queryString = namedNativeQuery.getString( "query" ); if ( registrationName.isEmpty() ) { throw new AnnotationException( "Class or package level '@NamedNativeQuery' annotation must specify a 'name'" ); } - final QueryHintDefinition hints = new QueryHintDefinition( registrationName, namedNativeQuery.hints() ); + final QueryHintDefinition hints = new QueryHintDefinition( registrationName, namedNativeQuery.getList( "hints" ) ); - final String resultSetMappingName = namedNativeQuery.resultSetMapping(); - final String resultSetMappingClassName = void.class.equals( namedNativeQuery.resultClass() ) + final String resultSetMappingName = namedNativeQuery.getString( "resultSetMapping" ); + final ClassDetails resultClassDetails = namedNativeQuery.getClassDetails( "resultClass" ); + final String resultSetMappingClassName = ClassDetails.VOID_CLASS_DETAILS == resultClassDetails ? null - : namedNativeQuery.resultClass().getName(); + : resultClassDetails.getName(); final NamedNativeQueryDefinitionBuilder builder = new NamedNativeQueryDefinitionBuilder( registrationName ) .setSqlString( queryString ) @@ -161,24 +167,23 @@ public abstract class QueryBinder { public static void bindNativeQuery( String name, - SQLSelect sqlSelect, - XClass annotatedClass, + AnnotationUsage sqlSelect, + ClassDetails annotatedClass, MetadataBuildingContext context) { final NamedNativeQueryDefinitionBuilder builder = new NamedNativeQueryDefinitionBuilder( name ) .setFlushMode( FlushMode.MANUAL ) - .setSqlString( sqlSelect.sql() ) - .setQuerySpaces( setOf( sqlSelect.querySpaces() ) ); + .setSqlString( sqlSelect.getString( "sql" ) ) + .setQuerySpaces( setOf( sqlSelect.getList( "querySpaces" ) ) ); if ( annotatedClass != null ) { builder.setResultSetMappingClassName( annotatedClass.getName() ); } - final SqlResultSetMapping resultSetMapping = sqlSelect.resultSetMapping(); - if ( resultSetMapping.columns().length != 0 - || resultSetMapping.entities().length != 0 - || resultSetMapping.classes().length != 0) { - context.getMetadataCollector() - .addResultSetMapping( SqlResultSetMappingDescriptor.from( resultSetMapping, name ) ); + final AnnotationUsage resultSetMapping = sqlSelect.getNestedUsage( "resultSetMapping" ); + if ( !resultSetMapping.getList( "columns" ).isEmpty() + || !resultSetMapping.getList( "entities" ).isEmpty() + || !resultSetMapping.getList( "classes" ).isEmpty() ) { + context.getMetadataCollector().addResultSetMapping( SqlResultSetMappingDescriptor.from( resultSetMapping, name ) ); builder.setResultSetMappingName( name ); } @@ -186,39 +191,47 @@ public abstract class QueryBinder { } public static void bindNativeQuery( - org.hibernate.annotations.NamedNativeQuery namedNativeQuery, + AnnotationUsage namedNativeQuery, MetadataBuildingContext context) { if ( namedNativeQuery == null ) { return; } - final String registrationName = namedNativeQuery.name(); + final String registrationName = namedNativeQuery.getString( "name" ); //ResultSetMappingDefinition mappingDefinition = mappings.getJdbcValuesMappingProducer( queryAnn.resultSetMapping() ); if ( registrationName.isEmpty() ) { throw new AnnotationException( "Class or package level '@NamedNativeQuery' annotation must specify a 'name'" ); } - final String resultSetMappingName = namedNativeQuery.resultSetMapping(); - final String resultSetMappingClassName = void.class.equals( namedNativeQuery.resultClass() ) + final String resultSetMappingName = namedNativeQuery.getString( "resultSetMapping" ); + final ClassDetails resultClassDetails = namedNativeQuery.getClassDetails( "resultClass" ); + final String resultSetMappingClassName = ClassDetails.VOID_CLASS_DETAILS == resultClassDetails ? null - : namedNativeQuery.resultClass().getName(); + : resultClassDetails.getName(); + + final Integer timeout = namedNativeQuery.getInteger( "timeout" ); + final Integer fetchSize = namedNativeQuery.getInteger( "fetchSize" ); + + final List querySpacesList = namedNativeQuery.getList( "querySpaces" ); + final HashSet querySpaces = new HashSet<>( determineProperSizing( querySpacesList.size() ) ); + querySpaces.addAll( querySpacesList ); final NamedNativeQueryDefinitionBuilder builder = new NamedNativeQueryDefinitionBuilder( registrationName ) - .setSqlString( namedNativeQuery.query() ) + .setSqlString( namedNativeQuery.getString( "query" ) ) .setResultSetMappingName( resultSetMappingName ) .setResultSetMappingClassName( resultSetMappingClassName ) - .setCacheable( namedNativeQuery.cacheable() ) - .setCacheRegion( nullIfEmpty( namedNativeQuery.cacheRegion() ) ) - .setCacheMode( getCacheMode( namedNativeQuery ) ) - .setTimeout( namedNativeQuery.timeout() < 0 ? null : namedNativeQuery.timeout() ) - .setFetchSize( namedNativeQuery.fetchSize() < 0 ? null : namedNativeQuery.fetchSize() ) - .setFlushMode( getFlushMode( namedNativeQuery.flushMode() ) ) - .setReadOnly( namedNativeQuery.readOnly() ) - .setQuerySpaces( setOf( namedNativeQuery.querySpaces() ) ) - .setComment( nullIfEmpty( namedNativeQuery.comment() ) ); + .setCacheable( namedNativeQuery.getBoolean( "cacheable" ) ) + .setCacheRegion( nullIfEmpty( namedNativeQuery.getString( "cacheRegion" ) ) ) + .setCacheMode( getCacheMode( namedNativeQuery ) ) + .setTimeout( timeout < 0 ? null : timeout ) + .setFetchSize( fetchSize < 0 ? null : fetchSize ) + .setFlushMode( getFlushMode( namedNativeQuery.getEnum( "flushMode" ) ) ) + .setReadOnly( namedNativeQuery.getBoolean( "readOnly" ) ) + .setQuerySpaces( querySpaces ) + .setComment( nullIfEmpty( namedNativeQuery.getString( "comment" ) ) ); - if ( namedNativeQuery.callable() ) { + if ( TRUE == namedNativeQuery.getBoolean( "callable" ) ) { final NamedProcedureCallDefinition definition = createStoredProcedure( builder, context, () -> illegalCallSyntax( namedNativeQuery ) ); context.getMetadataCollector().addNamedProcedureCallDefinition( definition ); @@ -320,71 +333,83 @@ public abstract class QueryBinder { return new NamedProcedureCallDefinitionImpl( AnnotationFactory.create( descriptor ) ); } - public static void bindQueries(NamedQueries namedQueries, MetadataBuildingContext context, boolean isDefault) { - if ( namedQueries != null ) { - for ( NamedQuery namedQuery : namedQueries.value() ) { - bindQuery( namedQuery, context, isDefault ); - } + public static void bindQueries(AnnotationUsage namedQueries, MetadataBuildingContext context, boolean isDefault) { + if ( namedQueries == null ) { + return; + } + + final List> nestedValues = namedQueries.getList( "value" ); + for ( AnnotationUsage nestedValue : nestedValues ) { + bindQuery( nestedValue, context, isDefault ); } } public static void bindNativeQueries( - NamedNativeQueries namedNativeQueries, + AnnotationUsage namedNativeQueries, MetadataBuildingContext context, boolean isDefault) { - if ( namedNativeQueries != null ) { - for ( NamedNativeQuery namedNativeQuery : namedNativeQueries.value() ) { - bindNativeQuery( namedNativeQuery, context, isDefault ); - } + if ( namedNativeQueries == null ) { + return; + } + + final List> nestedValues = namedNativeQueries.getList( "value" ); + for ( AnnotationUsage nestedValue : nestedValues ) { + bindNativeQuery( nestedValue, context, isDefault ); } } public static void bindNativeQueries( - org.hibernate.annotations.NamedNativeQueries namedNativeQueries, + AnnotationUsage namedNativeQueries, MetadataBuildingContext context) { - if ( namedNativeQueries != null ) { - for ( org.hibernate.annotations.NamedNativeQuery namedNativeQuery : namedNativeQueries.value() ) { - bindNativeQuery( namedNativeQuery, context ); - } + if ( namedNativeQueries == null ) { + return; + } + + final List> nestedValues = namedNativeQueries.getList( "value" ); + for ( AnnotationUsage nestedValue : nestedValues ) { + bindNativeQuery( nestedValue, context ); } } public static void bindQuery( String name, - HQLSelect hqlSelect, + AnnotationUsage hqlSelect, MetadataBuildingContext context) { final NamedHqlQueryDefinition hqlQueryDefinition = new NamedHqlQueryDefinition.Builder( name ) .setFlushMode( FlushMode.MANUAL ) - .setHqlString( hqlSelect.query() ) + .setHqlString( hqlSelect.getString( "query" ) ) .build(); context.getMetadataCollector().addNamedQuery( hqlQueryDefinition ); } public static void bindQuery( - org.hibernate.annotations.NamedQuery namedQuery, + AnnotationUsage namedQuery, MetadataBuildingContext context) { if ( namedQuery == null ) { return; } - final String registrationName = namedQuery.name(); + final String registrationName = namedQuery.getString( "name" ); //ResultSetMappingDefinition mappingDefinition = mappings.getJdbcValuesMappingProducer( namedQuery.resultSetMapping() ); if ( registrationName.isEmpty() ) { throw new AnnotationException( "Class or package level '@NamedQuery' annotation must specify a 'name'" ); } + final Integer timeout = namedQuery.getInteger( "timeout" ); + final Integer fetchSize = namedQuery.getInteger( "fetchSize" ); + final NamedHqlQueryDefinition.Builder builder = new NamedHqlQueryDefinition.Builder( registrationName ) - .setHqlString( namedQuery.query() ) - .setCacheable( namedQuery.cacheable() ) - .setCacheRegion(nullIfEmpty(namedQuery.cacheRegion())) + .setHqlString( namedQuery.getString( "query" ) ) + .setCacheable( namedQuery.getBoolean( "cacheable" ) ) + .setCacheRegion( nullIfEmpty( namedQuery.getString( "cacheRegion" ) ) ) .setCacheMode( getCacheMode( namedQuery ) ) - .setTimeout( namedQuery.timeout() < 0 ? null : namedQuery.timeout() ) - .setFetchSize( namedQuery.fetchSize() < 0 ? null : namedQuery.fetchSize() ) - .setFlushMode( getFlushMode( namedQuery.flushMode() ) ) - .setReadOnly( namedQuery.readOnly() ) - .setComment( nullIfEmpty( namedQuery.comment() ) ); + .setTimeout( timeout < 0 ? null : timeout ) + .setFetchSize( fetchSize < 0 ? null : fetchSize ) + .setFlushMode( getFlushMode( namedQuery.getEnum( "flushMode" ) ) ) + .setReadOnly( namedQuery.getBoolean( "readOnly" ) ) + .setComment( nullIfEmpty( namedQuery.getString( "comment" ) ) ); final NamedHqlQueryDefinitionImpl hqlQueryDefinition = builder.build(); @@ -395,14 +420,14 @@ public abstract class QueryBinder { context.getMetadataCollector().addNamedQuery( hqlQueryDefinition ); } - private static CacheMode getCacheMode(org.hibernate.annotations.NamedQuery namedQuery) { - CacheMode cacheMode = CacheMode.fromJpaModes( namedQuery.cacheRetrieveMode(), namedQuery.cacheStoreMode() ); - return cacheMode == null || cacheMode == CacheMode.NORMAL ? getCacheMode( namedQuery.cacheMode() ) : cacheMode; - } - - private static CacheMode getCacheMode(org.hibernate.annotations.NamedNativeQuery namedNativeQuery) { - CacheMode cacheMode = CacheMode.fromJpaModes( namedNativeQuery.cacheRetrieveMode(), namedNativeQuery.cacheStoreMode() ); - return cacheMode == null || cacheMode == CacheMode.NORMAL ? getCacheMode( namedNativeQuery.cacheMode() ) : cacheMode; + private static CacheMode getCacheMode(AnnotationUsage namedQuery) { + final CacheMode cacheMode = CacheMode.fromJpaModes( + namedQuery.getEnum( "cacheRetrieveMode" ), + namedQuery.getEnum( "cacheStoreMode" ) + ); + return cacheMode == null || cacheMode == CacheMode.NORMAL + ? interpretCacheMode( namedQuery.getEnum( "cacheMode" ) ) + : cacheMode; } private static FlushMode getFlushMode(FlushModeType flushModeType) { @@ -422,7 +447,7 @@ public abstract class QueryBinder { } } - private static CacheMode getCacheMode(CacheModeType cacheModeType) { + private static CacheMode interpretCacheMode(CacheModeType cacheModeType) { switch ( cacheModeType ) { case GET: return CacheMode.GET; @@ -441,21 +466,24 @@ public abstract class QueryBinder { public static void bindQueries( - org.hibernate.annotations.NamedQueries namedQueries, + AnnotationUsage namedQueries, MetadataBuildingContext context) { - if ( namedQueries != null ) { - for (org.hibernate.annotations.NamedQuery namedQuery : namedQueries.value()) { - bindQuery( namedQuery, context ); - } + if ( namedQueries == null ) { + return; + } + + final List> nestedValues = namedQueries.getList( "value" ); + for ( AnnotationUsage nestedValue : nestedValues ) { + bindQuery( nestedValue, context ); } } public static void bindNamedStoredProcedureQuery( - NamedStoredProcedureQuery namedStoredProcedureQuery, + AnnotationUsage namedStoredProcedureQuery, MetadataBuildingContext context, boolean isDefault) { if ( namedStoredProcedureQuery != null ) { - if ( namedStoredProcedureQuery.name().isEmpty() ) { + if ( namedStoredProcedureQuery.getString( "name" ).isEmpty() ) { throw new AnnotationException( "Class or package level '@NamedStoredProcedureQuery' annotation must specify a 'name'" ); } @@ -471,22 +499,25 @@ public abstract class QueryBinder { } public static void bindSqlResultSetMappings( - SqlResultSetMappings resultSetMappings, + AnnotationUsage resultSetMappings, MetadataBuildingContext context, boolean isDefault) { - if ( resultSetMappings != null ) { - for ( SqlResultSetMapping resultSetMapping : resultSetMappings.value() ) { - bindSqlResultSetMapping( resultSetMapping, context, isDefault ); - } + if ( resultSetMappings == null ) { + return; + } + + final List> mappings = resultSetMappings.getList( "value" ); + for ( AnnotationUsage mapping : mappings ) { + bindSqlResultSetMapping( mapping, context, isDefault ); } } public static void bindSqlResultSetMapping( - SqlResultSetMapping resultSetMapping, + AnnotationUsage resultSetMappingAnn, MetadataBuildingContext context, boolean isDefault) { //no need to handle inSecondPass - context.getMetadataCollector().addSecondPass( new ResultSetMappingSecondPass( resultSetMapping, context, isDefault ) ); + context.getMetadataCollector().addSecondPass( new ResultSetMappingSecondPass( resultSetMappingAnn, context, isDefault ) ); } private static class JdbcCall { @@ -631,8 +662,8 @@ public abstract class QueryBinder { return i; } - private static AnnotationException illegalCallSyntax(org.hibernate.annotations.NamedNativeQuery queryAnn) { - return new AnnotationException( "Callable 'NamedNativeQuery' named '" + queryAnn.name() + private static AnnotationException illegalCallSyntax(AnnotationUsage queryAnn) { + return new AnnotationException( "Callable 'NamedNativeQuery' named '" + queryAnn.getString( "name" ) + "' does not use the JDBC call syntax" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java index 8ffeb5d7b1..6fd76b64b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java @@ -7,7 +7,7 @@ package org.hibernate.boot.model.internal; import java.util.Collections; -import java.util.HashMap; +import java.util.List; import java.util.Map; import org.hibernate.AnnotationException; @@ -18,15 +18,19 @@ import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.cfg.AvailableSettings; import org.hibernate.internal.util.LockModeConverter; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.jpa.HibernateHints; import org.hibernate.jpa.LegacySpecHints; import org.hibernate.jpa.SpecHints; +import org.hibernate.models.spi.AnnotationUsage; import jakarta.persistence.LockModeType; import jakarta.persistence.NamedQuery; import jakarta.persistence.QueryHint; +import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize; + /** * @author Strong Liu */ @@ -34,15 +38,15 @@ public class QueryHintDefinition { private final String queryName; private final Map hintsMap; - public QueryHintDefinition(String queryName, final QueryHint[] hints) { + public QueryHintDefinition(String queryName, final List> hints) { this.queryName = queryName; - if ( hints == null || hints.length == 0 ) { + if ( CollectionHelper.isEmpty( hints ) ) { hintsMap = Collections.emptyMap(); } else { - final Map hintsMap = new HashMap<>(); - for ( QueryHint hint : hints ) { - hintsMap.put( hint.name(), hint.value() ); + final Map hintsMap = mapOfSize( hints.size() ); + for ( AnnotationUsage hint : hints ) { + hintsMap.put( hint.getString( "name" ), hint.getString( "value" ) ); } this.hintsMap = hintsMap; } @@ -149,8 +153,8 @@ public class QueryHintDefinition { } } - public LockOptions determineLockOptions(NamedQuery namedQueryAnnotation) { - final LockModeType lockModeType = namedQueryAnnotation.lockMode(); + public LockOptions determineLockOptions(AnnotationUsage namedQueryAnnotation) { + final LockModeType lockModeType = namedQueryAnnotation.getEnum( "lockMode" ); final Integer lockTimeoutHint = specLockTimeout(); final Boolean followOnLocking = getBooleanWrapper( HibernateHints.HINT_FOLLOW_ON_LOCKING ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ResultSetMappingSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ResultSetMappingSecondPass.java index f322037374..afd2a95bbb 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ResultSetMappingSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ResultSetMappingSecondPass.java @@ -12,6 +12,7 @@ import org.hibernate.MappingException; import org.hibernate.boot.query.SqlResultSetMappingDescriptor; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.PersistentClass; +import org.hibernate.models.spi.AnnotationUsage; import jakarta.persistence.SqlResultSetMapping; @@ -21,11 +22,11 @@ import jakarta.persistence.SqlResultSetMapping; public class ResultSetMappingSecondPass implements QuerySecondPass { // private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ResultsetMappingSecondPass.class ); - private final SqlResultSetMapping annotation; + private final AnnotationUsage annotation; private final MetadataBuildingContext context; private final boolean isDefault; - public ResultSetMappingSecondPass(SqlResultSetMapping annotation, MetadataBuildingContext context, boolean isDefault) { + public ResultSetMappingSecondPass(AnnotationUsage annotation, MetadataBuildingContext context, boolean isDefault) { this.annotation = annotation; this.context = context; this.isDefault = isDefault; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableFromAnnotationSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableFromAnnotationSecondPass.java index eff8c227f7..3444a61e25 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableFromAnnotationSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableFromAnnotationSecondPass.java @@ -9,19 +9,18 @@ package org.hibernate.boot.model.internal; import java.util.Map; import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; import org.hibernate.boot.spi.SecondPass; import org.hibernate.mapping.PersistentClass; public class SecondaryTableFromAnnotationSecondPass implements SecondPass { private final EntityBinder entityBinder; private final PropertyHolder propertyHolder; - private final XAnnotatedElement annotatedClass; - public SecondaryTableFromAnnotationSecondPass(EntityBinder entityBinder, PropertyHolder propertyHolder, XAnnotatedElement annotatedClass) { + public SecondaryTableFromAnnotationSecondPass( + EntityBinder entityBinder, + PropertyHolder propertyHolder) { this.entityBinder = entityBinder; this.propertyHolder = propertyHolder; - this.annotatedClass = annotatedClass; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableSecondPass.java index a3423eaf1e..b8b4881428 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SecondaryTableSecondPass.java @@ -9,7 +9,6 @@ package org.hibernate.boot.model.internal; import java.util.Map; import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; import org.hibernate.boot.spi.SecondPass; import org.hibernate.mapping.PersistentClass; @@ -19,12 +18,10 @@ import org.hibernate.mapping.PersistentClass; public class SecondaryTableSecondPass implements SecondPass { private final EntityBinder entityBinder; private final PropertyHolder propertyHolder; - private final XAnnotatedElement annotatedClass; - public SecondaryTableSecondPass(EntityBinder entityBinder, PropertyHolder propertyHolder, XAnnotatedElement annotatedClass) { + public SecondaryTableSecondPass(EntityBinder entityBinder, PropertyHolder propertyHolder) { this.entityBinder = entityBinder; this.propertyHolder = propertyHolder; - this.annotatedClass = annotatedClass; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SetBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SetBinder.java index 84aef1becc..da67beff09 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SetBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SetBinder.java @@ -13,6 +13,7 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Set; +import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.usertype.UserCollectionType; @@ -37,7 +38,7 @@ public class SetBinder extends CollectionBinder { } @Override - public void setSqlOrderBy(OrderBy orderByAnn) { + public void setSqlOrderBy(AnnotationUsage orderByAnn) { if ( orderByAnn != null ) { super.setSqlOrderBy( orderByAnn ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SoftDeleteHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SoftDeleteHelper.java index a075a20979..cd37fd7451 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SoftDeleteHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/SoftDeleteHelper.java @@ -21,6 +21,7 @@ import org.hibernate.metamodel.mapping.SoftDeletableModelPart; import org.hibernate.metamodel.mapping.SoftDeleteMapping; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.mapping.internal.SoftDeleteMappingImpl; +import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; @@ -44,18 +45,19 @@ public class SoftDeleteHelper { /** * Creates and binds the column and value for modeling the soft-delete in the database * - * @param softDeleteConfig The SoftDelete annotation + * @param softDeleteConfigAnnotation The SoftDelete annotation * @param target The thing which is to be soft-deleted * @param table The table to which the soft-delete should be applied * @param context The processing context for access to needed info and services */ public static void bindSoftDeleteIndicator( - SoftDelete softDeleteConfig, + AnnotationUsage softDeleteConfigAnnotation, SoftDeletable target, Table table, MetadataBuildingContext context) { - assert softDeleteConfig != null; + assert softDeleteConfigAnnotation != null; + final SoftDelete softDeleteConfig = softDeleteConfigAnnotation.toAnnotation(); final BasicValue softDeleteIndicatorValue = createSoftDeleteIndicatorValue( softDeleteConfig, table, context ); final Column softDeleteIndicatorColumn = createSoftDeleteIndicatorColumn( softDeleteConfig, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java index f79a6345dd..7b85487cba 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java @@ -37,6 +37,7 @@ import org.hibernate.mapping.SortableValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.Value; +import org.hibernate.models.spi.AnnotationUsage; import org.jboss.logging.Logger; @@ -72,8 +73,8 @@ public class TableBinder { private String associatedEntity; private String associatedJpaEntity; private boolean isJPA2ElementCollection; - private UniqueConstraint[] uniqueConstraints; - private Index[] indexes; + private List> uniqueConstraints; + private List> indexes; public void setBuildingContext(MetadataBuildingContext buildingContext) { this.buildingContext = buildingContext; @@ -99,11 +100,11 @@ public class TableBinder { isAbstract = anAbstract; } - public void setUniqueConstraints(UniqueConstraint[] uniqueConstraints) { + public void setUniqueConstraints(List> uniqueConstraints) { this.uniqueConstraints = uniqueConstraints; } - public void setJpaIndex(Index[] indexes){ + public void setJpaIndex(List> indexes){ this.indexes = indexes; } @@ -431,7 +432,7 @@ public class TableBinder { String catalog, Identifier logicalName, boolean isAbstract, - UniqueConstraint[] uniqueConstraints, + List> uniqueConstraints, MetadataBuildingContext buildingContext) { return buildAndFillTable( schema, @@ -451,7 +452,7 @@ public class TableBinder { String catalog, Identifier logicalName, boolean isAbstract, - UniqueConstraint[] uniqueConstraints, + List> uniqueConstraints, MetadataBuildingContext buildingContext, String subselect, InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) { @@ -473,17 +474,23 @@ public class TableBinder { String catalog, Identifier logicalName, boolean isAbstract, - UniqueConstraint[] uniqueConstraints, - Index[] indexes, + List> uniqueConstraints, + List> indexes, MetadataBuildingContext buildingContext, String subselect, InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) { final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector(); - final Table table = - addTable( nullIfEmpty( schema ), nullIfEmpty( catalog ), - logicalName, isAbstract, buildingContext, subselect, - denormalizedSuperTableXref, metadataCollector ); + final Table table = addTable( + nullIfEmpty( schema ), + nullIfEmpty( catalog ), + logicalName, + isAbstract, + buildingContext, + subselect, + denormalizedSuperTableXref, + metadataCollector + ); if ( uniqueConstraints != null ) { new IndexBinder( buildingContext ).bindUniqueConstraints( table, uniqueConstraints ); @@ -841,12 +848,34 @@ public class TableBinder { } } - static void addIndexes(Table table, org.hibernate.annotations.Index[] indexes, MetadataBuildingContext context) { - for ( org.hibernate.annotations.Index index : indexes ) { + static void addIndexes(Table table, List> indexes, MetadataBuildingContext context) { + for ( AnnotationUsage indexUsage : indexes ) { + final String name = indexUsage.getString( "name" ); + final String[] columnNames = indexUsage.getList( "columnNames" ).toArray(new String[0]); + //no need to handle inSecondPass here since it is only called from EntityBinder - context.getMetadataCollector().addSecondPass( - new IndexOrUniqueKeySecondPass( table, index.name(), index.columnNames(), context ) - ); + context.getMetadataCollector().addSecondPass( new IndexOrUniqueKeySecondPass( + table, + name, + columnNames, + context + ) ); + } + } + + static void addJpaIndexes(Table table, List> indexes, MetadataBuildingContext context) { + for ( AnnotationUsage indexUsage : indexes ) { + final String name = indexUsage.getString( "name" ); + final String columnList = indexUsage.getString( "columnList" ); + final String[] columnFragments = columnList.split(","); + + //no need to handle inSecondPass here since it is only called from EntityBinder + context.getMetadataCollector().addSecondPass( new IndexOrUniqueKeySecondPass( + table, + name, + columnFragments, + context + ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TimeZoneStorageHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TimeZoneStorageHelper.java index 89a1bc7589..bd844aaa96 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TimeZoneStorageHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TimeZoneStorageHelper.java @@ -6,20 +6,23 @@ */ package org.hibernate.boot.model.internal; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; + import org.hibernate.annotations.TimeZoneStorage; -import org.hibernate.annotations.common.reflection.XAnnotatedElement; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.annotations.TimeZoneStorageType; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.spi.AnnotationTarget; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.usertype.CompositeUserType; import org.hibernate.usertype.internal.OffsetDateTimeCompositeUserType; import org.hibernate.usertype.internal.OffsetTimeCompositeUserType; import org.hibernate.usertype.internal.ZonedDateTimeCompositeUserType; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZonedDateTime; - import static org.hibernate.TimeZoneStorageStrategy.COLUMN; import static org.hibernate.dialect.TimeZoneSupport.NATIVE; @@ -30,10 +33,10 @@ public class TimeZoneStorageHelper { private static final String ZONED_DATETIME_CLASS = ZonedDateTime.class.getName(); static Class> resolveTimeZoneStorageCompositeUserType( - XProperty property, - XClass returnedClass, + MemberDetails attributeMember, + ClassDetails returnedClass, MetadataBuildingContext context) { - if ( useColumnForTimeZoneStorage( property, context ) ) { + if ( useColumnForTimeZoneStorage( attributeMember, context ) ) { String returnedClassName = returnedClass.getName(); if ( OFFSET_DATETIME_CLASS.equals( returnedClassName ) ) { return OffsetDateTimeCompositeUserType.class; @@ -54,24 +57,31 @@ public class TimeZoneStorageHelper { || isOffsetTimeClass( returnedClassName ); } - public static boolean isOffsetTimeClass(XAnnotatedElement element) { - if ( element instanceof XProperty ) { - XProperty property = (XProperty) element; - return isOffsetTimeClass( property.getType().getName() ); + public static boolean isOffsetTimeClass(AnnotationTarget element) { + if ( element instanceof MemberDetails memberDetails ) { + return isOffsetTimeClass( memberDetails ); } return false; } + public static boolean isOffsetTimeClass(MemberDetails element) { + final TypeDetails type = element.getType(); + if ( type == null ) { + return false; + } + + return isOffsetTimeClass( type.determineRawClass().getClassName() ); + } + private static boolean isOffsetTimeClass(String returnedClassName) { return OFFSET_TIME_CLASS.equals( returnedClassName ); } - static boolean useColumnForTimeZoneStorage(XAnnotatedElement element, MetadataBuildingContext context) { - final TimeZoneStorage timeZoneStorage = element.getAnnotation( TimeZoneStorage.class ); + static boolean useColumnForTimeZoneStorage(AnnotationTarget element, MetadataBuildingContext context) { + final AnnotationUsage timeZoneStorage = element.getAnnotationUsage( TimeZoneStorage.class ); if ( timeZoneStorage == null ) { - if ( element instanceof XProperty ) { - XProperty property = (XProperty) element; - return isTemporalWithTimeZoneClass( property.getType().getName() ) + if ( element instanceof MemberDetails attributeMember ) { + return isTemporalWithTimeZoneClass( attributeMember.getType().getName() ) //no @TimeZoneStorage annotation, so we need to use the default storage strategy && context.getBuildingOptions().getDefaultTimeZoneStorage() == COLUMN; } @@ -80,15 +90,12 @@ public class TimeZoneStorageHelper { } } else { - switch ( timeZoneStorage.value() ) { - case COLUMN: - return true; - case AUTO: - // if the db has native support for timezones, we use that, not a column - return context.getBuildingOptions().getTimeZoneSupport() != NATIVE; - default: - return false; - } + return switch ( timeZoneStorage.getEnum( "value", TimeZoneStorageType.class ) ) { + case COLUMN -> true; + // if the db has native support for timezones, we use that, not a column + case AUTO -> context.getBuildingOptions().getTimeZoneSupport() != NATIVE; + default -> false; + }; } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java index 5af8304778..e7e372b72f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java @@ -17,24 +17,24 @@ import org.hibernate.annotations.Cascade; import org.hibernate.annotations.Columns; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchProfileOverride; -import org.hibernate.annotations.FetchProfileOverrides; import org.hibernate.annotations.LazyToOne; import org.hibernate.annotations.LazyToOneOption; import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; -import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; import org.hibernate.mapping.Join; import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.ToOne; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; import jakarta.persistence.Column; import jakarta.persistence.FetchType; @@ -80,15 +80,15 @@ public class ToOneBinder { boolean isIdentifierMapper, boolean inSecondPass, MetadataBuildingContext context, - XProperty property, + MemberDetails property, AnnotatedJoinColumns joinColumns, PropertyBinder propertyBinder, boolean forcePersist) { - final ManyToOne manyToOne = property.getAnnotation( ManyToOne.class ); + final AnnotationUsage manyToOne = property.getAnnotationUsage( ManyToOne.class ); //check validity - if ( property.isAnnotationPresent( Column.class ) - || property.isAnnotationPresent( Columns.class ) ) { + if ( property.hasAnnotationUsage( Column.class ) + || property.hasAnnotationUsage( Columns.class ) ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) + "' is a '@ManyToOne' association and may not use '@Column' to specify column mappings (use '@JoinColumn' instead)" @@ -102,19 +102,19 @@ public class ToOneBinder { ); } - final Cascade hibernateCascade = property.getAnnotation( Cascade.class ); - final NotFound notFound = property.getAnnotation( NotFound.class ); - final NotFoundAction notFoundAction = notFound == null ? null : notFound.action(); - matchIgnoreNotFoundWithFetchType( propertyHolder.getEntityName(), property.getName(), notFoundAction, manyToOne.fetch() ); - final OnDelete onDelete = property.getAnnotation( OnDelete.class ); - final JoinTable joinTable = propertyHolder.getJoinTable( property ); + final AnnotationUsage hibernateCascade = property.getAnnotationUsage( Cascade.class ); + final AnnotationUsage notFound = property.getAnnotationUsage( NotFound.class ); + final NotFoundAction notFoundAction = notFound == null ? null : notFound.getEnum( "action" ); + matchIgnoreNotFoundWithFetchType( propertyHolder.getEntityName(), property.getName(), notFoundAction, manyToOne.getEnum( "fetch" ) ); + final AnnotationUsage onDelete = property.getAnnotationUsage( OnDelete.class ); + final AnnotationUsage joinTable = propertyHolder.getJoinTable( property ); bindManyToOne( - getCascadeStrategy( manyToOne.cascade(), hibernateCascade, false, forcePersist ), + getCascadeStrategy( manyToOne.getList( "cascade" ), hibernateCascade, false, forcePersist ), joinColumns, joinTable, - !isMandatory( manyToOne.optional(), property, notFoundAction ), + !isMandatory( manyToOne.getBoolean( "optional" ), property, notFoundAction ), notFoundAction, - onDelete == null ? null : onDelete.action(), + onDelete == null ? null : onDelete.getEnum( "action" ), getTargetEntity( inferredData, context ), propertyHolder, inferredData, @@ -136,7 +136,7 @@ public class ToOneBinder { || isIdentifierMapper; } - private static boolean isMandatory(boolean optional, XProperty property, NotFoundAction notFoundAction) { + private static boolean isMandatory(boolean optional, MemberDetails property, NotFoundAction notFoundAction) { // @MapsId means the columns belong to the pk; // A @MapsId association (obviously) must be non-null when the entity is first persisted. // If a @MapsId association is not mapped with @NotFound(IGNORE), then the association @@ -145,18 +145,18 @@ public class ToOneBinder { // the association is optional. // @OneToOne(optional = true) with @PKJC makes the association optional. return !optional - || property.isAnnotationPresent( Id.class ) - || property.isAnnotationPresent( MapsId.class ) && notFoundAction != NotFoundAction.IGNORE; + || property.hasAnnotationUsage( Id.class ) + || property.hasAnnotationUsage( MapsId.class ) && notFoundAction != NotFoundAction.IGNORE; } private static void bindManyToOne( String cascadeStrategy, AnnotatedJoinColumns joinColumns, - JoinTable joinTable, + AnnotationUsage joinTable, boolean optional, NotFoundAction notFoundAction, OnDeleteAction onDeleteAction, - XClass targetEntity, + ClassDetails targetEntity, PropertyHolder propertyHolder, PropertyData inferredData, boolean unique, // identifies a "logical" @OneToOne @@ -164,8 +164,7 @@ public class ToOneBinder { boolean inSecondPass, PropertyBinder propertyBinder, MetadataBuildingContext context) { - - if ( joinTable != null && !isEmpty( joinTable.name() ) ) { + if ( joinTable != null && !isEmpty( joinTable.getString( "name" ) ) ) { final Join join = propertyHolder.addJoin( joinTable, false ); // TODO: if notFoundAction!=null should we call join.disableForeignKeyCreation() ? for ( AnnotatedJoinColumn joinColumn : joinColumns.getJoinColumns() ) { @@ -180,10 +179,16 @@ public class ToOneBinder { final org.hibernate.mapping.ManyToOne value = new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() ); - if ( joinTable != null && isEmpty( joinTable.name() ) ) { - context.getMetadataCollector() - .addSecondPass( new ImplicitToOneJoinTableSecondPass( propertyHolder, inferredData, context, - joinColumns, joinTable, notFoundAction, value ) ); + if ( joinTable != null && isEmpty( joinTable.getString( "name" ) ) ) { + context.getMetadataCollector().addSecondPass( new ImplicitToOneJoinTableSecondPass( + propertyHolder, + inferredData, + context, + joinColumns, + joinTable, + notFoundAction, + value + ) ); } if ( unique ) { @@ -191,7 +196,7 @@ public class ToOneBinder { value.markAsLogicalOneToOne(); } value.setReferencedEntityName( getReferenceEntityName( inferredData, targetEntity, context ) ); - final XProperty property = inferredData.getProperty(); + final MemberDetails property = inferredData.getAttributeMember(); defineFetchingStrategy( value, property, inferredData, propertyHolder ); //value.setFetchMode( fetchMode ); value.setNotFoundAction( notFoundAction ); @@ -203,15 +208,15 @@ public class ToOneBinder { } } - if ( property.isAnnotationPresent( MapsId.class ) ) { - final MapsId mapsId = property.getAnnotation(MapsId.class); + if ( property.hasAnnotationUsage( MapsId.class ) ) { + final AnnotationUsage mapsId = property.getAnnotationUsage( MapsId.class ); final List joinColumnList = joinColumns.getJoinColumns(); //read only for ( AnnotatedJoinColumn column : joinColumnList ) { column.setInsertable( false ); column.setUpdatable( false ); } - joinColumns.setMapsId( mapsId.value() ); + joinColumns.setMapsId( mapsId.getString( "value" ) ); } boolean hasSpecjManyToOne = handleSpecjSyntax( joinColumns, inferredData, context, property ); @@ -253,31 +258,31 @@ public class ToOneBinder { ); } - static boolean isTargetAnnotatedEntity(XClass targetEntity, XProperty property, MetadataBuildingContext context) { - final XClass target = isDefault( targetEntity, context ) ? property.getType() : targetEntity; - return target.isAnnotationPresent( Entity.class ); + static boolean isTargetAnnotatedEntity(ClassDetails targetEntity, MemberDetails property, MetadataBuildingContext context) { + final ClassDetails target = isDefault( targetEntity, context ) ? property.getType().determineRawClass() : targetEntity; + return target.hasAnnotationUsage( Entity.class ); } private static boolean handleSpecjSyntax( AnnotatedJoinColumns columns, PropertyData inferredData, MetadataBuildingContext context, - XProperty property) { + MemberDetails property) { //Make sure that JPA1 key-many-to-one columns are read only too boolean hasSpecjManyToOne = false; if ( context.getBuildingOptions().isSpecjProprietarySyntaxEnabled() ) { - final JoinColumn joinColumn = property.getAnnotation( JoinColumn.class ); + final AnnotationUsage joinColumn = property.getAnnotationUsage( JoinColumn.class ); String columnName = ""; - for ( XProperty prop : inferredData.getDeclaringClass() - .getDeclaredProperties( AccessType.FIELD.getType() ) ) { - if ( prop.isAnnotationPresent( Id.class ) && prop.isAnnotationPresent( Column.class ) ) { - columnName = prop.getAnnotation( Column.class ).name(); + for ( MemberDetails prop : inferredData.getDeclaringClass().getFields() ) { + if ( prop.hasAnnotationUsage( Id.class ) && prop.hasAnnotationUsage( Column.class ) ) { + columnName = prop.getAnnotationUsage( Column.class ).getString( "name" ); } - if ( property.isAnnotationPresent( ManyToOne.class ) && joinColumn != null ) { - if ( !joinColumn.name().isEmpty() - && joinColumn.name().equals( columnName ) - && !property.isAnnotationPresent( MapsId.class ) ) { + if ( property.hasAnnotationUsage( ManyToOne.class ) && joinColumn != null ) { + final String joinColumnName = joinColumn.getString( "name" ); + if ( StringHelper.isNotEmpty( joinColumnName ) + && joinColumnName.equals( columnName ) + && !property.hasAnnotationUsage( MapsId.class ) ) { hasSpecjManyToOne = true; for ( AnnotatedJoinColumn column : columns.getJoinColumns() ) { column.setInsertable( false ); @@ -298,7 +303,7 @@ public class ToOneBinder { boolean isIdentifierMapper, PropertyBinder propertyBinder, org.hibernate.mapping.ManyToOne value, - XProperty property, + MemberDetails property, boolean hasSpecjManyToOne, String propertyName) { @@ -319,35 +324,34 @@ public class ToOneBinder { propertyBinder.setColumns( columns ); propertyBinder.setAccessType( inferredData.getDefaultAccess() ); propertyBinder.setCascade( cascadeStrategy ); - propertyBinder.setProperty( property ); + propertyBinder.setMemberDetails( property ); propertyBinder.setToMany( true ); - final JoinColumn joinColumn = property.getAnnotation( JoinColumn.class ); - final JoinColumns joinColumns = property.getAnnotation( JoinColumns.class ); - propertyBinder.makePropertyAndBind() - .setOptional( optional && isNullable( joinColumns, joinColumn ) ); + final AnnotationUsage joinColumn = property.getSingleAnnotationUsage( JoinColumn.class ); + final AnnotationUsage joinColumns = property.getAnnotationUsage( JoinColumns.class ); + propertyBinder.makePropertyAndBind().setOptional( optional && isNullable( joinColumns, joinColumn ) ); } - private static boolean isNullable(JoinColumns joinColumns, JoinColumn joinColumn) { + private static boolean isNullable(AnnotationUsage joinColumns, AnnotationUsage joinColumn) { if ( joinColumn != null ) { - return joinColumn.nullable(); + return joinColumn.getBoolean( "nullable" ); } - else if ( joinColumns != null ) { - for ( JoinColumn column : joinColumns.value() ) { - if ( column.nullable() ) { + + if ( joinColumns != null ) { + for ( AnnotationUsage column : joinColumns.>getList( "value" ) ) { + if ( column.getBoolean( "nullable" ) ) { return true; } } return false; } - else { - return true; - } + + return true; } static void defineFetchingStrategy( ToOne toOne, - XProperty property, + MemberDetails property, PropertyData inferredData, PropertyHolder propertyHolder) { handleLazy( toOne, property, inferredData, propertyHolder ); @@ -355,8 +359,8 @@ public class ToOneBinder { handleFetchProfileOverrides( toOne, property, propertyHolder, inferredData ); } - private static void handleLazy(ToOne toOne, XProperty property, PropertyData inferredData, PropertyHolder propertyHolder) { - if ( property.isAnnotationPresent( NotFound.class ) ) { + private static void handleLazy(ToOne toOne, MemberDetails property, PropertyData inferredData, PropertyHolder propertyHolder) { + if ( property.hasAnnotationUsage( NotFound.class ) ) { toOne.setLazy( false ); toOne.setUnwrapProxy( true ); } @@ -370,33 +374,28 @@ public class ToOneBinder { private static void handleFetchProfileOverrides( ToOne toOne, - XProperty property, + MemberDetails property, PropertyHolder propertyHolder, PropertyData inferredData) { final MetadataBuildingContext context = toOne.getBuildingContext(); final InFlightMetadataCollector collector = context.getMetadataCollector(); - if ( property.isAnnotationPresent( FetchProfileOverride.class ) ) { - final FetchProfileOverride fetch = property.getAnnotation( FetchProfileOverride.class ); - collector.addSecondPass( new FetchSecondPass( fetch, propertyHolder, inferredData.getPropertyName(), context ) ); - } - else if ( property.isAnnotationPresent( FetchProfileOverrides.class ) ) { - for ( FetchProfileOverride fetch: property.getAnnotation( FetchProfileOverrides.class ).value() ) { - collector.addSecondPass( new FetchSecondPass( fetch, propertyHolder, inferredData.getPropertyName(), context ) ); - } - } + property.forEachAnnotationUsage( FetchProfileOverride.class, (usage) -> { + collector.addSecondPass( new FetchSecondPass( usage, propertyHolder, inferredData.getPropertyName(), context ) ); + } ); } - private static void handleFetch(ToOne toOne, XProperty property) { - if ( property.isAnnotationPresent( Fetch.class ) ) { + private static void handleFetch(ToOne toOne, MemberDetails property) { + final AnnotationUsage fetchAnnotationUsage = property.getAnnotationUsage( Fetch.class ); + if ( fetchAnnotationUsage != null ) { // Hibernate @Fetch annotation takes precedence - setHibernateFetchMode( toOne, property, property.getAnnotation( Fetch.class ).value() ); + setHibernateFetchMode( toOne, property, fetchAnnotationUsage.getEnum( "value" ) ); } else { toOne.setFetchMode( getFetchMode( getJpaFetchType( property ) ) ); } } - private static void setHibernateFetchMode(ToOne toOne, XProperty property, org.hibernate.annotations.FetchMode fetchMode) { + private static void setHibernateFetchMode(ToOne toOne, MemberDetails property, org.hibernate.annotations.FetchMode fetchMode) { switch ( fetchMode ) { case JOIN: toOne.setFetchMode( FetchMode.JOIN ); @@ -414,12 +413,13 @@ public class ToOneBinder { } } - private static boolean isEager(XProperty property, PropertyData inferredData, PropertyHolder propertyHolder) { + private static boolean isEager(MemberDetails property, PropertyData inferredData, PropertyHolder propertyHolder) { final FetchType fetchType = getJpaFetchType( property ); - if ( property.isAnnotationPresent( LazyToOne.class ) ) { - // LazyToOne takes precedent - final LazyToOne lazy = property.getAnnotation( LazyToOne.class ); - boolean eager = lazy.value() == LazyToOneOption.FALSE; + + final AnnotationUsage lazyToOneAnnotationUsage = property.getAnnotationUsage( LazyToOne.class ); + if ( lazyToOneAnnotationUsage != null ) { + final LazyToOneOption option = lazyToOneAnnotationUsage.getEnum( "value" ); + boolean eager = option == LazyToOneOption.FALSE; if ( eager && fetchType == LAZY ) { // conflicts with non-default setting throw new AnnotationException("Association '" + getPath(propertyHolder, inferredData) @@ -432,14 +432,14 @@ public class ToOneBinder { } } - private static FetchType getJpaFetchType(XProperty property) { - final ManyToOne manyToOne = property.getAnnotation( ManyToOne.class ); - final OneToOne oneToOne = property.getAnnotation( OneToOne.class ); + private static FetchType getJpaFetchType(MemberDetails property) { + final AnnotationUsage manyToOne = property.getAnnotationUsage( ManyToOne.class ); + final AnnotationUsage oneToOne = property.getAnnotationUsage( OneToOne.class ); if ( manyToOne != null ) { - return manyToOne.fetch(); + return manyToOne.getEnum( "fetch" ); } else if ( oneToOne != null ) { - return oneToOne.fetch(); + return oneToOne.getEnum( "fetch" ); } else { throw new AssertionFailure("Define fetch strategy on a property not annotated with @OneToMany nor @OneToOne"); @@ -452,15 +452,15 @@ public class ToOneBinder { boolean isIdentifierMapper, boolean inSecondPass, MetadataBuildingContext context, - XProperty property, + MemberDetails property, AnnotatedJoinColumns joinColumns, PropertyBinder propertyBinder, boolean forcePersist) { - final OneToOne oneToOne = property.getAnnotation( OneToOne.class ); + final AnnotationUsage oneToOne = property.getAnnotationUsage( OneToOne.class ); //check validity - if ( property.isAnnotationPresent( Column.class ) - || property.isAnnotationPresent( Columns.class ) ) { + if ( property.hasAnnotationUsage( Column.class ) + || property.hasAnnotationUsage( Columns.class ) ) { throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) + "' is a '@OneToOne' association and may not use '@Column' to specify column mappings" @@ -476,28 +476,28 @@ public class ToOneBinder { } //FIXME support a proper PKJCs - final boolean trueOneToOne = property.isAnnotationPresent( PrimaryKeyJoinColumn.class ) - || property.isAnnotationPresent( PrimaryKeyJoinColumns.class ); - final Cascade hibernateCascade = property.getAnnotation( Cascade.class ); - final NotFound notFound = property.getAnnotation( NotFound.class ); - final NotFoundAction notFoundAction = notFound == null ? null : notFound.action(); + final boolean trueOneToOne = property.hasAnnotationUsage( PrimaryKeyJoinColumn.class ) + || property.hasAnnotationUsage( PrimaryKeyJoinColumns.class ); + final AnnotationUsage hibernateCascade = property.getAnnotationUsage( Cascade.class ); + final AnnotationUsage notFound = property.getAnnotationUsage( NotFound.class ); + final NotFoundAction notFoundAction = notFound == null ? null : notFound.getEnum( "action" ); - matchIgnoreNotFoundWithFetchType( propertyHolder.getEntityName(), property.getName(), notFoundAction, oneToOne.fetch() ); - final OnDelete onDelete = property.getAnnotation( OnDelete.class ); - final JoinTable joinTable = propertyHolder.getJoinTable(property); + matchIgnoreNotFoundWithFetchType( propertyHolder.getEntityName(), property.getName(), notFoundAction, oneToOne.getEnum( "fetch" ) ); + final AnnotationUsage onDelete = property.getAnnotationUsage( OnDelete.class ); + final AnnotationUsage joinTable = propertyHolder.getJoinTable( property ); bindOneToOne( - getCascadeStrategy( oneToOne.cascade(), hibernateCascade, oneToOne.orphanRemoval(), forcePersist ), + getCascadeStrategy( oneToOne.getList( "cascade" ), hibernateCascade, oneToOne.getBoolean( "orphanRemoval" ), forcePersist ), joinColumns, joinTable, - !isMandatory( oneToOne.optional(), property, notFoundAction ), - getFetchMode( oneToOne.fetch() ), + !isMandatory( oneToOne.getBoolean( "optional" ), property, notFoundAction ), + getFetchMode( oneToOne.getEnum( "fetch" ) ), notFoundAction, - onDelete == null ? null : onDelete.action(), + onDelete == null ? null : onDelete.getEnum( "action" ), getTargetEntity( inferredData, context ), property, propertyHolder, inferredData, - nullIfEmpty( oneToOne.mappedBy() ), + nullIfEmpty( oneToOne.getString( "mappedBy" ) ), trueOneToOne, isIdentifierMapper, inSecondPass, @@ -509,13 +509,13 @@ public class ToOneBinder { private static void bindOneToOne( String cascadeStrategy, AnnotatedJoinColumns joinColumns, - JoinTable joinTable, + AnnotationUsage joinTable, boolean optional, FetchMode fetchMode, NotFoundAction notFoundAction, OnDeleteAction cascadeOnDelete, - XClass targetEntity, - XProperty annotatedProperty, + ClassDetails targetEntity, + MemberDetails annotatedProperty, PropertyHolder propertyHolder, PropertyData inferredData, String mappedBy, @@ -607,77 +607,75 @@ public class ToOneBinder { public static void bindForeignKeyNameAndDefinition( SimpleValue value, - XProperty property, - ForeignKey foreignKey, + MemberDetails property, + AnnotationUsage foreignKey, MetadataBuildingContext context) { - if ( property.getAnnotation( NotFound.class ) != null ) { + if ( property.hasAnnotationUsage( NotFound.class ) ) { // supersedes all others value.disableForeignKey(); } else { - final JoinColumn joinColumn = property.getAnnotation( JoinColumn.class ); - final JoinColumns joinColumns = property.getAnnotation( JoinColumns.class ); + final AnnotationUsage joinColumn = property.getSingleAnnotationUsage( JoinColumn.class ); + final AnnotationUsage joinColumns = property.getAnnotationUsage( JoinColumns.class ); final boolean noConstraintByDefault = context.getBuildingOptions().isNoConstraintByDefault(); - if ( joinColumn != null && noConstraint( joinColumn.foreignKey(), noConstraintByDefault ) - || joinColumns != null && noConstraint( joinColumns.foreignKey(), noConstraintByDefault ) ) { + if ( joinColumn != null && noConstraint( joinColumn.getNestedUsage( "foreignKey" ), noConstraintByDefault ) + || joinColumns != null && noConstraint( joinColumns.getNestedUsage( "foreignKey" ), noConstraintByDefault ) ) { value.disableForeignKey(); } else { - final org.hibernate.annotations.ForeignKey fk = - property.getAnnotation( org.hibernate.annotations.ForeignKey.class ); - if ( fk != null && isNotEmpty( fk.name() ) ) { - value.setForeignKeyName( fk.name() ); + final AnnotationUsage fk = + property.getAnnotationUsage( org.hibernate.annotations.ForeignKey.class ); + if ( fk != null && isNotEmpty( fk.getString( "name" ) ) ) { + value.setForeignKeyName( fk.getString( "name" ) ); } else { if ( noConstraint( foreignKey, noConstraintByDefault ) ) { value.disableForeignKey(); } else if ( foreignKey != null ) { - value.setForeignKeyName( nullIfEmpty( foreignKey.name() ) ); - value.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) ); + value.setForeignKeyName( nullIfEmpty( foreignKey.getString( "name" ) ) ); + value.setForeignKeyDefinition( nullIfEmpty( foreignKey.getString( "foreignKeyDefinition" ) ) ); } else if ( noConstraintByDefault ) { value.disableForeignKey(); } else if ( joinColumns != null ) { - value.setForeignKeyName( nullIfEmpty( joinColumns.foreignKey().name() ) ); - value.setForeignKeyDefinition( nullIfEmpty( joinColumns.foreignKey().foreignKeyDefinition() ) ); + final AnnotationUsage joinColumnsForeignKey = joinColumns.getNestedUsage( "foreignKey" ); + value.setForeignKeyName( nullIfEmpty( joinColumnsForeignKey.getString( "name" ) ) ); + value.setForeignKeyDefinition( nullIfEmpty( joinColumnsForeignKey.getString( "foreignKeyDefinition" ) ) ); } else if ( joinColumn != null ) { - value.setForeignKeyName( nullIfEmpty( joinColumn.foreignKey().name() ) ); - value.setForeignKeyDefinition( nullIfEmpty( joinColumn.foreignKey().foreignKeyDefinition() ) ); + final AnnotationUsage joinColumnForeignKey = joinColumn.getNestedUsage( "foreignKey" ); + value.setForeignKeyName( nullIfEmpty( joinColumnForeignKey.getString( "name" ) ) ); + value.setForeignKeyDefinition( nullIfEmpty( joinColumnForeignKey.getString( "foreignKeyDefinition" ) ) ); } } } } } - public static String getReferenceEntityName(PropertyData propertyData, XClass targetEntity, MetadataBuildingContext context) { + public static String getReferenceEntityName(PropertyData propertyData, ClassDetails targetEntity, MetadataBuildingContext context) { return isDefault( targetEntity, context ) ? propertyData.getClassOrElementName() : targetEntity.getName(); } public static String getReferenceEntityName(PropertyData propertyData, MetadataBuildingContext context) { - final XClass targetEntity = getTargetEntity( propertyData, context ); - return isDefault( targetEntity, context ) - ? propertyData.getClassOrElementName() - : targetEntity.getName(); + return getReferenceEntityName( propertyData, getTargetEntity( propertyData, context ), context ); } - public static XClass getTargetEntity(PropertyData propertyData, MetadataBuildingContext context) { - return context.getBootstrapContext().getReflectionManager() - .toXClass( getTargetEntityClass( propertyData.getProperty() ) ); + public static ClassDetails getTargetEntity(PropertyData propertyData, MetadataBuildingContext context) { + return getTargetEntityClass( propertyData.getAttributeMember() ); } - private static Class getTargetEntityClass(XProperty property) { - final ManyToOne manyToOne = property.getAnnotation( ManyToOne.class ); + private static ClassDetails getTargetEntityClass(MemberDetails property) { + final AnnotationUsage manyToOne = property.getAnnotationUsage( ManyToOne.class ); if ( manyToOne != null ) { - return manyToOne.targetEntity(); + return manyToOne.getClassDetails( "targetEntity" ); } - final OneToOne oneToOne = property.getAnnotation( OneToOne.class ); + final AnnotationUsage oneToOne = property.getAnnotationUsage( OneToOne.class ); if ( oneToOne != null ) { - return oneToOne.targetEntity(); + return oneToOne.getClassDetails( "targetEntity" ); } throw new AssertionFailure( "Unexpected discovery of a targetEntity: " + property.getName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/WrappedInferredData.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/WrappedInferredData.java index 0b804e554c..178e93e68f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/WrappedInferredData.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/WrappedInferredData.java @@ -7,11 +7,12 @@ package org.hibernate.boot.model.internal; import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.PropertyData; import org.hibernate.internal.util.StringHelper; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; /** * @author Emmanuel Bernard @@ -26,8 +27,8 @@ public class WrappedInferredData implements PropertyData { } @Override - public XClass getClassOrElement() throws MappingException { - return wrappedInferredData.getClassOrElement(); + public TypeDetails getClassOrElementType() throws MappingException { + return wrappedInferredData.getClassOrElementType(); } @Override @@ -46,18 +47,18 @@ public class WrappedInferredData implements PropertyData { } @Override - public XProperty getProperty() { - return wrappedInferredData.getProperty(); + public MemberDetails getAttributeMember() { + return wrappedInferredData.getAttributeMember(); } @Override - public XClass getDeclaringClass() { + public ClassDetails getDeclaringClass() { return wrappedInferredData.getDeclaringClass(); } @Override - public XClass getPropertyClass() throws MappingException { - return wrappedInferredData.getPropertyClass(); + public TypeDetails getPropertyType() throws MappingException { + return wrappedInferredData.getPropertyType(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java index 641b877a5b..09f8009697 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java @@ -49,10 +49,8 @@ import org.hibernate.boot.model.source.internal.hbm.HbmMetadataSourceProcessorIm import org.hibernate.boot.model.source.internal.hbm.MappingDocument; import org.hibernate.boot.model.source.internal.hbm.ModelBinder; import org.hibernate.boot.model.source.spi.MetadataSourceProcessor; -import org.hibernate.boot.models.categorize.internal.ClassLoaderServiceLoading; import org.hibernate.boot.models.categorize.internal.DomainModelCategorizationCollector; import org.hibernate.boot.models.categorize.internal.OrmAnnotationHelper; -import org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor; import org.hibernate.boot.models.xml.spi.XmlPreProcessingResult; import org.hibernate.boot.models.xml.spi.XmlPreProcessor; import org.hibernate.boot.models.xml.spi.XmlProcessingResult; @@ -75,7 +73,6 @@ import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.mapping.Table; -import org.hibernate.models.internal.SourceModelBuildingContextImpl; import org.hibernate.models.internal.jandex.JandexClassDetails; import org.hibernate.models.internal.jandex.JandexIndexerHelper; import org.hibernate.models.internal.jdk.JdkBuilders; @@ -194,14 +191,17 @@ public class MetadataBuildingProcess { final ManagedResources managedResources, final BootstrapContext bootstrapContext, final MetadataBuildingOptions options) { - final InFlightMetadataCollectorImpl metadataCollector = new InFlightMetadataCollectorImpl( - bootstrapContext, - options - ); + + final ClassLoaderService classLoaderService = bootstrapContext.getServiceRegistry().getService( ClassLoaderService.class ); + final InFlightMetadataCollectorImpl metadataCollector = new InFlightMetadataCollectorImpl( bootstrapContext, options ); handleTypes( bootstrapContext, options, metadataCollector ); - final DomainModelSource domainModelSource = processManagedResources( managedResources, bootstrapContext ); + final DomainModelSource domainModelSource = processManagedResources( + managedResources, + metadataCollector, + bootstrapContext + ); final MetadataBuildingContextRootImpl rootMetadataBuildingContext = new MetadataBuildingContextRootImpl( "orm", @@ -218,14 +218,12 @@ public class MetadataBuildingProcess { // Set up the processors and start binding // NOTE : this becomes even more simplified after we move purely // to unified model - final ClassLoaderService classLoaderService = options.getServiceRegistry().getService( ClassLoaderService.class ); final IndexView jandexView = domainModelSource.getJandexIndex(); final MetadataSourceProcessor processor = new MetadataSourceProcessor() { - private final MetadataSourceProcessor hbmProcessor = - options.isXmlMappingEnabled() - ? new HbmMetadataSourceProcessorImpl( managedResources, rootMetadataBuildingContext ) - : new NoOpMetadataSourceProcessorImpl(); + private final MetadataSourceProcessor hbmProcessor = options.isXmlMappingEnabled() + ? new HbmMetadataSourceProcessorImpl( managedResources, rootMetadataBuildingContext ) + : new NoOpMetadataSourceProcessorImpl(); private final AnnotationMetadataSourceProcessorImpl annotationProcessor = new AnnotationMetadataSourceProcessorImpl( managedResources, @@ -375,11 +373,8 @@ public class MetadataBuildingProcess { @Internal public static DomainModelSource processManagedResources( ManagedResources managedResources, + InFlightMetadataCollector metadataCollector, BootstrapContext bootstrapContext) { - final ClassLoaderService classLoaderService = bootstrapContext.getServiceRegistry().getService( ClassLoaderService.class ); - final ClassLoaderServiceLoading classLoading = new ClassLoaderServiceLoading( classLoaderService ); - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - pre-process the XML // - collect all known classes @@ -396,6 +391,7 @@ public class MetadataBuildingProcess { // - allKnownClassNames (technically could be included in xmlPreProcessingResult) // - sourceModelBuildingContext + final SourceModelBuildingContext sourceModelBuildingContext = metadataCollector.getSourceModelBuildingContext(); final XmlPreProcessingResult xmlPreProcessingResult = XmlPreProcessor.preProcessXmlResources( managedResources ); //noinspection unchecked @@ -406,7 +402,7 @@ public class MetadataBuildingProcess { ); managedResources.getAnnotatedPackageNames().forEach( (packageName) -> { try { - final Class packageInfoClass = classLoading.classForName( packageName + ".package-info" ); + final Class packageInfoClass = sourceModelBuildingContext.getClassLoading().classForName( packageName + ".package-info" ); allKnownClassNames.add( packageInfoClass.getName() ); } catch (ClassLoadingException classLoadingException) { @@ -417,13 +413,7 @@ public class MetadataBuildingProcess { // At this point we know all managed class names across all sources. // Resolve the Jandex Index and build the SourceModelBuildingContext. - final IndexView jandexIndex = resolveJandexIndex( allKnownClassNames, bootstrapContext.getJandexView(), classLoading ); - final SourceModelBuildingContextImpl sourceModelBuildingContext = new SourceModelBuildingContextImpl( - classLoading, - jandexIndex, - ManagedResourcesProcessor::preFillRegistries - ); - + final IndexView jandexIndex = resolveJandexIndex( allKnownClassNames, bootstrapContext.getJandexView(), sourceModelBuildingContext.getClassLoading() ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - process metadata-complete XML @@ -449,6 +439,7 @@ public class MetadataBuildingProcess { areIdGeneratorsGlobal, classDetailsRegistry, descriptorRegistry, + metadataCollector.getGlobalRegistrations(), jandexIndex ); @@ -473,6 +464,7 @@ public class MetadataBuildingProcess { return new DomainModelSource( classDetailsRegistry.makeImmutableCopy(), jandexIndex, + allKnownClassNames, modelCategorizationCollector.getGlobalRegistrations(), xmlPreProcessingResult.getPersistenceUnitMetadata() ); @@ -495,9 +487,10 @@ public class MetadataBuildingProcess { ClassDetailsRegistry classDetailsRegistry, DomainModelCategorizationCollector modelCategorizationCollector) { modelCategorizationCollector.apply( classDetails ); - if ( classDetails.getSuperType() != null ) { - if ( categorizedClassNames.add( classDetails.getSuperType().getClassName() ) ) { - applyKnownClass( classDetails.getSuperType(), categorizedClassNames, classDetailsRegistry, modelCategorizationCollector ); + if ( classDetails.getSuperClass() != null + && classDetails.getSuperClass() != ClassDetails.OBJECT_CLASS_DETAILS ) { + if ( categorizedClassNames.add( classDetails.getSuperClass().getClassName() ) ) { + applyKnownClass( classDetails.getSuperClass(), categorizedClassNames, classDetailsRegistry, modelCategorizationCollector ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index 544e3bec41..d64bce988d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -13,9 +13,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.hibernate.annotations.common.reflection.MetadataProviderInjector; -import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; @@ -25,22 +22,19 @@ import org.hibernate.boot.model.convert.spi.ConverterRegistry; import org.hibernate.boot.model.convert.spi.RegisteredConversion; import org.hibernate.boot.model.internal.AnnotationBinder; import org.hibernate.boot.model.internal.InheritanceState; -import org.hibernate.boot.model.internal.JPAXMLOverriddenMetadataProvider; import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.process.spi.MetadataBuildingProcess; import org.hibernate.boot.model.source.spi.MetadataSourceProcessor; import org.hibernate.boot.models.categorize.spi.FilterDefRegistration; -import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.JpaOrmXmlPersistenceUnitDefaultAware; -import org.hibernate.boot.spi.JpaOrmXmlPersistenceUnitDefaultAware.JpaOrmXmlPersistenceUnitDefaults; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.engine.spi.FilterDefinition; -import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.usertype.UserType; import org.jboss.logging.Logger; @@ -52,11 +46,10 @@ import jakarta.persistence.MappedSuperclass; import static org.hibernate.boot.jaxb.SourceType.OTHER; import static org.hibernate.boot.model.internal.AnnotationBinder.resolveAttributeConverter; import static org.hibernate.boot.model.internal.AnnotationBinder.resolveBasicType; -import static org.hibernate.boot.model.internal.AnnotationBinder.resolveFilterParamType; import static org.hibernate.boot.model.internal.AnnotationBinder.resolveJavaType; import static org.hibernate.boot.model.internal.AnnotationBinder.resolveUserType; -import static org.hibernate.models.internal.jdk.VoidClassDetails.VOID_CLASS_DETAILS; -import static org.hibernate.models.internal.jdk.VoidClassDetails.VOID_OBJECT_CLASS_DETAILS; +import static org.hibernate.models.spi.ClassDetails.VOID_CLASS_DETAILS; +import static org.hibernate.models.spi.ClassDetails.VOID_OBJECT_CLASS_DETAILS; /** * @author Steve Ebersole @@ -73,9 +66,8 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc private final MetadataBuildingContextRootImpl rootMetadataBuildingContext; private final ClassLoaderService classLoaderService; - private final ReflectionManager reflectionManager; private final LinkedHashSet annotatedPackages = new LinkedHashSet<>(); - private final List xClasses = new ArrayList<>(); + private final LinkedHashSet knownClasses = new LinkedHashSet<>(); /** * Normal constructor used while processing {@linkplain org.hibernate.boot.MetadataSources mapping sources} @@ -87,10 +79,9 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc this.domainModelSource = domainModelSource; this.rootMetadataBuildingContext = rootMetadataBuildingContext; - this.reflectionManager = rootMetadataBuildingContext.getBootstrapContext().getReflectionManager(); - final MetadataBuildingOptions metadataBuildingOptions = rootMetadataBuildingContext.getBuildingOptions(); this.classLoaderService = metadataBuildingOptions.getServiceRegistry().getService( ClassLoaderService.class ); + assert classLoaderService != null; final ConverterRegistry converterRegistry = rootMetadataBuildingContext.getMetadataCollector().getConverterRegistry(); domainModelSource.getConversionRegistrations().forEach( (registration) -> { @@ -116,45 +107,19 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc ) ); } ); - - if ( metadataBuildingOptions.isXmlMappingEnabled() ) { - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Ewww. This is temporary until we migrate to Jandex + StAX for annotation binding - final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) - ( (MetadataProviderInjector) reflectionManager ).getMetadataProvider(); - for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { - Object root = xmlBinding.getRoot(); - if ( !( root instanceof JaxbEntityMappingsImpl ) ) { - continue; - } - final JaxbEntityMappingsImpl entityMappings = (JaxbEntityMappingsImpl) xmlBinding.getRoot(); - final List classNames = jpaMetadataProvider.getXMLContext().addDocument( entityMappings ); - for ( String className : classNames ) { - xClasses.add( toXClass( className ) ); - } - } - } + applyManagedClasses( domainModelSource, knownClasses, rootMetadataBuildingContext ); for ( String className : managedResources.getAnnotatedClassNames() ) { - final Class annotatedClass = classLoaderService.classForName( className ); - xClasses.add( toXClass( annotatedClass ) ); + knownClasses.add( domainModelSource.getClassDetailsRegistry().resolveClassDetails( className ) ); } for ( Class annotatedClass : managedResources.getAnnotatedClassReferences() ) { - xClasses.add( toXClass( annotatedClass ) ); + knownClasses.add( domainModelSource.getClassDetailsRegistry().resolveClassDetails( annotatedClass.getName() ) ); } annotatedPackages.addAll( managedResources.getAnnotatedPackageNames() ); } - private XClass toXClass(String className) { - return reflectionManager.toXClass( classLoaderService.classForName( className ) ); - } - - private XClass toXClass(Class classRef) { - return reflectionManager.toXClass( classRef ); - } - /** * Used as part of processing * {@linkplain org.hibernate.boot.spi.AdditionalMappingContributions#contributeEntity(Class) "additional" mappings} @@ -172,6 +137,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc final ManagedResources mr = mrBuilder.build(); final DomainModelSource additionalDomainModelSource = MetadataBuildingProcess.processManagedResources( mr, + rootMetadataBuildingContext.getMetadataCollector(), rootMetadataBuildingContext.getBootstrapContext() ); final AnnotationMetadataSourceProcessorImpl processor = new AnnotationMetadataSourceProcessorImpl( mr, additionalDomainModelSource, rootMetadataBuildingContext ); @@ -181,27 +147,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc @Override public void prepare() { // use any persistence-unit-defaults defined in orm.xml - // todo : invert this to use the PersistenceUnitMetadata directly (defaulting to the settings) - ( (JpaOrmXmlPersistenceUnitDefaultAware) rootMetadataBuildingContext.getBuildingOptions() ).apply( - new JpaOrmXmlPersistenceUnitDefaults() { - final PersistenceUnitMetadata persistenceUnitMetadata = domainModelSource.getPersistenceUnitMetadata(); - - @Override - public String getDefaultSchemaName() { - return StringHelper.nullIfEmpty( persistenceUnitMetadata.getDefaultSchema() ); - } - - @Override - public String getDefaultCatalogName() { - return StringHelper.nullIfEmpty( persistenceUnitMetadata.getDefaultCatalog() ); - } - - @Override - public boolean shouldImplicitlyQuoteIdentifiers() { - return persistenceUnitMetadata.useQuotedIdentifiers(); - } - } - ); + ( (JpaOrmXmlPersistenceUnitDefaultAware) rootMetadataBuildingContext.getBuildingOptions() ).apply( domainModelSource.getPersistenceUnitMetadata() ); rootMetadataBuildingContext.getMetadataCollector().getDatabase().adjustDefaultNamespace( rootMetadataBuildingContext.getBuildingOptions().getMappingDefaults().getImplicitCatalogName(), @@ -292,13 +238,13 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc @Override public void processEntityHierarchies(Set processedEntityNames) { - final List orderedClasses = orderAndFillHierarchy( xClasses ); - Map inheritanceStatePerClass = AnnotationBinder.buildInheritanceStates( + final List orderedClasses = orderAndFillHierarchy( knownClasses ); + Map inheritanceStatePerClass = AnnotationBinder.buildInheritanceStates( orderedClasses, rootMetadataBuildingContext ); - for ( XClass clazz : orderedClasses ) { + for ( ClassDetails clazz : orderedClasses ) { if ( processedEntityNames.contains( clazz.getName() ) ) { log.debugf( "Skipping annotated class processing of entity [%s], as it has already been processed", clazz ); } @@ -310,17 +256,29 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc } } - /** - * @return a partially ordered list so entry's ancestors always show up earlier - */ - private List orderAndFillHierarchy(List classes) { + private List orderAndFillHierarchy(LinkedHashSet original) { + + LinkedHashSet copy = new LinkedHashSet<>( original.size() ); + insertMappedSuperclasses( original, copy ); + + // order the hierarchy + List workingCopy = new ArrayList<>( copy ); + List newList = new ArrayList<>( copy.size() ); + while ( !workingCopy.isEmpty() ) { + ClassDetails clazz = workingCopy.get( 0 ); + orderHierarchy( workingCopy, newList, copy, clazz ); + } + return newList; + } + + private void insertMappedSuperclasses(LinkedHashSet original, LinkedHashSet copy) { final boolean debug = log.isDebugEnabled(); LinkedHashSet orderedClasses = CollectionHelper.linkedSetOfSize( classes.size() * 2 ); List clazzHierarchy = new ArrayList<>(); - for ( XClass clazz : classes ) { - if ( clazz.isAnnotationPresent( MappedSuperclass.class ) ) { + for ( ClassDetails clazz : classes ) { + if ( clazz.hasAnnotationUsage( MappedSuperclass.class ) ) { if ( debug ) { log.debugf( "Skipping explicit MappedSuperclass %s, the class will be discovered analyzing the implementing class", @@ -336,20 +294,29 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc clazzHierarchy.clear(); clazzHierarchy.add( clazz ); - XClass superClass = clazz.getSuperclass(); + ClassDetails superClass = clazz.getSuperClass(); while ( superClass != null - && !reflectionManager.equals( superClass, Object.class ) ) { - if ( superClass.isAnnotationPresent( Entity.class ) - || superClass.isAnnotationPresent( MappedSuperclass.class ) ) { + && !Object.class.getName().equals( superClass.getName() ) ) { + if ( superClass.hasAnnotationUsage( Entity.class ) + || superClass.hasAnnotationUsage( MappedSuperclass.class ) ) { if ( orderedClasses.contains( superClass ) ) { break; } clazzHierarchy.add( superClass ); } - superClass = superClass.getSuperclass(); + superClass = superClass.getSuperClass(); } - for (int i = clazzHierarchy.size() - 1; i >= 0; i-- ) { - orderedClasses.add( clazzHierarchy.get(i) ); + } + } + } + + private void orderHierarchy(List copy, List newList, LinkedHashSet original, ClassDetails clazz) { + if ( clazz != null && !Object.class.getName().equals( clazz.getName() ) ) { + //process superclass first + orderHierarchy( copy, newList, original, clazz.getSuperClass() ); + if ( original.contains( clazz ) ) { + if ( !newList.contains( clazz ) ) { + newList.add( clazz ); } } } @@ -370,4 +337,14 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc @Override public void finishUp() { } + + private static void applyManagedClasses( + DomainModelSource domainModelSource, + LinkedHashSet knownClasses, + MetadataBuildingContextRootImpl rootMetadataBuildingContext) { + final ClassDetailsRegistry classDetailsRegistry = domainModelSource.getClassDetailsRegistry(); + domainModelSource.getManagedClassNames().forEach( (className) -> { + knownClasses.add( classDetailsRegistry.resolveClassDetails( className ) ); + } ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/DomainModelSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/DomainModelSource.java index 7bc450c85b..e149acd2c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/DomainModelSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/DomainModelSource.java @@ -6,7 +6,6 @@ */ package org.hibernate.boot.model.source.internal.annotations; -import java.util.Collections; import java.util.List; import java.util.Set; @@ -14,6 +13,7 @@ import org.hibernate.boot.models.categorize.spi.ConversionRegistration; import org.hibernate.boot.models.categorize.spi.ConverterRegistration; import org.hibernate.boot.models.categorize.spi.GlobalRegistrations; import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; import org.jboss.jandex.IndexView; @@ -24,18 +24,21 @@ import org.jboss.jandex.IndexView; public class DomainModelSource { private final ClassDetailsRegistry classDetailsRegistry; private final IndexView jandexIndex; - private final GlobalRegistrations globalRegistrations; private final PersistenceUnitMetadata persistenceUnitMetadata; + private final GlobalRegistrations globalRegistrations; + private final List allKnownClassNames; public DomainModelSource( ClassDetailsRegistry classDetailsRegistry, IndexView jandexIndex, + List allKnownClassNames, GlobalRegistrations globalRegistrations, PersistenceUnitMetadata persistenceUnitMetadata) { this.classDetailsRegistry = classDetailsRegistry; this.jandexIndex = jandexIndex; - this.globalRegistrations = globalRegistrations; this.persistenceUnitMetadata = persistenceUnitMetadata; + this.globalRegistrations = globalRegistrations; + this.allKnownClassNames = allKnownClassNames; } public ClassDetailsRegistry getClassDetailsRegistry() { @@ -46,6 +49,10 @@ public class DomainModelSource { return jandexIndex; } + public PersistenceUnitMetadata getPersistenceUnitMetadata() { + return persistenceUnitMetadata; + } + public GlobalRegistrations getGlobalRegistrations() { return globalRegistrations; } @@ -58,7 +65,7 @@ public class DomainModelSource { return globalRegistrations.getJpaConverters(); } - public PersistenceUnitMetadata getPersistenceUnitMetadata() { - return persistenceUnitMetadata; + public List getManagedClassNames() { + return allKnownClassNames; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index 544c38379a..ffff42c1a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -442,27 +442,6 @@ public class ModelBinder { entityDescriptor.setBatchSize( entitySource.getBatchSize() ); entityDescriptor.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() ); - if ( isNotEmpty( entitySource.getCustomPersisterClassName() ) ) { - try { - entityDescriptor.setEntityPersisterClass( - sourceDocument.getBootstrapContext() - .getClassLoaderAccess() - .classForName( entitySource.getCustomPersisterClassName() ) - ); - } - catch (ClassLoadingException e) { - throw new MappingException( - String.format( - Locale.ENGLISH, - "Unable to load specified persister class : %s", - entitySource.getCustomPersisterClassName() - ), - e, - sourceDocument.getOrigin() - ); - } - } - bindCustomSql( entitySource, entityDescriptor ); final JdbcEnvironment jdbcEnvironment = sourceDocument.getMetadataCollector().getDatabase().getJdbcEnvironment(); @@ -1418,10 +1397,10 @@ public class ModelBinder { binding.setOptimisticLocked( source.isIncludedInOptimisticLocking() ); if ( source.getCustomPersisterClassName() != null ) { - binding.setCollectionPersisterClass( - mappingDocument.getBootstrapContext().getClassLoaderAccess().classForName( - mappingDocument.qualifyClassName( source.getCustomPersisterClassName() ) - ) + DEPRECATION_LOGGER.debugf( + "Custom CollectionPersister impls are no longer supported - %s (%s)", + binding.getRole(), + mappingDocument.getOrigin().getName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java b/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java index a8dc78f2ae..a3f41846ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java @@ -21,13 +21,17 @@ import org.hibernate.models.spi.AnnotationDescriptor; import static org.hibernate.models.internal.AnnotationHelper.createOrmDescriptor; /** - * Details about Hibernate annotations + * Details about Hibernate annotations. * - * @implNote Suppressed for deprecation because we refer to many deprecated annotations + * @apiNote Here we only collect "stateless" annotations - namely those where we do not care about + * meta-annotations, which is the vast majority. + * + * @implNote Suppressed for deprecation and removal because we refer to many deprecated annotations; suppressed + * for unused because * * @author Steve Ebersole */ -@SuppressWarnings("deprecation") +@SuppressWarnings({ "deprecation", "removal", "unused" }) public interface HibernateAnnotations { AnnotationDescriptor ANY = createOrmDescriptor( Any.class ); AnnotationDescriptor ANY_DISCRIMINATOR = createOrmDescriptor( AnyDiscriminator.class ); @@ -159,7 +163,6 @@ public interface HibernateAnnotations { AnnotationDescriptor SYNCHRONIZE = createOrmDescriptor( Synchronize.class ); AnnotationDescriptor TABLES = createOrmDescriptor( Tables.class ); AnnotationDescriptor TABLE = createOrmDescriptor( Table.class, TABLES ); - AnnotationDescriptor TENANT_ID = createOrmDescriptor( TenantId.class ); AnnotationDescriptor TZ_COLUMN = createOrmDescriptor( TimeZoneColumn.class ); AnnotationDescriptor TZ_STORAGE = createOrmDescriptor( TimeZoneStorage.class ); AnnotationDescriptor TYPE = createOrmDescriptor( Type.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/JpaAnnotations.java b/hibernate-core/src/main/java/org/hibernate/boot/models/JpaAnnotations.java index 06b47e67ae..c5abb4ab34 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/JpaAnnotations.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/JpaAnnotations.java @@ -22,6 +22,7 @@ import jakarta.persistence.Cacheable; import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; import jakarta.persistence.ColumnResult; +import jakarta.persistence.ConstructorResult; import jakarta.persistence.Convert; import jakarta.persistence.Converter; import jakarta.persistence.Converts; @@ -116,6 +117,7 @@ public interface JpaAnnotations { AnnotationDescriptor COLLECTION_TABLE = createOrmDescriptor( CollectionTable.class ); AnnotationDescriptor COLUMN = createOrmDescriptor( Column.class ); AnnotationDescriptor COLUMN_RESULT = createOrmDescriptor( ColumnResult.class ); + AnnotationDescriptor CONSTRUCTOR_RESULT = createOrmDescriptor( ConstructorResult.class ); AnnotationDescriptor CONVERTS = createOrmDescriptor( Converts.class ); AnnotationDescriptor CONVERT = createOrmDescriptor( Convert.class, CONVERTS ); AnnotationDescriptor CONVERTER = createOrmDescriptor( Converter.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BasicValueHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BasicValueHelper.java index a32e83ff7c..8249ef3824 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BasicValueHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/bind/internal/BasicValueHelper.java @@ -69,7 +69,7 @@ public class BasicValueHelper { @SuppressWarnings("unused") BindingOptions bindingOptions, @SuppressWarnings("unused") BindingState bindingState, @SuppressWarnings("unused") BindingContext bindingContext) { - basicValue.setImplicitJavaTypeAccess( (typeConfiguration) -> member.getType().toJavaClass() ); + basicValue.setImplicitJavaTypeAccess( (typeConfiguration) -> member.getType().determineRawClass().toJavaClass() ); } public static void bindJavaType( @@ -313,7 +313,7 @@ public class BasicValueHelper { final TypeConfiguration typeConfiguration = collector.getTypeConfiguration(); final MemberDetails memberDetails = tenantIdAttribute.getMember(); - final String returnedClassName = memberDetails.getType().getClassName(); + final String returnedClassName = memberDetails.getType().determineRawClass().getClassName(); final BasicType tenantIdType = typeConfiguration .getBasicTypeRegistry() .getRegisteredType( returnedClassName ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/CategorizationHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/CategorizationHelper.java index 671e403e64..17d8281ffa 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/CategorizationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/CategorizationHelper.java @@ -10,6 +10,7 @@ import java.util.EnumSet; import org.hibernate.annotations.Any; import org.hibernate.annotations.ManyToAny; +import org.hibernate.annotations.TenantId; import org.hibernate.boot.models.HibernateAnnotations; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.MultipleAttributeNaturesException; @@ -98,7 +99,7 @@ public class CategorizationHelper { if ( embedded != null || embeddedId != null - || ( backingMember.getType() != null && backingMember.getType().getAnnotationUsage( JpaAnnotations.EMBEDDABLE ) != null ) ) { + || ( backingMember.getType() != null && backingMember.getType().determineRawClass().getAnnotationUsage( JpaAnnotations.EMBEDDABLE ) != null ) ) { natures.add( EMBEDDED ); } @@ -142,7 +143,7 @@ public class CategorizationHelper { || backingMember.getAnnotationUsage( HibernateAnnotations.TZ_COLUMN ) != null || backingMember.getAnnotationUsage( HibernateAnnotations.TZ_STORAGE ) != null || backingMember.getAnnotationUsage( HibernateAnnotations.TYPE ) != null - || backingMember.getAnnotationUsage( HibernateAnnotations.TENANT_ID ) != null + || backingMember.getAnnotationUsage( TenantId.class ) != null || backingMember.getAnnotationUsage( HibernateAnnotations.JAVA_TYPE ) != null || backingMember.getAnnotationUsage( HibernateAnnotations.JDBC_TYPE_CODE ) != null || backingMember.getAnnotationUsage( HibernateAnnotations.JDBC_TYPE ) != null; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/DomainModelCategorizationCollector.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/DomainModelCategorizationCollector.java index 17713ff87a..9ccd139638 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/DomainModelCategorizationCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/DomainModelCategorizationCollector.java @@ -17,11 +17,13 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitDefaultsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitMetadataImpl; import org.hibernate.boot.models.categorize.spi.CategorizedDomainModel; import org.hibernate.boot.models.categorize.spi.EntityHierarchy; +import org.hibernate.boot.models.categorize.spi.GlobalRegistrations; import org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor; import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.models.spi.AnnotationDescriptorRegistry; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; import org.jboss.jandex.IndexView; @@ -53,10 +55,11 @@ public class DomainModelCategorizationCollector { boolean areIdGeneratorsGlobal, ClassDetailsRegistry classDetailsRegistry, AnnotationDescriptorRegistry descriptorRegistry, + GlobalRegistrations globalRegistrations, IndexView jandexIndex) { this.areIdGeneratorsGlobal = areIdGeneratorsGlobal; this.jandexIndex = jandexIndex; - this.globalRegistrations = new GlobalRegistrationsImpl( classDetailsRegistry, descriptorRegistry ); + this.globalRegistrations = (GlobalRegistrationsImpl) globalRegistrations; } public GlobalRegistrationsImpl getGlobalRegistrations() { @@ -99,7 +102,8 @@ public class DomainModelCategorizationCollector { getGlobalRegistrations().collectIdGenerators( jaxbRoot ); - // todo : named queries + getGlobalRegistrations().collectQueryReferences( jaxbRoot ); + // todo : named graphs } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyBuilder.java index 94cd3e42a5..4829fdcd17 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyBuilder.java @@ -10,7 +10,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.hibernate.boot.models.AccessTypeDeterminationException; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.categorize.spi.EntityHierarchy; import org.hibernate.boot.models.categorize.spi.IdentifiableTypeMetadata; @@ -127,7 +126,7 @@ public class EntityHierarchyBuilder { return accessAnnotation.getAttributeValue( "value" ); } - current = current.getSuperType(); + current = current.getSuperClass(); } return null; @@ -152,7 +151,7 @@ public class EntityHierarchyBuilder { } } - current = current.getSuperType(); + current = current.getSuperClass(); } return null; @@ -208,17 +207,17 @@ public class EntityHierarchyBuilder { // 1) it has no super-types // 2) its super types contain no entities (MappedSuperclasses are allowed) - if ( classInfo.getSuperType() == null ) { + if ( classInfo.getSuperClass() == null ) { return true; } - ClassDetails current = classInfo.getSuperType(); + ClassDetails current = classInfo.getSuperClass(); while ( current != null ) { if ( current.getAnnotationUsage( JpaAnnotations.ENTITY ) != null && !current.isAbstract() ) { // a non-abstract super type has `@Entity` -> classInfo cannot be a root entity return false; } - current = current.getSuperType(); + current = current.getSuperClass(); } // if we hit no opt-outs we have a root diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyImpl.java index 02bf5ee406..b8e10a7c2b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/EntityHierarchyImpl.java @@ -117,8 +117,8 @@ public class EntityHierarchyImpl implements EntityHierarchy { } private ClassDetails findRootRoot(ClassDetails rootEntityClassDetails) { - if ( rootEntityClassDetails.getSuperType() != null ) { - final ClassDetails match = walkSupers( rootEntityClassDetails.getSuperType() ); + if ( rootEntityClassDetails.getSuperClass() != null ) { + final ClassDetails match = walkSupers( rootEntityClassDetails.getSuperClass() ); if ( match != null ) { return match; } @@ -129,8 +129,8 @@ public class EntityHierarchyImpl implements EntityHierarchy { private ClassDetails walkSupers(ClassDetails type) { assert type != null; - if ( type.getSuperType() != null ) { - final ClassDetails match = walkSupers( type.getSuperType() ); + if ( type.getSuperClass() != null ) { + final ClassDetails match = walkSupers( type.getSuperClass() ); if ( match != null ) { return match; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/GlobalRegistrationsImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/GlobalRegistrationsImpl.java index 151a0f39f4..1315db731f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/GlobalRegistrationsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/internal/GlobalRegistrationsImpl.java @@ -14,6 +14,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import org.hibernate.annotations.FilterDef; import org.hibernate.annotations.GenericGenerator; @@ -21,20 +22,33 @@ import org.hibernate.annotations.Imported; import org.hibernate.annotations.ParamDef; import org.hibernate.annotations.Parameter; import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionUserTypeRegistrationImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbColumnResultImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbCompositeUserTypeRegistrationImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbConfigurationParameterImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbConstructorResultImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbConverterImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbConverterRegistrationImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddableInstantiatorRegistrationImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListenerImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityResultImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbFieldResultImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbFilterDefImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbGenericIdGeneratorImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbJavaTypeRegistrationImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbJdbcTypeRegistrationImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedNativeQueryImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQueryBase; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQueryImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedStoredProcedureQueryImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbQueryHint; import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGeneratorImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbSqlResultSetMappingImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbStoredProcedureParameterImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGeneratorImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbUserTypeRegistrationImpl; +import org.hibernate.boot.models.HibernateAnnotations; +import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.categorize.spi.CollectionTypeRegistration; import org.hibernate.boot.models.categorize.spi.CompositeUserTypeRegistration; import org.hibernate.boot.models.categorize.spi.ConversionRegistration; @@ -47,24 +61,38 @@ import org.hibernate.boot.models.categorize.spi.JavaTypeRegistration; import org.hibernate.boot.models.categorize.spi.JdbcTypeRegistration; import org.hibernate.boot.models.categorize.spi.JpaEventListener; import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; +import org.hibernate.boot.models.categorize.spi.NamedNativeQueryRegistration; +import org.hibernate.boot.models.categorize.spi.NamedQueryRegistration; +import org.hibernate.boot.models.categorize.spi.NamedStoredProcedureQueryRegistration; import org.hibernate.boot.models.categorize.spi.SequenceGeneratorRegistration; +import org.hibernate.boot.models.categorize.spi.SqlResultSetMappingRegistration; import org.hibernate.boot.models.categorize.spi.TableGeneratorRegistration; import org.hibernate.boot.models.categorize.spi.UserTypeRegistration; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.jpa.AvailableHints; import org.hibernate.metamodel.CollectionClassification; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.dynamic.DynamicAnnotationUsage; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationDescriptorRegistry; import org.hibernate.models.spi.AnnotationTarget; import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.MutableAnnotationUsage; import org.hibernate.models.spi.SourceModelContext; +import jakarta.persistence.ColumnResult; +import jakarta.persistence.ConstructorResult; +import jakarta.persistence.EntityResult; +import jakarta.persistence.FieldResult; +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.NamedStoredProcedureQuery; +import jakarta.persistence.QueryHint; import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.SqlResultSetMapping; +import jakarta.persistence.StoredProcedureParameter; import jakarta.persistence.TableGenerator; import static java.util.Collections.emptyList; @@ -78,6 +106,7 @@ import static org.hibernate.boot.models.HibernateAnnotations.FILTER_DEF; import static org.hibernate.boot.models.HibernateAnnotations.JAVA_TYPE_REG; import static org.hibernate.boot.models.HibernateAnnotations.JDBC_TYPE_REG; import static org.hibernate.boot.models.HibernateAnnotations.TYPE_REG; +import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; /** @@ -104,6 +133,11 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { private Set jpaConverters; + private Map sqlResultSetMappingRegistrations; + private Map namedQueryRegistrations; + private Map namedNativeQueryRegistrations; + private Map namedStoredProcedureQueryRegistrations; + public GlobalRegistrationsImpl(SourceModelContext sourceModelContext) { this( sourceModelContext.getClassDetailsRegistry(), sourceModelContext.getAnnotationDescriptorRegistry() ); } @@ -183,6 +217,26 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { return jpaConverters == null ? emptySet() : jpaConverters; } + @Override + public Map getSqlResultSetMappingRegistrations() { + return sqlResultSetMappingRegistrations == null ? emptyMap() : sqlResultSetMappingRegistrations; + } + + @Override + public Map getNamedQueryRegistrations() { + return namedQueryRegistrations == null ? emptyMap() : namedQueryRegistrations; + } + + @Override + public Map getNamedNativeQueryRegistrations() { + return namedNativeQueryRegistrations == null ? emptyMap() : namedNativeQueryRegistrations; + } + + @Override + public Map getNamedStoredProcedureQueryRegistrations() { + return namedStoredProcedureQueryRegistrations== null ? emptyMap() : namedStoredProcedureQueryRegistrations; + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JavaTypeRegistration @@ -581,7 +635,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { } sequenceGenerators.forEach( (generator) -> { - final MutableAnnotationUsage annotationUsage = makeAnnotation( SequenceGenerator.class ); + final MutableAnnotationUsage annotationUsage = makeAnnotation( JpaAnnotations.SEQUENCE_GENERATOR ); annotationUsage.setAttributeValue( "name", generator.getName() ); annotationUsage.setAttributeValue( "sequenceName", generator.getSequenceName() ); annotationUsage.setAttributeValue( "catalog", generator.getCatalog() ); @@ -593,9 +647,8 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { } ); } - private MutableAnnotationUsage makeAnnotation(Class annotationType) { - final AnnotationDescriptor descriptor = descriptorRegistry.getDescriptor( annotationType ); - return new DynamicAnnotationUsage<>( descriptor ); + private MutableAnnotationUsage makeAnnotation(AnnotationDescriptor annotationDescriptor) { + return annotationDescriptor.createUsage( null, null ); } public void collectSequenceGenerator(AnnotationUsage usage) { @@ -607,7 +660,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { sequenceGeneratorRegistrations = new HashMap<>(); } - sequenceGeneratorRegistrations.put( generatorRegistration.getName(), generatorRegistration ); + sequenceGeneratorRegistrations.put( generatorRegistration.name(), generatorRegistration ); } @@ -620,7 +673,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { } tableGenerators.forEach( (generator) -> { - final MutableAnnotationUsage annotationUsage = makeAnnotation( TableGenerator.class ); + final MutableAnnotationUsage annotationUsage = makeAnnotation( JpaAnnotations.TABLE_GENERATOR ); annotationUsage.setAttributeValue( "name", generator.getName() ); annotationUsage.setAttributeValue( "table", generator.getTable() ); annotationUsage.setAttributeValue( "catalog", generator.getCatalog() ); @@ -644,7 +697,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { tableGeneratorRegistrations = new HashMap<>(); } - tableGeneratorRegistrations.put( generatorRegistration.getName(), generatorRegistration ); + tableGeneratorRegistrations.put( generatorRegistration.name(), generatorRegistration ); } @@ -657,7 +710,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { } genericGenerators.forEach( (generator) -> { - final MutableAnnotationUsage annotationUsage = makeAnnotation( GenericGenerator.class ); + final MutableAnnotationUsage annotationUsage = makeAnnotation( HibernateAnnotations.GENERIC_GENERATOR ); annotationUsage.setAttributeValue( "name", generator.getName() ); annotationUsage.setAttributeValue( "strategy", generator.getClazz() ); @@ -676,7 +729,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { genericGeneratorRegistrations = new HashMap<>(); } - genericGeneratorRegistrations.put( generatorRegistration.getName(), generatorRegistration ); + genericGeneratorRegistrations.put( generatorRegistration.name(), generatorRegistration ); } @@ -709,4 +762,317 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations { jpaConverters.add( new ConverterRegistration( converterType, autoApply ) ); } ); } + + public void collectQueryReferences(JaxbEntityMappingsImpl jaxbRoot) { + collectNamedSqlResultSetMappings( jaxbRoot.getSqlResultSetMappings() ); + collectNamedQueries( jaxbRoot.getNamedQueries() ); + collectNamedNativeQueries( jaxbRoot.getNamedNativeQueries() ); + collectStoredProcedureQueries( jaxbRoot.getNamedProcedureQueries() ); + } + + private void collectNamedSqlResultSetMappings(List jaxbSqlResultSetMappings) { + if ( isEmpty( jaxbSqlResultSetMappings ) ) { + return; + } + + if ( sqlResultSetMappingRegistrations == null ) { + sqlResultSetMappingRegistrations = new HashMap<>(); + } + + jaxbSqlResultSetMappings.forEach( (jaxbMapping) -> { + final MutableAnnotationUsage mappingAnnotation = JpaAnnotations.SQL_RESULT_SET_MAPPING.createUsage( null, null ); + mappingAnnotation.setAttributeValue( "name", jaxbMapping.getName() ); + + sqlResultSetMappingRegistrations.put( + jaxbMapping.getName(), + new SqlResultSetMappingRegistration( jaxbMapping.getName(), mappingAnnotation ) + ); + + applyEntityResults( + jaxbMapping.getEntityResult(), + (results) -> mappingAnnotation.setAttributeValue( "entities", results ) + ); + + applyConstructorResults( + jaxbMapping.getConstructorResult(), + (results) -> mappingAnnotation.setAttributeValue( "classes", results ) + ); + + applyColumnResults( + jaxbMapping.getColumnResult(), + (columnResults) -> mappingAnnotation.setAttributeValue( "columns", columnResults ) + ); + } ); + } + + private void applyEntityResults( + List jaxbEntityResults, + Consumer>> annotationListConsumer) { + if ( jaxbEntityResults.isEmpty() ) { + return; + } + + final List> entityResults = arrayList( jaxbEntityResults.size() ); + + for ( JaxbEntityResultImpl jaxbEntityResult : jaxbEntityResults ) { + final MutableAnnotationUsage entityResultAnnotation = makeAnnotation( JpaAnnotations.ENTITY_RESULT ); + entityResults.add( entityResultAnnotation ); + + entityResultAnnotation.setAttributeValue( "entityClass", classDetailsRegistry.resolveClassDetails( jaxbEntityResult.getEntityClass() ) ); + entityResultAnnotation.setAttributeValue( "lockMode", jaxbEntityResult.getLockMode() ); + entityResultAnnotation.setAttributeValue( "discriminatorColumn", jaxbEntityResult.getDiscriminatorColumn() ); + + if ( !jaxbEntityResult.getFieldResult().isEmpty() ) { + final List> fieldResults = arrayList( jaxbEntityResult.getFieldResult().size() ); + entityResultAnnotation.setAttributeValue( "fields", fieldResults ); + + for ( JaxbFieldResultImpl jaxbFieldResult : jaxbEntityResult.getFieldResult() ) { + final MutableAnnotationUsage fieldResultAnnotation = makeAnnotation( JpaAnnotations.FIELD_RESULT ); + fieldResultAnnotation.setAttributeValue( "name", jaxbFieldResult.getName() ); + fieldResultAnnotation.setAttributeValue( "column", jaxbFieldResult.getColumn() ); + } + } + } + annotationListConsumer.accept( entityResults ); + } + + private void applyConstructorResults( + List jaxbConstructorResults, + Consumer>> annotationListConsumer) { + if ( isEmpty( jaxbConstructorResults ) ) { + return; + } + + final List> results = arrayList( jaxbConstructorResults.size() ); + for ( JaxbConstructorResultImpl jaxbConstructorResult : jaxbConstructorResults ) { + final MutableAnnotationUsage result = makeAnnotation( JpaAnnotations.CONSTRUCTOR_RESULT ); + results.add( result ); + + result.setAttributeValue( + "entityClass", + classDetailsRegistry.resolveClassDetails( jaxbConstructorResult.getTargetClass() ) + ); + + if ( !jaxbConstructorResult.getColumns().isEmpty() ) { + applyColumnResults( + jaxbConstructorResult.getColumns(), + (columnResults) -> result.setAttributeValue( "columns", columnResults ) + ); + } + } + } + + private void applyColumnResults( + List jaxbColumnResults, + Consumer>> annotationListConsumer) { + if ( isEmpty( jaxbColumnResults ) ) { + return; + } + + final List> columnResults = arrayList( jaxbColumnResults.size() ); + for ( JaxbColumnResultImpl jaxbColumn : jaxbColumnResults ) { + final MutableAnnotationUsage columnResultAnnotation = makeAnnotation( JpaAnnotations.COLUMN_RESULT ); + columnResults.add( columnResultAnnotation ); + + columnResultAnnotation.setAttributeValue( "name", jaxbColumn.getName() ); + columnResultAnnotation.setAttributeValue( "type", classDetailsRegistry.resolveClassDetails( jaxbColumn.getClazz() ) ); + } + annotationListConsumer.accept( columnResults ); + } + + private void collectNamedQueries(List jaxbNamedQueries) { + if ( isEmpty( jaxbNamedQueries ) ) { + return; + } + + if ( namedQueryRegistrations == null ) { + namedQueryRegistrations = new HashMap<>(); + } + + for ( JaxbNamedQueryImpl jaxbNamedQuery : jaxbNamedQueries ) { + final MutableAnnotationUsage queryAnnotation = makeAnnotation( JpaAnnotations.NAMED_QUERY ); + namedQueryRegistrations.put( + jaxbNamedQuery.getName(), + new NamedQueryRegistration( jaxbNamedQuery.getName(), queryAnnotation ) + ); + + queryAnnotation.setAttributeValue( "name", jaxbNamedQuery.getName() ); + queryAnnotation.setAttributeValue( "query", jaxbNamedQuery.getQuery() ); + queryAnnotation.setAttributeValue( "lockMode", jaxbNamedQuery.getLockMode() ); + + final List> hints = extractQueryHints( jaxbNamedQuery ); + queryAnnotation.setAttributeValue( "hints", hints ); + + if ( jaxbNamedQuery.isCacheable() == Boolean.TRUE ) { + final MutableAnnotationUsage cacheableHint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + cacheableHint.setAttributeValue( "name", AvailableHints.HINT_CACHEABLE ); + cacheableHint.setAttributeValue( "value", Boolean.TRUE.toString() ); + + if ( jaxbNamedQuery.getCacheMode() != null ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_CACHE_MODE ); + hint.setAttributeValue( "value", jaxbNamedQuery.getCacheMode().name() ); + } + + if ( StringHelper.isNotEmpty( jaxbNamedQuery.getCacheRegion() ) ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_CACHE_REGION ); + hint.setAttributeValue( "value", jaxbNamedQuery.getCacheRegion() ); + } + } + + if ( StringHelper.isNotEmpty( jaxbNamedQuery.getComment() ) ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_COMMENT ); + hint.setAttributeValue( "value", jaxbNamedQuery.getComment() ); + } + + if ( jaxbNamedQuery.getFetchSize() != null ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_FETCH_SIZE ); + hint.setAttributeValue( "value", jaxbNamedQuery.getFetchSize().toString() ); + } + + if ( jaxbNamedQuery.isReadOnly() == Boolean.TRUE ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_READ_ONLY ); + hint.setAttributeValue( "value", Boolean.TRUE.toString() ); + } + + if ( jaxbNamedQuery.getFlushMode() != null ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_FLUSH_MODE ); + hint.setAttributeValue( "value", jaxbNamedQuery.getFlushMode().name() ); + } + } + } + + private void collectNamedNativeQueries(List namedNativeQueries) { + if ( isEmpty( namedNativeQueries ) ) { + return; + } + + if ( namedNativeQueryRegistrations == null ) { + namedNativeQueryRegistrations = new HashMap<>(); + } + + for ( JaxbNamedNativeQueryImpl jaxbNamedQuery : namedNativeQueries ) { + final MutableAnnotationUsage queryAnnotation = makeAnnotation( JpaAnnotations.NAMED_NATIVE_QUERY ); + namedNativeQueryRegistrations.put( + jaxbNamedQuery.getName(), + new NamedNativeQueryRegistration( jaxbNamedQuery.getName(), queryAnnotation ) + ); + + queryAnnotation.setAttributeValue( "name", jaxbNamedQuery.getName() ); + queryAnnotation.setAttributeValue( "query", jaxbNamedQuery.getQuery() ); + + if ( StringHelper.isNotEmpty( jaxbNamedQuery.getResultClass() ) ) { + queryAnnotation.setAttributeValue( "resultClass", classDetailsRegistry.resolveClassDetails( jaxbNamedQuery.getResultClass() ) ); + } + + if ( StringHelper.isNotEmpty( jaxbNamedQuery.getResultSetMapping() ) ) { + queryAnnotation.setAttributeValue( "resultSetMapping", jaxbNamedQuery.getResultSetMapping() ); + } + + applyEntityResults( + jaxbNamedQuery.getEntityResult(), + (results) -> queryAnnotation.setAttributeValue( "entities", results ) + ); + + applyConstructorResults( + jaxbNamedQuery.getConstructorResult(), + (results) -> queryAnnotation.setAttributeValue( "classes", results ) + ); + + applyColumnResults( + jaxbNamedQuery.getColumnResult(), + (columnResults) -> queryAnnotation.setAttributeValue( "columns", columnResults ) + ); + + final List> hints = extractQueryHints( jaxbNamedQuery ); + queryAnnotation.setAttributeValue( "hints", hints ); + + if ( jaxbNamedQuery.isCacheable() == Boolean.TRUE ) { + final MutableAnnotationUsage cacheableHint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + cacheableHint.setAttributeValue( "name", AvailableHints.HINT_CACHEABLE ); + cacheableHint.setAttributeValue( "value", Boolean.TRUE.toString() ); + + if ( jaxbNamedQuery.getCacheMode() != null ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_CACHE_MODE ); + hint.setAttributeValue( "value", jaxbNamedQuery.getCacheMode().name() ); + } + + if ( StringHelper.isNotEmpty( jaxbNamedQuery.getCacheRegion() ) ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_CACHE_REGION ); + hint.setAttributeValue( "value", jaxbNamedQuery.getCacheRegion() ); + } + } + + if ( jaxbNamedQuery.isReadOnly() == Boolean.TRUE ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_READ_ONLY ); + hint.setAttributeValue( "value", Boolean.TRUE.toString() ); + } + + if ( StringHelper.isNotEmpty( jaxbNamedQuery.getComment() ) ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", AvailableHints.HINT_COMMENT ); + hint.setAttributeValue( "value", jaxbNamedQuery.getComment() ); + } + } + } + + private void collectStoredProcedureQueries(List namedProcedureQueries) { + if ( isEmpty( namedProcedureQueries ) ) { + return; + } + + if ( namedStoredProcedureQueryRegistrations == null ) { + namedStoredProcedureQueryRegistrations = new HashMap<>(); + } + + for ( JaxbNamedStoredProcedureQueryImpl jaxbQuery : namedProcedureQueries ) { + final MutableAnnotationUsage queryAnnotation = makeAnnotation( JpaAnnotations.NAMED_STORED_PROCEDURE_QUERY ); + namedStoredProcedureQueryRegistrations.put( + jaxbQuery.getName(), + new NamedStoredProcedureQueryRegistration( jaxbQuery.getName(), queryAnnotation ) + ); + + queryAnnotation.setAttributeValue( "name", jaxbQuery.getName() ); + queryAnnotation.setAttributeValue( "procedureName", jaxbQuery.getProcedureName() ); + + final ArrayList resultClasses = arrayList( jaxbQuery.getResultClasses().size() ); + queryAnnotation.setAttributeValue( "resultClasses", resultClasses ); + for ( String resultClassName : jaxbQuery.getResultClasses() ) { + resultClasses.add( classDetailsRegistry.resolveClassDetails( resultClassName ) ); + } + + queryAnnotation.setAttributeValue( "resultSetMappings", jaxbQuery.getResultSetMappings() ); + + queryAnnotation.setAttributeValue( "hints", extractQueryHints( jaxbQuery ) ); + + final ArrayList> parameters = arrayList( jaxbQuery.getProcedureParameters().size() ); + queryAnnotation.setAttributeValue( "parameters", parameters ); + for ( JaxbStoredProcedureParameterImpl jaxbProcedureParameter : jaxbQuery.getProcedureParameters() ) { + final MutableAnnotationUsage parameterAnnotation = makeAnnotation( JpaAnnotations.STORED_PROCEDURE_PARAMETER ); + parameters.add( parameterAnnotation ); + + parameterAnnotation.setAttributeValue( "name", jaxbProcedureParameter.getName() ); + parameterAnnotation.setAttributeValue( "mode", jaxbProcedureParameter.getMode() ); + parameterAnnotation.setAttributeValue( "type", classDetailsRegistry.resolveClassDetails( jaxbProcedureParameter.getClazz() ) ); + } + } + } + + private List> extractQueryHints(JaxbNamedQueryBase jaxbQuery) { + final List> hints = new ArrayList<>(); + for ( JaxbQueryHint jaxbHint : jaxbQuery.getHints() ) { + final MutableAnnotationUsage hint = makeAnnotation( JpaAnnotations.QUERY_HINT ); + hint.setAttributeValue( "name", jaxbHint.getName() ); + hint.setAttributeValue( "value", jaxbHint.getValue() ); + } + return hints; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GenericGeneratorRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GenericGeneratorRegistration.java index 4f36c7c898..f4e765dcdc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GenericGeneratorRegistration.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GenericGeneratorRegistration.java @@ -12,25 +12,9 @@ import org.hibernate.models.spi.AnnotationUsage; /** * Global registration of a generic generator * + * @author Steve Ebersole * @see GenericGenerator * @see org.hibernate.boot.jaxb.mapping.spi.JaxbGenericIdGeneratorImpl - * - * @author Steve Ebersole */ -public class GenericGeneratorRegistration { - private final String name; - private final AnnotationUsage configuration; - - public GenericGeneratorRegistration(String name, AnnotationUsage configuration) { - this.name = name; - this.configuration = configuration; - } - - public String getName() { - return name; - } - - public AnnotationUsage getConfiguration() { - return configuration; - } +public record GenericGeneratorRegistration(String name, AnnotationUsage configuration) { } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GlobalRegistrations.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GlobalRegistrations.java index 3e1dba5b78..7a1ff2ed36 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GlobalRegistrations.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/GlobalRegistrations.java @@ -10,6 +10,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.hibernate.boot.models.categorize.spi.NamedQueryRegistration; + /** * Registrations which are considered global, collected across annotations @@ -46,6 +48,13 @@ public interface GlobalRegistrations { Set getJpaConverters(); + Map getSqlResultSetMappingRegistrations(); + + Map getNamedQueryRegistrations(); + + Map getNamedNativeQueryRegistrations(); + + Map getNamedStoredProcedureQueryRegistrations(); + // todo : named entity graphs - // todo : named queries } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/JpaEventListener.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/JpaEventListener.java index f627039992..cbae9bcf08 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/JpaEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/JpaEventListener.java @@ -10,7 +10,6 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListenerImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitDefaultsImpl; import org.hibernate.internal.util.MutableObject; import org.hibernate.models.ModelsException; -import org.hibernate.models.internal.jdk.VoidClassDetails; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.MethodDetails; @@ -282,13 +281,13 @@ public class JpaEventListener { if ( callbackType == JpaEventListenerStyle.CALLBACK ) { // should have no arguments. and technically (spec) have a void return return methodDetails.getArgumentTypes().isEmpty() - && methodDetails.getReturnType() == VoidClassDetails.VOID_CLASS_DETAILS; + && methodDetails.getReturnType() == ClassDetails.VOID_CLASS_DETAILS; } else { assert callbackType == JpaEventListenerStyle.LISTENER; // should have 1 argument. and technically (spec) have a void return return methodDetails.getArgumentTypes().size() == 1 - && methodDetails.getReturnType() == VoidClassDetails.VOID_CLASS_DETAILS; + && methodDetails.getReturnType() == ClassDetails.VOID_CLASS_DETAILS; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/ManagedResourcesProcessor.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/ManagedResourcesProcessor.java index e4985f11bf..308e46cf01 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/ManagedResourcesProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/ManagedResourcesProcessor.java @@ -12,10 +12,12 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.hibernate.annotations.TenantId; import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.models.categorize.ModelCategorizationLogging; import org.hibernate.boot.models.categorize.internal.ClassLoaderServiceLoading; import org.hibernate.boot.models.categorize.internal.DomainModelCategorizationCollector; +import org.hibernate.boot.models.categorize.internal.GlobalRegistrationsImpl; import org.hibernate.boot.models.categorize.internal.ModelCategorizationContextImpl; import org.hibernate.boot.models.categorize.internal.OrmAnnotationHelper; import org.hibernate.boot.models.xml.spi.XmlPreProcessingResult; @@ -123,10 +125,12 @@ public class ManagedResourcesProcessor { final boolean areIdGeneratorsGlobal = true; final ClassDetailsRegistry classDetailsRegistry = sourceModelBuildingContext.getClassDetailsRegistry(); final AnnotationDescriptorRegistry descriptorRegistry = sourceModelBuildingContext.getAnnotationDescriptorRegistry(); + final GlobalRegistrationsImpl globalRegistrations = new GlobalRegistrationsImpl( sourceModelBuildingContext ); final DomainModelCategorizationCollector modelCategorizationCollector = new DomainModelCategorizationCollector( areIdGeneratorsGlobal, classDetailsRegistry, descriptorRegistry, + globalRegistrations, jandexIndex ); @@ -166,7 +170,7 @@ public class ManagedResourcesProcessor { final ModelCategorizationContextImpl mappingBuildingContext = new ModelCategorizationContextImpl( classDetailsRegistryImmutable, annotationDescriptorRegistryImmutable, - modelCategorizationCollector.getGlobalRegistrations() + globalRegistrations ); final Set entityHierarchies; @@ -240,6 +244,8 @@ public class ManagedResourcesProcessor { public static void preFillRegistries(RegistryPrimer.Contributions contributions, SourceModelBuildingContext buildingContext) { OrmAnnotationHelper.forEachOrmAnnotation( contributions::registerAnnotation ); + buildingContext.getAnnotationDescriptorRegistry().getDescriptor( TenantId.class ); + final IndexView jandexIndex = buildingContext.getJandexIndex(); if ( jandexIndex == null ) { return; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedNativeQueryRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedNativeQueryRegistration.java new file mode 100644 index 0000000000..4116a68705 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedNativeQueryRegistration.java @@ -0,0 +1,48 @@ +/* + * 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.boot.models.categorize.spi; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; + +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.QueryHint; + +/** + * @author Steve Ebersole + */ +public record NamedNativeQueryRegistration(String name, AnnotationUsage configuration) { + public String getQueryString() { + return configuration.getString( "query" ); + } + + public ClassDetails getResultClass() { + return configuration.getClassDetails( "resultClass" ); + } + + public String getResultSetMapping() { + return configuration.getString( "resultSetMapping" ); + } + + public Map getQueryHints() { + final List> hints = configuration.getList( "hints" ); + if ( CollectionHelper.isEmpty( hints ) ) { + return Collections.emptyMap(); + } + + final Map result = CollectionHelper.linkedMapOfSize( hints.size() ); + for ( AnnotationUsage hint : hints ) { + result.put( hint.getString( "name" ), hint.getString( "value" ) ); + } + return result; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedQueryRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedQueryRegistration.java new file mode 100644 index 0000000000..975f8db502 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedQueryRegistration.java @@ -0,0 +1,44 @@ +/* + * 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.boot.models.categorize.spi; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.models.spi.AnnotationUsage; + +import jakarta.persistence.LockModeType; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.QueryHint; + +/** + * @author Steve Ebersole + */ +public record NamedQueryRegistration(String name, AnnotationUsage configuration) { + public String getQueryString() { + return configuration.getString( "query" ); + } + + public LockModeType getLockModeType() { + return configuration.getEnum( "lockMode" ); + } + + public Map getQueryHints() { + final List> hints = configuration.getList( "hints" ); + if ( CollectionHelper.isEmpty( hints ) ) { + return Collections.emptyMap(); + } + + final Map result = CollectionHelper.linkedMapOfSize( hints.size() ); + for ( AnnotationUsage hint : hints ) { + result.put( hint.getString( "name" ), hint.getString( "value" ) ); + } + return result; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedStoredProcedureQueryRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedStoredProcedureQueryRegistration.java new file mode 100644 index 0000000000..dc01951169 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/NamedStoredProcedureQueryRegistration.java @@ -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. + */ +package org.hibernate.boot.models.categorize.spi; + +import org.hibernate.models.spi.AnnotationUsage; + +import jakarta.persistence.NamedStoredProcedureQuery; + +/** + * @author Steve Ebersole + */ +public record NamedStoredProcedureQueryRegistration(String name, AnnotationUsage configuration) { +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SequenceGeneratorRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SequenceGeneratorRegistration.java index deb6dfb2a0..6f1e5bbc8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SequenceGeneratorRegistration.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SequenceGeneratorRegistration.java @@ -15,20 +15,5 @@ import jakarta.persistence.SequenceGenerator; * * @author Steve Ebersole */ -public class SequenceGeneratorRegistration { - private final String name; - private final AnnotationUsage configuration; - - public SequenceGeneratorRegistration(String name, AnnotationUsage configuration) { - this.name = name; - this.configuration = configuration; - } - - public String getName() { - return name; - } - - public AnnotationUsage getConfiguration() { - return configuration; - } +public record SequenceGeneratorRegistration(String name, AnnotationUsage configuration) { } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SingleAttributeKeyMapping.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SingleAttributeKeyMapping.java index 38fc5ead5a..33402e8c6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SingleAttributeKeyMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SingleAttributeKeyMapping.java @@ -19,7 +19,7 @@ public interface SingleAttributeKeyMapping extends KeyMapping { } default ClassDetails getKeyType() { - return getAttribute().getMember().getType(); + return getAttribute().getMember().getType().determineRawClass(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SqlResultSetMappingRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SqlResultSetMappingRegistration.java new file mode 100644 index 0000000000..2a3b53d720 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/SqlResultSetMappingRegistration.java @@ -0,0 +1,20 @@ +/* + * 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.boot.models.categorize.spi; + +import org.hibernate.models.spi.AnnotationUsage; + +import jakarta.persistence.SqlResultSetMapping; + +/** + * Registration of a SqlResultSetMapping while processing managed resources as part of + * building the domain metamodel + * + * @author Steve Ebersole + */ +public record SqlResultSetMappingRegistration(String name, AnnotationUsage configuration) { +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/TableGeneratorRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/TableGeneratorRegistration.java index 51d72cfdcb..fc6f0ae099 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/TableGeneratorRegistration.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/categorize/spi/TableGeneratorRegistration.java @@ -15,20 +15,5 @@ import jakarta.persistence.TableGenerator; * * @author Steve Ebersole */ -public class TableGeneratorRegistration { - private final String name; - private final AnnotationUsage configuration; - - public TableGeneratorRegistration(String name, AnnotationUsage configuration) { - this.name = name; - this.configuration = configuration; - } - - public String getName() { - return name; - } - - public AnnotationUsage getConfiguration() { - return configuration; - } +public record TableGeneratorRegistration(String name, AnnotationUsage configuration) { } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/AttributeProcessor.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/AttributeProcessor.java index a836510c20..1762d65695 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/AttributeProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/AttributeProcessor.java @@ -29,8 +29,8 @@ import org.hibernate.boot.models.xml.internal.attr.OneToManyAttributeProcessing; import org.hibernate.boot.models.xml.internal.attr.OneToOneAttributeProcessing; import org.hibernate.boot.models.xml.internal.attr.PluralAnyMappingAttributeProcessing; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java index bcdc963a3e..3f5a77d5a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java @@ -38,6 +38,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOneImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute; import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute; import org.hibernate.boot.jaxb.mapping.spi.JaxbTenantIdImpl; +import org.hibernate.boot.models.HibernateAnnotations; import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; import org.hibernate.boot.models.xml.internal.attr.BasicAttributeProcessing; import org.hibernate.boot.models.xml.internal.attr.BasicIdAttributeProcessing; @@ -48,17 +49,19 @@ import org.hibernate.boot.models.xml.spi.XmlProcessingResult; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.models.ModelsException; +import org.hibernate.models.internal.ClassTypeDetailsImpl; import org.hibernate.models.internal.ModelsClassLogging; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import org.hibernate.models.internal.dynamic.DynamicClassDetails; -import org.hibernate.models.internal.dynamic.MapModeFieldDetails; +import org.hibernate.models.internal.dynamic.DynamicFieldDetails; import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; import org.hibernate.models.spi.FieldDetails; import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.TypeDetails; import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies; import jakarta.persistence.Access; @@ -111,6 +114,7 @@ public class ManagedTypeProcessor { null, false, null, + null, xmlDocumentContext.getModelBuildingContext() ) ); @@ -157,10 +161,11 @@ public class ManagedTypeProcessor { if ( CollectionHelper.isNotEmpty( attributes.getIdAttributes() ) ) { // attributes.getIdAttributes().forEach( (jaxbId) -> { - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbId, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbId, xmlDocumentContext ); + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbId.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -170,10 +175,11 @@ public class ManagedTypeProcessor { else { // final JaxbEmbeddedIdImpl embeddedId = attributes.getEmbeddedIdAttribute(); - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( embeddedId, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( embeddedId, xmlDocumentContext ); + final DynamicFieldDetails member = new DynamicFieldDetails( embeddedId.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -183,13 +189,14 @@ public class ManagedTypeProcessor { // if ( attributes.getNaturalId() != null ) { attributes.getNaturalId().getBasicAttributes().forEach( (jaxbBasic) -> { - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbBasic, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbBasic.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -197,13 +204,14 @@ public class ManagedTypeProcessor { } ); attributes.getNaturalId().getEmbeddedAttributes().forEach( (jaxbEmbedded) -> { - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbEmbedded, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbEmbedded.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -211,10 +219,11 @@ public class ManagedTypeProcessor { } ); attributes.getNaturalId().getManyToOneAttributes().forEach( (jaxbManyToOne) -> { - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbManyToOne, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbManyToOne, xmlDocumentContext ); + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbManyToOne.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -222,10 +231,11 @@ public class ManagedTypeProcessor { } ); attributes.getNaturalId().getAnyMappingAttributes().forEach( (jaxbAnyMapping) -> { - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbAnyMapping, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbAnyMapping, xmlDocumentContext ); + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbAnyMapping.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -236,13 +246,14 @@ public class ManagedTypeProcessor { // final JaxbTenantIdImpl tenantId = jaxbDynamicEntity.getTenantId(); if ( tenantId != null ) { - final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( + final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( tenantId, xmlDocumentContext ); - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( tenantId.getName(), attributeJavaType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -252,9 +263,10 @@ public class ManagedTypeProcessor { final JaxbAttributesContainer attributes = jaxbManagedType.getAttributes(); attributes.getBasicAttributes().forEach( (jaxbBasic) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbBasic.getName(), determineDynamicAttributeJavaType( jaxbBasic, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -262,9 +274,10 @@ public class ManagedTypeProcessor { } ); attributes.getEmbeddedAttributes().forEach( (jaxbEmbedded) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbEmbedded.getName(), determineDynamicAttributeJavaType( jaxbEmbedded, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -272,9 +285,10 @@ public class ManagedTypeProcessor { } ); attributes.getOneToOneAttributes().forEach( (jaxbOneToOne) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbOneToOne.getName(), determineDynamicAttributeJavaType( jaxbOneToOne, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -282,9 +296,10 @@ public class ManagedTypeProcessor { } ); attributes.getManyToOneAttributes().forEach( (jaxbManyToOne) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbManyToOne.getName(), determineDynamicAttributeJavaType( jaxbManyToOne, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -292,9 +307,10 @@ public class ManagedTypeProcessor { } ); attributes.getAnyMappingAttributes().forEach( (jaxbAnyMapping) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbAnyMapping.getName(), determineDynamicAttributeJavaType( jaxbAnyMapping, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -302,9 +318,10 @@ public class ManagedTypeProcessor { } ); attributes.getElementCollectionAttributes().forEach( (jaxbElementCollection) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbElementCollection.getName(), determineDynamicAttributeJavaType( jaxbElementCollection, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -312,9 +329,10 @@ public class ManagedTypeProcessor { } ); attributes.getOneToManyAttributes().forEach( (jaxbOneToMany) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbOneToMany.getName(), determineDynamicAttributeJavaType( jaxbOneToMany, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -322,9 +340,10 @@ public class ManagedTypeProcessor { } ); attributes.getManyToManyAttributes().forEach( (jaxbManyToMany) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbManyToMany.getName(), determineDynamicAttributeJavaType( jaxbManyToMany, xmlDocumentContext ), + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -332,9 +351,14 @@ public class ManagedTypeProcessor { } ); attributes.getPluralAnyMappingAttributes().forEach( (jaxbPluralAnyMapping) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( + final TypeDetails attributeType = determineDynamicAttributeJavaType( + jaxbPluralAnyMapping, + xmlDocumentContext + ); + final DynamicFieldDetails member = new DynamicFieldDetails( jaxbPluralAnyMapping.getName(), - determineDynamicAttributeJavaType( jaxbPluralAnyMapping, xmlDocumentContext ), + attributeType, + classDetails, MEMBER_MODIFIERS, xmlDocumentContext.getModelBuildingContext() ); @@ -342,13 +366,14 @@ public class ManagedTypeProcessor { } ); } - private static ClassDetails determineDynamicAttributeJavaType( + private static TypeDetails determineDynamicAttributeJavaType( JaxbPersistentAttribute jaxbPersistentAttribute, XmlDocumentContext xmlDocumentContext) { final ClassDetailsRegistry classDetailsRegistry = xmlDocumentContext.getModelBuildingContext().getClassDetailsRegistry(); if ( jaxbPersistentAttribute instanceof JaxbIdImpl jaxbId ) { - return xmlDocumentContext.resolveJavaType( jaxbId.getTarget() ); + final MutableClassDetails classDetails = xmlDocumentContext.resolveJavaType( jaxbId.getTarget() ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); } if ( jaxbPersistentAttribute instanceof JaxbEmbeddedIdImpl jaxbEmbeddedId ) { @@ -356,14 +381,16 @@ public class ManagedTypeProcessor { if ( StringHelper.isEmpty( target ) ) { return null; } - return classDetailsRegistry.resolveClassDetails( + final ClassDetails classDetails = classDetailsRegistry.resolveClassDetails( target, (name) -> new DynamicClassDetails( target, xmlDocumentContext.getModelBuildingContext() ) ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); } if ( jaxbPersistentAttribute instanceof JaxbBasicImpl jaxbBasic ) { - return xmlDocumentContext.resolveJavaType( jaxbBasic.getTarget() ); + final MutableClassDetails classDetails = xmlDocumentContext.resolveJavaType( jaxbBasic.getTarget() ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); } if ( jaxbPersistentAttribute instanceof JaxbEmbeddedImpl jaxbEmbedded ) { @@ -371,10 +398,11 @@ public class ManagedTypeProcessor { if ( StringHelper.isEmpty( target ) ) { return null; } - return classDetailsRegistry.resolveClassDetails( + final ClassDetails classDetails = classDetailsRegistry.resolveClassDetails( target, (name) -> new DynamicClassDetails( target, xmlDocumentContext.getModelBuildingContext() ) ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); } if ( jaxbPersistentAttribute instanceof JaxbOneToOneImpl jaxbOneToOne ) { @@ -382,31 +410,39 @@ public class ManagedTypeProcessor { if ( StringHelper.isEmpty( target ) ) { return null; } - return classDetailsRegistry.resolveClassDetails( + final ClassDetails classDetails = classDetailsRegistry.resolveClassDetails( target, (name) -> new DynamicClassDetails( target, null, false, null, + null, xmlDocumentContext.getModelBuildingContext() ) ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); } if ( jaxbPersistentAttribute instanceof JaxbAnyMappingImpl ) { - return classDetailsRegistry.getClassDetails( Object.class.getName() ); + final ClassDetails classDetails = classDetailsRegistry.getClassDetails( Object.class.getName() ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); } if ( jaxbPersistentAttribute instanceof JaxbPluralAttribute jaxbPluralAttribute ) { final LimitedCollectionClassification classification = nullif( jaxbPluralAttribute.getClassification(), LimitedCollectionClassification.BAG ); - return switch ( classification ) { + final ClassDetails collectionClassDetails; + + collectionClassDetails = switch ( classification ) { case BAG -> classDetailsRegistry.resolveClassDetails( Collection.class.getName() ); case LIST -> classDetailsRegistry.resolveClassDetails( List.class.getName() ); case SET -> classDetailsRegistry.resolveClassDetails( Set.class.getName() ); case MAP -> classDetailsRegistry.resolveClassDetails( Map.class.getName() ); }; + + return new ClassTypeDetailsImpl( collectionClassDetails, TypeDetails.Kind.CLASS ); } + throw new UnsupportedOperationException( "Resolution of dynamic attribute Java type not yet implemented for " + jaxbPersistentAttribute ); } @@ -433,10 +469,9 @@ public class ManagedTypeProcessor { } if ( StringHelper.isNotEmpty( jaxbEntity.getExtends() ) ) { - final MutableAnnotationUsage extendsAnn = XmlProcessingHelper.makeAnnotation( - Extends.class, + final MutableAnnotationUsage extendsAnn = HibernateAnnotations.EXTENDS.createUsage( classDetails, - xmlDocumentContext + xmlDocumentContext.getModelBuildingContext() ); extendsAnn.setAttributeValue( "superType", jaxbEntity.getExtends() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java index 3e08261607..cf0b931a5a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java @@ -24,6 +24,7 @@ import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.CollectionType; import org.hibernate.annotations.DiscriminatorFormula; +import org.hibernate.annotations.DiscriminatorOptions; import org.hibernate.annotations.Filter; import org.hibernate.annotations.FilterJoinTable; import org.hibernate.annotations.JavaType; @@ -55,6 +56,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbConfigurationParameterImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbConvertImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbCustomSqlImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorColumnImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorFormulaImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedIdImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListenerImpl; @@ -85,6 +87,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbUuidGeneratorImpl; import org.hibernate.boot.jaxb.mapping.spi.db.JaxbCheckable; import org.hibernate.boot.jaxb.mapping.spi.db.JaxbColumnJoined; import org.hibernate.boot.jaxb.mapping.spi.db.JaxbTableMapping; +import org.hibernate.boot.models.HibernateAnnotations; import org.hibernate.boot.models.categorize.spi.JpaEventListener; import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; import org.hibernate.boot.models.xml.internal.db.ColumnProcessing; @@ -94,15 +97,15 @@ import org.hibernate.internal.util.KeyedConsumer; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.models.ModelsException; -import org.hibernate.models.internal.MutableAnnotationTarget; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.MutableAnnotationTarget; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.type.SqlTypes; @@ -1583,15 +1586,27 @@ public class XmlAnnotationHelper { } public static void applyDiscriminatorFormula( - String discriminatorFormula, + JaxbDiscriminatorFormulaImpl jaxbDiscriminatorFormula, MutableClassDetails target, XmlDocumentContext xmlDocumentContext) { - if ( StringHelper.isNotEmpty( discriminatorFormula ) ) { - final MutableAnnotationUsage discriminatorFormulaAnn = XmlProcessingHelper - .getOrMakeAnnotation( DiscriminatorFormula.class, target, xmlDocumentContext ); - discriminatorFormulaAnn.setAttributeValue( "value", discriminatorFormula ); + if ( jaxbDiscriminatorFormula == null || StringHelper.isEmpty( jaxbDiscriminatorFormula.getFragment() ) ) { + return; + } - // todo add to mapping-3.2.0.xsd discriminatorType of @DiscriminatorFormula + final MutableAnnotationUsage discriminatorFormulaAnn = HibernateAnnotations.DISCRIMINATOR_FORMULA.createUsage( + target, + xmlDocumentContext.getModelBuildingContext() + ); + + discriminatorFormulaAnn.setAttributeValue( "value", jaxbDiscriminatorFormula.getFragment() ); + discriminatorFormulaAnn.setAttributeValue( "discriminatorType", jaxbDiscriminatorFormula.getDiscriminatorType() ); + + if ( jaxbDiscriminatorFormula.isForceSelection() ) { + final MutableAnnotationUsage existingOptionsAnnotation = (MutableAnnotationUsage) target.getAnnotationUsage( DiscriminatorOptions.class ); + final MutableAnnotationUsage optionsAnnotation = existingOptionsAnnotation != null + ? existingOptionsAnnotation + : HibernateAnnotations.DISCRIMINATOR_OPTIONS.createUsage( target, xmlDocumentContext.getModelBuildingContext() ); + optionsAnnotation.setAttributeValue( "force", true ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlProcessingHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlProcessingHelper.java index 56aba91732..9f042377ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlProcessingHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlProcessingHelper.java @@ -14,14 +14,14 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbManagedType; import org.hibernate.boot.models.MemberResolutionException; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationTarget; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.internal.dynamic.DynamicAnnotationUsage; import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.FieldDetails; import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.MutableAnnotationTarget; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/AnyMappingAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/AnyMappingAttributeProcessing.java index 84c5dbf761..468ec740cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/AnyMappingAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/AnyMappingAttributeProcessing.java @@ -13,22 +13,22 @@ import org.hibernate.annotations.Any; import org.hibernate.annotations.AnyDiscriminator; import org.hibernate.annotations.AnyDiscriminatorValue; import org.hibernate.annotations.AnyDiscriminatorValues; +import org.hibernate.boot.internal.AnyKeyType; import org.hibernate.boot.jaxb.mapping.spi.JaxbAnyDiscriminatorValueMappingImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMappingDiscriminatorImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMappingImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMappingKeyImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbColumnImpl; -import org.hibernate.boot.internal.AnyKeyType; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.internal.db.ColumnProcessing; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.Column; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicAttributeProcessing.java index 807ff4c6a0..752ae01024 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicAttributeProcessing.java @@ -13,9 +13,9 @@ import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.internal.db.ColumnProcessing; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.Basic; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicIdAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicIdAttributeProcessing.java index 7e92d06b40..5915fa7e97 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicIdAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/BasicIdAttributeProcessing.java @@ -10,9 +10,9 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbIdImpl; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.AccessType; import jakarta.persistence.Basic; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonAttributeProcessing.java index 6ce445054c..0a727e7a2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonAttributeProcessing.java @@ -20,9 +20,9 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbSingularFetchModeImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbStandardAttribute; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.Access; import jakarta.persistence.AccessType; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java index e790e2dc0e..c75068f552 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java @@ -20,14 +20,14 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbOrderColumnImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; -import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; +import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableMemberDetails; import org.hibernate.models.spi.SourceModelBuildingContext; import jakarta.persistence.MapKey; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java index abf2e19986..e6ce746b2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java @@ -13,16 +13,15 @@ import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.CollectionTable; import jakarta.persistence.ElementCollection; -import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.applyOr; import static org.hibernate.internal.util.NullnessHelper.coalesce; /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java index fa0bf54a2e..17f2e108f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java @@ -12,9 +12,9 @@ import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.AccessType; import jakarta.persistence.Embedded; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java index 6550350a16..5d1be397af 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java @@ -10,9 +10,9 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedIdImpl; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; +import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.AccessType; import jakarta.persistence.EmbeddedId; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToManyAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToManyAttributeProcessing.java index ab2016826c..6fc3c4f129 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToManyAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToManyAttributeProcessing.java @@ -7,19 +7,17 @@ package org.hibernate.boot.models.xml.internal.attr; import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToManyImpl; -import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToManyImpl; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.AccessType; import jakarta.persistence.ManyToMany; -import jakarta.persistence.OneToMany; import static org.hibernate.boot.models.xml.internal.XmlProcessingHelper.getOrMakeAnnotation; import static org.hibernate.internal.util.NullnessHelper.coalesce; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java index 38cc24077d..c57d31e3da 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java @@ -20,10 +20,10 @@ import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.ManyToOne; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToManyAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToManyAttributeProcessing.java index 9e5abdb00c..964ad0eddd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToManyAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToManyAttributeProcessing.java @@ -7,16 +7,17 @@ package org.hibernate.boot.models.xml.internal.attr; import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.OnDelete; import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToManyImpl; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.OneToMany; @@ -76,7 +77,9 @@ public class OneToManyAttributeProcessing { } if ( jaxbOneToMany.getNotFound() != null ) { - XmlProcessingHelper.getOrMakeAnnotation( NotFound.class, memberDetails, xmlDocumentContext ).setAttributeValue( "action", jaxbOneToMany.getNotFound() ); + if ( jaxbOneToMany.getNotFound() != NotFoundAction.EXCEPTION ) { + XmlProcessingHelper.getOrMakeAnnotation( NotFound.class, memberDetails, xmlDocumentContext ).setAttributeValue( "action", jaxbOneToMany.getNotFound() ); + } } return memberDetails; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java index 149fda7426..8d4815f3cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java @@ -12,10 +12,10 @@ import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationUsage; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.OneToOne; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/PluralAnyMappingAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/PluralAnyMappingAttributeProcessing.java index e4f6a12140..5b8ba604a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/PluralAnyMappingAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/PluralAnyMappingAttributeProcessing.java @@ -8,8 +8,8 @@ package org.hibernate.boot.models.xml.internal.attr; import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAnyMappingImpl; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; -import org.hibernate.models.internal.MutableClassDetails; -import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/ColumnProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/ColumnProcessing.java index 91b6802e04..2122dcd22f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/ColumnProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/ColumnProcessing.java @@ -18,11 +18,11 @@ import org.hibernate.boot.jaxb.mapping.spi.db.JaxbColumnSizable; import org.hibernate.boot.jaxb.mapping.spi.db.JaxbColumnStandard; import org.hibernate.boot.jaxb.mapping.spi.db.JaxbColumnUniqueable; import org.hibernate.boot.jaxb.mapping.spi.db.JaxbCommentable; -import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; +import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; -import org.hibernate.models.internal.MutableAnnotationTarget; -import org.hibernate.models.internal.MutableAnnotationUsage; +import org.hibernate.models.spi.MutableAnnotationTarget; +import org.hibernate.models.spi.MutableAnnotationUsage; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/spi/XmlDocumentContext.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/spi/XmlDocumentContext.java index cb3578095e..56fe56d7ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/spi/XmlDocumentContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/spi/XmlDocumentContext.java @@ -7,7 +7,7 @@ package org.hibernate.boot.models.xml.spi; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; -import org.hibernate.models.internal.MutableClassDetails; +import org.hibernate.models.spi.MutableClassDetails; import org.hibernate.models.spi.SourceModelBuildingContext; /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java index e17a113942..6922732550 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java @@ -22,6 +22,8 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.query.internal.FetchMementoBasicStandard; import org.hibernate.query.internal.FetchMementoEntityStandard; import org.hibernate.query.internal.ModelPartResultMementoBasicImpl; @@ -47,6 +49,7 @@ import jakarta.persistence.FieldResult; import jakarta.persistence.SqlResultSetMapping; import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; +import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize; import static org.hibernate.metamodel.mapping.EntityIdentifierMapping.ID_ROLE_NAME; /** @@ -68,28 +71,24 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr // (`org.hibernate.query.results.ResultBuilder`) as part of the // memento for its resolution - public static SqlResultSetMappingDescriptor from(SqlResultSetMapping mappingAnnotation, String name) { - final EntityResult[] entityResults = mappingAnnotation.entities(); - final ConstructorResult[] constructorResults = mappingAnnotation.classes(); - final ColumnResult[] columnResults = mappingAnnotation.columns(); + public static SqlResultSetMappingDescriptor from(AnnotationUsage mappingAnnotation, String name) { + final List> entityResults = mappingAnnotation.getList( "entities" ); + final List> constructorResults = mappingAnnotation.getList( "classes" ); + final List> columnResults = mappingAnnotation.getList( "columns" ); final List resultDescriptors = arrayList( - entityResults.length + columnResults.length + columnResults.length + entityResults.size() + columnResults.size() + columnResults.size() ); - for ( final EntityResult entityResult : entityResults ) { - resultDescriptors.add( - new EntityResultDescriptor( entityResult ) - ); + for ( final AnnotationUsage entityResult : entityResults ) { + resultDescriptors.add( new EntityResultDescriptor( entityResult ) ); } - for ( final ConstructorResult constructorResult : constructorResults ) { - resultDescriptors.add( - new ConstructorResultDescriptor( constructorResult, mappingAnnotation ) - ); + for ( final AnnotationUsage constructorResult : constructorResults ) { + resultDescriptors.add( new ConstructorResultDescriptor( constructorResult, mappingAnnotation ) ); } - for ( final ColumnResult columnResult : columnResults ) { + for ( final AnnotationUsage columnResult : columnResults ) { resultDescriptors.add( new JpaColumnResultDescriptor( columnResult, mappingAnnotation ) ); @@ -98,8 +97,8 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr return new SqlResultSetMappingDescriptor( name, resultDescriptors ); } - public static SqlResultSetMappingDescriptor from(SqlResultSetMapping mappingAnnotation) { - return from( mappingAnnotation, mappingAnnotation.name() ); + public static SqlResultSetMappingDescriptor from(AnnotationUsage mappingAnnotation) { + return from( mappingAnnotation, mappingAnnotation.getString( "name" ) ); } private final String mappingName; @@ -131,19 +130,21 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr * @see jakarta.persistence.ColumnResult */ private static class JpaColumnResultDescriptor implements ResultDescriptor { - private final ColumnResult columnResult; + private final AnnotationUsage columnResult; private final String mappingName; - public JpaColumnResultDescriptor(ColumnResult columnResult, SqlResultSetMapping mappingAnnotation) { + public JpaColumnResultDescriptor( + AnnotationUsage columnResult, + AnnotationUsage mappingAnnotation) { this.columnResult = columnResult; - this.mappingName = mappingAnnotation.name(); + this.mappingName = mappingAnnotation.getString( "name" ); } @Override public ResultMemento resolve(ResultSetMappingResolutionContext resolutionContext) { BootQueryLogging.BOOT_QUERY_LOGGER.debugf( "Generating ScalarResultMappingMemento for JPA ColumnResult(%s) for ResultSet mapping `%s`", - columnResult.name(), + columnResult.getString( "name" ), mappingName ); @@ -172,23 +173,32 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr private final Class targetJavaType; private final List argumentResultDescriptors; - public ConstructorResultDescriptor(ConstructorResult constructorResult, SqlResultSetMapping mappingAnnotation) { - this.mappingName = mappingAnnotation.name(); - this.targetJavaType = constructorResult.targetClass(); + public ConstructorResultDescriptor( + AnnotationUsage constructorResult, + AnnotationUsage mappingAnnotation) { + this.mappingName = mappingAnnotation.getString( "name" ); + this.targetJavaType = constructorResult.getClassDetails( "targetClass" ).toJavaClass(); - final ColumnResult[] columnResults = constructorResult.columns(); - if ( columnResults.length == 0 ) { + argumentResultDescriptors = interpretArguments( constructorResult, mappingAnnotation ); + } + + private static List interpretArguments( + AnnotationUsage constructorResult, + AnnotationUsage mappingAnnotation) { + final List> columnResults = constructorResult.getList( "columns" ); + if ( columnResults.isEmpty() ) { throw new IllegalArgumentException( "ConstructorResult did not define any ColumnResults" ); } - this.argumentResultDescriptors = arrayList( columnResults.length ); - for ( final ColumnResult columnResult : columnResults ) { + final List argumentResultDescriptors = arrayList( columnResults.size() ); + for ( AnnotationUsage columnResult : columnResults ) { final JpaColumnResultDescriptor argumentResultDescriptor = new JpaColumnResultDescriptor( columnResult, mappingAnnotation ); argumentResultDescriptors.add(new ArgumentDescriptor(argumentResultDescriptor)); } + return argumentResultDescriptors; } @Override @@ -224,26 +234,38 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr private final Map explicitFetchMappings; - public EntityResultDescriptor(EntityResult entityResult) { - this.entityName = entityResult.entityClass().getName(); - this.discriminatorColumn = entityResult.discriminatorColumn(); - + public EntityResultDescriptor(AnnotationUsage entityResult) { + final ClassDetails classDetails = entityResult.getClassDetails( "entityClass" ); + this.entityName = classDetails.getName(); this.navigablePath = new NavigablePath( entityName ); - this.explicitFetchMappings = new HashMap<>(); - for ( int i = 0; i < entityResult.fields().length; i++ ) { - final FieldResult fieldResult = entityResult.fields()[ i ]; - final AttributeFetchDescriptor existing = explicitFetchMappings.get( fieldResult.name() ); + this.discriminatorColumn = entityResult.getString( "discriminatorColumn" ); + + this.explicitFetchMappings = extractFetchMappings( navigablePath, entityResult ); + } + + private static Map extractFetchMappings( + NavigablePath navigablePath, + AnnotationUsage entityResult) { + final List> fields = entityResult.getList( "fields" ); + final Map explicitFetchMappings = mapOfSize( fields.size() ); + + for ( int i = 0; i < fields.size(); i++ ) { + final AnnotationUsage fieldResult = fields.get( i ); + final String fieldName = fieldResult.getString("name" ); + final AttributeFetchDescriptor existing = explicitFetchMappings.get( fieldName ); if ( existing != null ) { existing.addColumn( fieldResult ); } else { explicitFetchMappings.put( - fieldResult.name(), - AttributeFetchDescriptor.from( navigablePath, entityName, fieldResult ) + fieldName, + AttributeFetchDescriptor.from( navigablePath, navigablePath.getFullPath(), fieldResult ) ); } } + + return explicitFetchMappings; } @Override @@ -304,6 +326,18 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr ); } + private static AttributeFetchDescriptor from( + NavigablePath entityPath, + String entityName, + AnnotationUsage fieldResult) { + return new AttributeFetchDescriptor( + entityPath, + entityName, + fieldResult.getString( "name" ), + fieldResult.getString( "column" ) + ); + } + private final NavigablePath navigablePath; private final String entityName; @@ -340,6 +374,25 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr columnNames.add( fieldResult.column() ); } + private void addColumn(AnnotationUsage fieldResult) { + final String name = fieldResult.getString( "name" ); + final String column = fieldResult.getString( "column" ); + + if ( ! propertyPath.equals( name ) ) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Passed FieldResult [%s, %s] does not match AttributeFetchMapping [%s]", + name, + column, + propertyPath + ) + ); + } + + columnNames.add( column ); + } + @Override public ResultMemento asResultMemento(NavigablePath path, ResultSetMappingResolutionContext resolutionContext) { final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java index aad235322c..ee685a2459 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java @@ -13,6 +13,7 @@ import org.hibernate.TimeZoneStorageStrategy; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.boot.model.relational.ColumnOrderingStrategy; +import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cfg.MetadataSourceType; @@ -167,6 +168,20 @@ public abstract class AbstractDelegatingMetadataBuildingOptions implements Metad } } + @Override + public void apply(PersistenceUnitMetadata persistenceUnitMetadata) { + if ( delegate instanceof JpaOrmXmlPersistenceUnitDefaultAware ) { + ( (JpaOrmXmlPersistenceUnitDefaultAware) delegate ).apply( persistenceUnitMetadata ); + } + else { + throw new HibernateException( + "AbstractDelegatingMetadataBuildingOptions delegate did not " + + "implement JpaOrmXmlPersistenceUnitDefaultAware; " + + "cannot delegate JpaOrmXmlPersistenceUnitDefaultAware#apply" + ); + } + } + @Override public String getSchemaCharset() { return delegate.getSchemaCharset(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java index 8f0d81569f..74ac9a295b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java @@ -31,6 +31,8 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext; +import org.hibernate.boot.models.categorize.spi.GlobalRegistrations; +import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.boot.query.NamedHqlQueryDefinition; import org.hibernate.boot.query.NamedNativeQueryDefinition; import org.hibernate.boot.query.NamedProcedureCallDefinition; @@ -46,6 +48,11 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.spi.EmbeddableInstantiator; +import org.hibernate.models.spi.AnnotationDescriptorRegistry; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.usertype.CompositeUserType; @@ -64,6 +71,19 @@ import jakarta.persistence.AttributeConverter; public interface InFlightMetadataCollector extends MetadataImplementor { BootstrapContext getBootstrapContext(); + SourceModelBuildingContext getSourceModelBuildingContext(); + + default ClassDetailsRegistry getClassDetailsRegistry() { + return getSourceModelBuildingContext().getClassDetailsRegistry(); + } + + default AnnotationDescriptorRegistry getAnnotationDescriptorRegistry() { + return getSourceModelBuildingContext().getAnnotationDescriptorRegistry(); + } + + GlobalRegistrations getGlobalRegistrations(); + PersistenceUnitMetadata getPersistenceUnitMetadata(); + /** * Add the {@link PersistentClass} for an entity mapping. * @@ -84,9 +104,9 @@ public interface InFlightMetadataCollector extends MetadataImplementor { void registerGenericComponent(Component component); - void registerEmbeddableSubclass(XClass superclass, XClass subclass); + void registerEmbeddableSubclass(ClassDetails superclass, ClassDetails subclass); - List getEmbeddableSubclasses(XClass superclass); + List getEmbeddableSubclasses(ClassDetails superclass); /** * Adds an import (for use in HQL). @@ -310,15 +330,18 @@ public interface InFlightMetadataCollector extends MetadataImplementor { AnnotatedClassType addClassType(XClass clazz); AnnotatedClassType getClassType(XClass clazz); + AnnotatedClassType addClassType(ClassDetails classDetails); + AnnotatedClassType getClassType(ClassDetails classDetails); + void addMappedSuperclass(Class type, MappedSuperclass mappedSuperclass); MappedSuperclass getMappedSuperclass(Class type); - PropertyData getPropertyAnnotatedWithMapsId(XClass persistentXClass, String propertyName); - void addPropertyAnnotatedWithMapsId(XClass entity, PropertyData propertyAnnotatedElement); - void addPropertyAnnotatedWithMapsIdSpecj(XClass entity, PropertyData specJPropertyData, String s); + PropertyData getPropertyAnnotatedWithMapsId(ClassDetails persistentClassDetails, String propertyName); + void addPropertyAnnotatedWithMapsId(ClassDetails entityClassDetails, PropertyData propertyAnnotatedElement); + void addPropertyAnnotatedWithMapsIdSpecj(ClassDetails entityClassDetails, PropertyData specJPropertyData, String s); - void addToOneAndIdProperty(XClass entity, PropertyData propertyAnnotatedElement); - PropertyData getPropertyAnnotatedWithIdAndToOne(XClass persistentXClass, String propertyName); + void addToOneAndIdProperty(ClassDetails entityClassDetails, PropertyData propertyAnnotatedElement); + PropertyData getPropertyAnnotatedWithIdAndToOne(ClassDetails persistentClassDetails, String propertyName); boolean isInSecondPass(); @@ -339,7 +362,7 @@ public interface InFlightMetadataCollector extends MetadataImplementor { void registerUserType(Class embeddableType, Class> userType); Class> findRegisteredUserType(Class basicType); - void addCollectionTypeRegistration(CollectionTypeRegistration registrationAnnotation); + void addCollectionTypeRegistration(AnnotationUsage registrationAnnotation); void addCollectionTypeRegistration(CollectionClassification classification, CollectionTypeRegistrationDescriptor descriptor); CollectionTypeRegistrationDescriptor findCollectionTypeRegistration(CollectionClassification classification); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/JpaOrmXmlPersistenceUnitDefaultAware.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/JpaOrmXmlPersistenceUnitDefaultAware.java index 7b51cf517a..c47d022afe 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/JpaOrmXmlPersistenceUnitDefaultAware.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/JpaOrmXmlPersistenceUnitDefaultAware.java @@ -6,6 +6,8 @@ */ package org.hibernate.boot.spi; +import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; + /** * Contract for things that need to be aware of JPA {@code orm.xml}-defined persistence-unit-defaults. * Only {@link MetadataBuildingOptions} are supported to implement this contract. @@ -30,4 +32,6 @@ public interface JpaOrmXmlPersistenceUnitDefaultAware { * @param jpaOrmXmlPersistenceUnitDefaults The {@code persistence-unit-defaults} values */ void apply(JpaOrmXmlPersistenceUnitDefaults jpaOrmXmlPersistenceUnitDefaults); + + void apply(PersistenceUnitMetadata persistenceUnitMetadata); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/PropertyData.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/PropertyData.java index 7476a15001..2a89f1cd85 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/PropertyData.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/PropertyData.java @@ -7,8 +7,9 @@ package org.hibernate.boot.spi; import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.TypeDetails; /** * Details about an attribute as we process the {@linkplain org.hibernate.mapping boot model}. @@ -30,17 +31,17 @@ public interface PropertyData { /** * Returns the returned class itself or the element type if an array */ - XClass getClassOrElement() throws MappingException; + TypeDetails getClassOrElementType() throws MappingException; /** * Returns the returned class itself or the element type if an array or collection */ - XClass getClassOrPluralElement() throws MappingException; + ClassDetails getClassOrPluralElement() throws MappingException; /** * Return the class itself */ - XClass getPropertyClass() throws MappingException; + TypeDetails getPropertyType() throws MappingException; /** * Returns the returned class name itself or the element type if an array @@ -55,12 +56,12 @@ public interface PropertyData { /** * Return the Hibernate mapping property */ - XProperty getProperty(); + MemberDetails getAttributeMember(); /** * Return the Class the property is declared on * If the property is declared on a @MappedSuperclass, * this class will be different than the PersistentClass's class */ - XClass getDeclaringClass(); + ClassDetails getDeclaringClass(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java index 7ebf52fd31..b05bbf06a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java @@ -30,7 +30,7 @@ public class MappingXsdSupport { ); public static final XsdDescriptor _320 = LocalXsdResolver.buildXsdDescriptor( - "org/hibernate/xsd/mapping/mapping-3.2.0.xsd", + "org/hibernate/xsd/mapping/mapping-7.0.xsd", "3.2", "http://www.hibernate.org/xsd/orm/mapping" ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 1eb4ef2f1f..b86df4cb93 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -6,6 +6,8 @@ */ package org.hibernate.internal.log; +import java.lang.annotation.Annotation; + import org.hibernate.boot.jaxb.SourceType; import org.hibernate.cfg.AvailableSettings; @@ -16,6 +18,8 @@ import org.jboss.logging.annotations.Message; import org.jboss.logging.annotations.MessageLogger; import org.jboss.logging.annotations.ValidIdRange; +import jakarta.persistence.Temporal; + import static org.jboss.logging.Logger.Level.WARN; /** @@ -297,4 +301,10 @@ public interface DeprecationLogger extends BasicLogger { ) void deprecatedArrayContainsWithArray(); + @LogMessage(level = WARN) + @Message( + id = 90000033, + value = "Encountered use of deprecated annotation [%s] at %s." + ) + void deprecatedAnnotation(Class annotationType, String locationDescription); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java index 7e4fb8e9e9..2fd2ec716c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java @@ -6,6 +6,7 @@ */ package org.hibernate.internal.util.collections; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -245,6 +246,14 @@ public final class CollectionHelper { return new ArrayList<>( Math.max( expectedNumberOfElements + 1, DEFAULT_LIST_CAPACITY ) ); } + public static ArrayList populatedArrayList(int expectedNumberOfElements, T value) { + final ArrayList list = new ArrayList<>( Math.max( expectedNumberOfElements + 1, DEFAULT_LIST_CAPACITY ) ); + for ( int i = 0; i < expectedNumberOfElements; i++ ) { + list.add( value ); + } + return list; + } + public static Set makeCopy(Set source) { if ( source == null ) { return null; @@ -298,6 +307,13 @@ public final class CollectionHelper { return set; } + public static Set setOf(Collection values) { + if ( isEmpty( values ) ) { + return Collections.emptySet(); + } + return new HashSet<>( values ); + } + public static Properties asProperties(Map map) { if ( map instanceof Properties ) { return ( (Properties) map ); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java index f22adb3890..61c6d47d03 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java @@ -6,18 +6,11 @@ */ package org.hibernate.jpa.event.internal; -import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import jakarta.persistence.Entity; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.ExcludeDefaultListeners; -import jakarta.persistence.ExcludeSuperclassListeners; -import jakarta.persistence.MappedSuperclass; -import jakarta.persistence.PersistenceException; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; @@ -26,10 +19,20 @@ import org.hibernate.internal.util.ReflectHelper; import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.mapping.Property; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MethodDetails; import org.hibernate.property.access.spi.Getter; import org.jboss.logging.Logger; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.ExcludeDefaultListeners; +import jakarta.persistence.ExcludeSuperclassListeners; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PersistenceException; + /** * Resolves JPA callback definitions using a HCANN ReflectionManager. *

@@ -40,66 +43,70 @@ import org.jboss.logging.Logger; public final class CallbackDefinitionResolverLegacyImpl { private static final Logger log = Logger.getLogger( CallbackDefinitionResolverLegacyImpl.class ); - public static List resolveEntityCallbacks(ReflectionManager reflectionManager, - XClass entityClass, CallbackType callbackType) { + public static List resolveEntityCallbacks( + ReflectionManager reflectionManager, + ClassDetails entityClass, + CallbackType callbackType) { List callbackDefinitions = new ArrayList<>(); List callbacksMethodNames = new ArrayList<>(); List> orderedListeners = new ArrayList<>(); - XClass currentClazz = entityClass; + ClassDetails currentClazz = entityClass; boolean stopListeners = false; boolean stopDefaultListeners = false; do { CallbackDefinition callbackDefinition = null; - List methods = currentClazz.getDeclaredMethods(); - for ( final XMethod xMethod : methods ) { - if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) { - Method method = reflectionManager.toMethod( xMethod ); - final String methodName = method.getName(); - if ( !callbacksMethodNames.contains( methodName ) ) { - //overridden method, remove the superclass overridden method - if ( callbackDefinition == null ) { - callbackDefinition = new EntityCallback.Definition( method, callbackType ); - Class returnType = method.getReturnType(); - Class[] args = method.getParameterTypes(); - if ( returnType != Void.TYPE || args.length != 0 ) { - throw new RuntimeException( - "Callback methods annotated on the bean class must return void and take no arguments: " - + callbackType.getCallbackAnnotation().getName() + " - " + xMethod - ); - } - ReflectHelper.ensureAccessibility( method ); - if ( log.isDebugEnabled() ) { - log.debugf( - "Adding %s as %s callback for entity %s", - methodName, - callbackType.getCallbackAnnotation().getSimpleName(), - entityClass.getName() - ); - } - callbackDefinitions.add( 0, callbackDefinition ); //superclass first - callbacksMethodNames.add( 0, methodName ); - } - else { - throw new PersistenceException( - "You can only annotate one callback method with " - + callbackType.getCallbackAnnotation().getName() + " in bean class: " + entityClass.getName() - ); - } + final List methodsDetailsList = currentClazz.getMethods(); + for ( MethodDetails methodDetails : methodsDetailsList ) { + if ( !methodDetails.hasAnnotationUsage( callbackType.getCallbackAnnotation() ) ) { + continue; + } + if ( callbacksMethodNames.contains( methodDetails.getName() ) ) { + continue; + } + + //overridden method, remove the superclass overridden method + if ( callbackDefinition == null ) { + final Method javaMethod = (Method) methodDetails.toJavaMember(); + callbackDefinition = new EntityCallback.Definition( javaMethod, callbackType ); + Class returnType = javaMethod.getReturnType(); + Class[] args = javaMethod.getParameterTypes(); + if ( returnType != Void.TYPE || args.length != 0 ) { + throw new RuntimeException( + "Callback methods annotated on the bean class must return void and take no arguments: " + + callbackType.getCallbackAnnotation().getName() + " - " + methodDetails + ); } + ReflectHelper.ensureAccessibility( javaMethod ); + if ( log.isDebugEnabled() ) { + log.debugf( + "Adding %s as %s callback for entity %s", + methodDetails.getName(), + callbackType.getCallbackAnnotation().getSimpleName(), + entityClass.getName() + ); + } + callbackDefinitions.add( 0, callbackDefinition ); //superclass first + callbacksMethodNames.add( 0, methodDetails.getName() ); + } + else { + throw new PersistenceException( + "You can only annotate one callback method with " + + callbackType.getCallbackAnnotation().getName() + " in bean class: " + entityClass.getName() + ); } } if ( !stopListeners ) { - getListeners( currentClazz, orderedListeners ); - stopListeners = currentClazz.isAnnotationPresent( ExcludeSuperclassListeners.class ); - stopDefaultListeners = currentClazz.isAnnotationPresent( ExcludeDefaultListeners.class ); + applyListeners( currentClazz, orderedListeners ); + stopListeners = currentClazz.hasAnnotationUsage( ExcludeSuperclassListeners.class ); + stopDefaultListeners = currentClazz.hasAnnotationUsage( ExcludeDefaultListeners.class ); } do { - currentClazz = currentClazz.getSuperclass(); + currentClazz = currentClazz.getSuperClass(); } while ( currentClazz != null - && !( currentClazz.isAnnotationPresent( Entity.class ) - || currentClazz.isAnnotationPresent( MappedSuperclass.class ) ) + && !( currentClazz.hasAnnotationUsage( Entity.class ) + || currentClazz.hasAnnotationUsage( MappedSuperclass.class ) ) ); } while ( currentClazz != null ); @@ -246,25 +253,22 @@ public final class CallbackDefinitionResolverLegacyImpl { } } - private static void getListeners(XClass currentClazz, List> orderedListeners) { - EntityListeners entityListeners = currentClazz.getAnnotation( EntityListeners.class ); + private static void applyListeners(ClassDetails currentClazz, List> listOfListeners) { + final AnnotationUsage entityListeners = currentClazz.getAnnotationUsage( EntityListeners.class ); if ( entityListeners != null ) { - Class[] classes = entityListeners.value(); - int size = classes.length; - for ( int index = size - 1; index >= 0; index-- ) { - orderedListeners.add( classes[index] ); + final List listeners = entityListeners.getList( "value" ); + for ( ClassDetails listener : listeners ) { + listOfListeners.add( listener.toJavaClass() ); } } + if ( useAnnotationAnnotatedByListener ) { - Annotation[] annotations = currentClazz.getAnnotations(); - for ( Annotation annot : annotations ) { - entityListeners = annot.getClass().getAnnotation( EntityListeners.class ); - if ( entityListeners != null ) { - Class[] classes = entityListeners.value(); - int size = classes.length; - for ( int index = size - 1; index >= 0; index-- ) { - orderedListeners.add( classes[index] ); - } + final List> metaAnnotatedUsageList = currentClazz.getMetaAnnotated( EntityListeners.class ); + for ( AnnotationUsage metaAnnotatedUsage : metaAnnotatedUsageList ) { + final AnnotationUsage metaAnnotatedListeners = metaAnnotatedUsage.getAnnotationDescriptor().getAnnotationUsage( EntityListeners.class ); + final List listeners = metaAnnotatedListeners.getList( "value" ); + for ( ClassDetails listener : listeners ) { + listOfListeners.add( listener.toJavaClass() ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java index 4d9b7494a2..559bc0482b 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java @@ -12,6 +12,7 @@ import java.lang.reflect.Method; import org.hibernate.jpa.event.spi.Callback; import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.models.spi.MethodDetails; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; /** @@ -31,6 +32,11 @@ public class EntityCallback extends AbstractCallback { this.callbackType = callbackType; } + public Definition(MethodDetails callbackMethod, CallbackType callbackType) { + this.callbackMethod = (Method) callbackMethod.toJavaMember(); + this.callbackType = callbackType; + } + @Override public Callback createCallback(ManagedBeanRegistry beanRegistry) { return new EntityCallback( callbackMethod, callbackType ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java index dfc6dadca9..31c1f90540 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java @@ -28,7 +28,6 @@ import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.FilterConfiguration; import org.hibernate.internal.util.StringHelper; import org.hibernate.jdbc.Expectation; -import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.CollectionType; @@ -84,8 +83,6 @@ public abstract class Collection implements Fetchable, Value, Filterable, SoftDe private CollectionType cachedCollectionType; private CollectionSemantics cachedCollectionSemantics; - private Class collectionPersisterClass; - private final List filters = new ArrayList<>(); private final List manyToManyFilters = new ArrayList<>(); private final java.util.Set synchronizedTables = new HashSet<>(); @@ -162,7 +159,6 @@ public abstract class Collection implements Fetchable, Value, Filterable, SoftDe this.typeName = original.typeName; this.typeParameters = original.typeParameters == null ? null : new Properties(original.typeParameters); this.customTypeBeanResolver = original.customTypeBeanResolver; - this.collectionPersisterClass = original.collectionPersisterClass; this.filters.addAll( original.filters ); this.manyToManyFilters.addAll( original.manyToManyFilters ); this.synchronizedTables.addAll( original.synchronizedTables ); @@ -375,14 +371,6 @@ public abstract class Collection implements Fetchable, Value, Filterable, SoftDe this.fetchMode = fetchMode; } - public void setCollectionPersisterClass(Class persister) { - this.collectionPersisterClass = persister; - } - - public Class getCollectionPersisterClass() { - return collectionPersisterClass; - } - public void validate(Mapping mapping) throws MappingException { assert getKey() != null : "Collection key not bound : " + getRole(); assert getElement() != null : "Collection element not bound : " + getRole(); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index ecd326d860..7fbcbbbf31 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -46,6 +46,7 @@ import org.hibernate.metamodel.mapping.EmbeddableDiscriminatorConverter; import org.hibernate.metamodel.mapping.internal.DiscriminatorTypeImpl; import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.persister.entity.DiscriminatorHelper; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.property.access.spi.Setter; import org.hibernate.generator.Generator; import org.hibernate.generator.BeforeExecutionGenerator; @@ -176,7 +177,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable return properties; } - public void addProperty(Property p, XClass declaringClass) { + public void addProperty(Property p, ClassDetails declaringClass) { properties.add( p ); if ( isPolymorphic() && declaringClass != null ) { if ( propertyDeclaringClasses == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index e3faa1fcad..82484365fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -419,10 +419,6 @@ public abstract class PersistentClass implements IdentifiableTypeClass, Attribut public abstract boolean hasEmbeddedIdentifier(); - public abstract Class getEntityPersisterClass(); - - public abstract void setEntityPersisterClass(Class classPersisterClass); - public abstract Table getRootTable(); public abstract RootClass getRootClass(); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java index 31505e46ae..d5c9a7bbc4 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/RootClass.java @@ -17,7 +17,6 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.persister.entity.EntityPersister; import static org.hibernate.internal.util.StringHelper.nullIfEmpty; @@ -49,7 +48,6 @@ public class RootClass extends PersistentClass implements TableOwner, SoftDeleta private boolean mutable = true; private boolean embeddedIdentifier; private boolean explicitPolymorphism; - private Class entityPersisterClass; private boolean forceDiscriminator; private boolean concreteProxy; private String where; @@ -194,21 +192,11 @@ public class RootClass extends PersistentClass implements TableOwner, SoftDeleta return embeddedIdentifier; } - @Override - public Class getEntityPersisterClass() { - return entityPersisterClass; - } - @Override public Table getRootTable() { return getTable(); } - @Override - public void setEntityPersisterClass(Class persister) { - this.entityPersisterClass = persister; - } - @Override public PersistentClass getSuperclass() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index e2ca14baf5..837b28d939 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -10,6 +10,7 @@ import java.io.Serializable; import java.lang.annotation.Annotation; import java.sql.Types; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -25,8 +26,6 @@ import org.hibernate.MappingException; import org.hibernate.Remove; import org.hibernate.TimeZoneStorageStrategy; import org.hibernate.annotations.OnDeleteAction; -import org.hibernate.annotations.common.reflection.XProperty; -import org.hibernate.annotations.common.reflection.java.JavaXMember; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext; @@ -39,18 +38,21 @@ import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.Mapping; +import org.hibernate.generator.Generator; +import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentityGenerator; import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.type.descriptor.converter.spi.JpaAttributeConverter; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.MemberDetails; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.service.ServiceRegistry; -import org.hibernate.generator.Generator; import org.hibernate.type.Type; import org.hibernate.type.descriptor.JdbcTypeNameMapper; +import org.hibernate.type.descriptor.converter.spi.JpaAttributeConverter; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; @@ -922,11 +924,9 @@ public abstract class SimpleValue implements KeyValue { } } - final XProperty xProperty = (XProperty) typeParameters.get( DynamicParameterizedType.XPROPERTY ); + final MemberDetails attributeMember = (MemberDetails) typeParameters.get( DynamicParameterizedType.XPROPERTY ); // todo : not sure this works for handling @MapKeyEnumerated - final Annotation[] annotations = xProperty == null - ? new Annotation[0] - : xProperty.getAnnotations(); + final Annotation[] annotations = getAnnotations( attributeMember ); final ClassLoaderService classLoaderService = getMetadata() .getMetadataBuildingOptions() @@ -954,6 +954,22 @@ public abstract class SimpleValue implements KeyValue { } } + private static Annotation[] getAnnotations(MemberDetails memberDetails) { + final Annotation[] annotations; + final Collection> allAnnotationUsages = memberDetails.getAllAnnotationUsages(); + if ( allAnnotationUsages == null ) { + annotations = new Annotation[0]; + } + else { + annotations = new Annotation[allAnnotationUsages.size()]; + int index = 0; + for ( AnnotationUsage annotationUsage : allAnnotationUsages ) { + annotations[ index++ ] = annotationUsage.toAnnotation(); + } + } + return annotations; + } + public DynamicParameterizedType.ParameterType makeParameterImpl() { try { final String[] columnNames = new String[ columns.size() ]; @@ -968,11 +984,9 @@ public abstract class SimpleValue implements KeyValue { } } - final XProperty xProperty = (XProperty) typeParameters.get( DynamicParameterizedType.XPROPERTY ); + final MemberDetails attributeMember = (MemberDetails) typeParameters.get( DynamicParameterizedType.XPROPERTY ); // todo : not sure this works for handling @MapKeyEnumerated - final Annotation[] annotations = xProperty == null - ? new Annotation[0] - : xProperty.getAnnotations(); + final Annotation[] annotations = getAnnotations( attributeMember ); final ClassLoaderService classLoaderService = getMetadata() .getMetadataBuildingOptions() diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java b/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java index 4649c09e10..95eb25d120 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Subclass.java @@ -181,13 +181,6 @@ public class Subclass extends PersistentClass { return getSuperclass().hasEmbeddedIdentifier(); } - @Override - public Class getEntityPersisterClass() { - return classPersisterClass == null - ? getSuperclass().getEntityPersisterClass() - : classPersisterClass; - } - @Override public Table getRootTable() { return getSuperclass().getRootTable(); @@ -228,11 +221,6 @@ public class Subclass extends PersistentClass { } } - @Override - public void setEntityPersisterClass(Class classPersisterClass) { - this.classPersisterClass = classPersisterClass; - } - @Override public int getJoinClosureSpan() { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java index 6f5cb86c85..b602573a00 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/internal/PersisterFactoryImpl.java @@ -8,6 +8,7 @@ package org.hibernate.persister.internal; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Locale; import org.hibernate.HibernateException; import org.hibernate.MappingException; @@ -67,15 +68,8 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi EntityDataAccess entityCacheAccessStrategy, NaturalIdDataAccess naturalIdCacheAccessStrategy, RuntimeModelCreationContext creationContext) { - // If the metadata for the entity specified an explicit persister class, use it... - Class persisterClass = entityBinding.getEntityPersisterClass(); - if ( persisterClass == null ) { - // Otherwise, use the persister class indicated by the PersisterClassResolver service - persisterClass = persisterClassResolver.getEntityPersisterClass( entityBinding ); - } - return createEntityPersister( - persisterClass, + persisterClassResolver.getEntityPersisterClass( entityBinding ), entityBinding, entityCacheAccessStrategy, naturalIdCacheAccessStrategy, @@ -102,11 +96,27 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi throw (HibernateException) target; } else { - throw new MappingException( "Could not instantiate persister " + persisterClass.getName(), target ); + throw new MappingException( + String.format( + Locale.ROOT, + "Could not instantiate persister %s (%s)", + persisterClass.getName(), + entityBinding.getEntityName() + ), + target + ); } } catch (Exception e) { - throw new MappingException( "Could not instantiate persister " + persisterClass.getName(), e ); + throw new MappingException( + String.format( + Locale.ROOT, + "Could not instantiate persister %s (%s)", + persisterClass.getName(), + entityBinding.getEntityName() + ), + e + ); } } @@ -147,14 +157,12 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi Collection collectionBinding, @Nullable CollectionDataAccess cacheAccessStrategy, RuntimeModelCreationContext creationContext) { - // If the metadata for the collection specified an explicit persister class, use it - Class persisterClass = collectionBinding.getCollectionPersisterClass(); - if ( persisterClass == null ) { - // Otherwise, use the persister class indicated by the PersisterClassResolver service - persisterClass = persisterClassResolver.getCollectionPersisterClass( collectionBinding ); - } - - return createCollectionPersister( persisterClass, collectionBinding, cacheAccessStrategy, creationContext ); + return createCollectionPersister( + persisterClassResolver.getCollectionPersisterClass( collectionBinding ), + collectionBinding, + cacheAccessStrategy, + creationContext + ); } private CollectionPersister createCollectionPersister( diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java index fb165f7480..fb4d7b126b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java @@ -12,6 +12,8 @@ import java.util.function.Consumer; import org.hibernate.boot.model.convert.internal.ConverterHelper; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.models.spi.AnnotationUsage; +import org.hibernate.models.spi.ClassDetails; import org.hibernate.query.named.ResultMementoBasic; import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.complete.CompleteResultBuilderBasicValuedConverted; @@ -69,14 +71,15 @@ public class ResultMementoBasicStandard implements ResultMementoBasic { * Creation for JPA descriptor */ public ResultMementoBasicStandard( - ColumnResult definition, + AnnotationUsage definition, ResultSetMappingResolutionContext context) { - this.explicitColumnName = definition.name(); + this.explicitColumnName = definition.getString( "name" ); final SessionFactoryImplementor sessionFactory = context.getSessionFactory(); final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration(); - final Class definedType = definition.type(); + final ClassDetails definedTypeDetails = definition.getClassDetails( "type" ); + final Class definedType = definedTypeDetails.toJavaClass(); if ( void.class == definedType ) { builder = new CompleteResultBuilderBasicValuedStandard( explicitColumnName, null, null ); @@ -106,14 +109,14 @@ public class ResultMementoBasicStandard implements ResultMementoBasic { final JavaType explicitJavaType; // see if this is a registered BasicType... - final BasicType registeredBasicType = typeConfiguration.getBasicTypeRegistry().getRegisteredType( definition.type().getName() ); + final BasicType registeredBasicType = typeConfiguration.getBasicTypeRegistry().getRegisteredType( definedTypeDetails.getName() ); if ( registeredBasicType != null ) { explicitType = registeredBasicType; explicitJavaType = registeredBasicType.getJavaTypeDescriptor(); } else { final JavaTypeRegistry jtdRegistry = typeConfiguration.getJavaTypeRegistry(); - final JavaType registeredJtd = jtdRegistry.getDescriptor( definition.type() ); + final JavaType registeredJtd = jtdRegistry.getDescriptor( definedType ); final ManagedBeanRegistry beanRegistry = sessionFactory.getServiceRegistry().requireService( ManagedBeanRegistry.class ); if ( BasicType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) { @@ -131,7 +134,7 @@ public class ResultMementoBasicStandard implements ResultMementoBasic { } else { explicitType = null; - explicitJavaType = jtdRegistry.getDescriptor( definition.type() ); + explicitJavaType = jtdRegistry.getDescriptor( definedType ); } } diff --git a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-3.2.0.xsd b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-7.0.xsd similarity index 99% rename from hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-3.2.0.xsd rename to hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-7.0.xsd index 6e04dc536a..346d9d569a 100644 --- a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-3.2.0.xsd +++ b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-7.0.xsd @@ -351,7 +351,7 @@ - + + + + + + @interface DiscriminatorFormula { + /** The fragment */ + String value(); + DiscriminatorType discriminatorType() default STRING; + } + + @interface DiscriminatorOptions { + boolean force() default false; + ... + } + + + + + + + diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index db0734e4d9..4805227b45 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -6,7 +6,7 @@ extensionBindingPrefixes="inheritance" version="3.0"> - + @@ -580,13 +580,20 @@ org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbQueryHint + + + org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQueryBase + org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQueryBase @@ -596,6 +603,7 @@ + org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQueryBase @@ -605,6 +613,9 @@ + + + diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/persister/PersisterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/persister/PersisterTest.java deleted file mode 100644 index 54cdd5c376..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/persister/PersisterTest.java +++ /dev/null @@ -1,53 +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 . - */ -package org.hibernate.orm.test.annotations.persister; - -import org.hibernate.mapping.Collection; -import org.hibernate.mapping.PersistentClass; -import org.hibernate.persister.entity.SingleTableEntityPersister; - -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * @author Shawn Clowater - */ -public class PersisterTest extends BaseNonConfigCoreFunctionalTestCase { - @Test - public void testEntityEntityPersisterAndPersisterSpecified() { - //checks to see that the persister specified with the @Persister annotation takes precedence if a @Entity.persister() is also specified - PersistentClass persistentClass = metadata().getEntityBinding( Deck.class.getName() ); - assertEquals( "Incorrect Persister class for " + persistentClass.getMappedClass(), EntityPersister.class, - persistentClass.getEntityPersisterClass() ); - } - - @Test - public void testEntityEntityPersisterSpecified() { - //tests the persister specified with an @Entity.persister() - PersistentClass persistentClass = metadata().getEntityBinding( Card.class.getName() ); - assertEquals( "Incorrect Persister class for " + persistentClass.getMappedClass(), - SingleTableEntityPersister.class, persistentClass.getEntityPersisterClass() ); - } - - @Test - public void testCollectionPersisterSpecified() { - //tests the persister specified by the @Persister annotation on a collection - Collection collection = metadata().getCollectionBinding( Deck.class.getName() + ".cards" ); - assertEquals( "Incorrect Persister class for collection " + collection.getRole(), CollectionPersister.class, - collection.getCollectionPersisterClass() ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[]{ - Card.class, - Deck.class - }; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/BindingTestingHelper.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/BindingTestingHelper.java index f55137b0f2..ea729ec6a5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/BindingTestingHelper.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/bind/BindingTestingHelper.java @@ -19,12 +19,15 @@ import org.hibernate.boot.models.bind.internal.BindingContextImpl; import org.hibernate.boot.models.bind.internal.BindingOptionsImpl; import org.hibernate.boot.models.bind.internal.BindingStateImpl; import org.hibernate.boot.models.bind.spi.BindingCoordinator; +import org.hibernate.boot.models.categorize.internal.ClassLoaderServiceLoading; import org.hibernate.boot.models.categorize.spi.CategorizedDomainModel; import org.hibernate.boot.models.categorize.spi.EntityHierarchy; import org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.model.source.internal.annotations.AdditionalManagedResourcesImpl; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.models.internal.SourceModelBuildingContextImpl; /** * @author Steve Ebersole diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/XmlProcessingSmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/XmlProcessingSmokeTests.java index b3162561ac..b323e5af47 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/XmlProcessingSmokeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/XmlProcessingSmokeTests.java @@ -128,6 +128,7 @@ public class XmlProcessingSmokeTests { false, buildingContext.getClassDetailsRegistry(), buildingContext.getAnnotationDescriptorRegistry(), + new GlobalRegistrationsImpl( buildingContext ), null ); collectedXmlResources.getDocuments().forEach( collector::apply ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/dynamic/DynamicModelTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/dynamic/DynamicModelTests.java index 383a49cc8d..096a153fa6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/dynamic/DynamicModelTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/dynamic/DynamicModelTests.java @@ -74,14 +74,14 @@ public class DynamicModelTests { assertThat( rootEntity.getClassDetails().getName() ).isEqualTo( "SimpleEntity" ); final FieldDetails idField = rootEntity.getClassDetails().findFieldByName( "id" ); - assertThat( idField.getType().getClassName() ).isEqualTo( Integer.class.getName() ); + assertThat( idField.getType().determineRawClass().getClassName() ).isEqualTo( Integer.class.getName() ); final FieldDetails nameField = rootEntity.getClassDetails().findFieldByName( "name" ); - assertThat( nameField.getType().getClassName() ).isEqualTo( Object.class.getName() ); + assertThat( nameField.getType().determineRawClass().getClassName() ).isEqualTo( Object.class.getName() ); assertThat( nameField.getAnnotationUsage( JavaType.class ) ).isNotNull(); final FieldDetails qtyField = rootEntity.getClassDetails().findFieldByName( "quantity" ); - assertThat( qtyField.getType().getClassName() ).isEqualTo( int.class.getName() ); + assertThat( qtyField.getType().determineRawClass().getClassName() ).isEqualTo( int.class.getName() ); } } @@ -107,18 +107,18 @@ public class DynamicModelTests { assertThat( rootEntity.getClassDetails().getName() ).isEqualTo( "Contact" ); final FieldDetails idField = rootEntity.getClassDetails().findFieldByName( "id" ); - assertThat( idField.getType().getClassName() ).isEqualTo( Integer.class.getName() ); + assertThat( idField.getType().determineRawClass().getClassName() ).isEqualTo( Integer.class.getName() ); final FieldDetails nameField = rootEntity.getClassDetails().findFieldByName( "name" ); - assertThat( nameField.getType().getClassName() ).isNull(); + assertThat( nameField.getType().determineRawClass().getClassName() ).isNull(); assertThat( nameField.getType().getName() ).isEqualTo( "Name" ); assertThat( nameField.getAnnotationUsage( Target.class ) ).isNotNull(); assertThat( nameField.getAnnotationUsage( Target.class ).getString( "value" ) ).isEqualTo( "Name" ); - assertThat( nameField.getType().getFields() ).hasSize( 2 ); + assertThat( nameField.getType().determineRawClass().getFields() ).hasSize( 2 ); final FieldDetails labels = rootEntity.getClassDetails().findFieldByName( "labels" ); - assertThat( labels.getType().getClassName() ).isEqualTo( Set.class.getName() ); + assertThat( labels.getType().determineRawClass().getClassName() ).isEqualTo( Set.class.getName() ); final AnnotationUsage elementCollection = labels.getAnnotationUsage( ElementCollection.class ); assertThat( elementCollection.getAttributeValue( "targetClass" ).getName() ).isEqualTo( String.class.getName() ); final AnnotationUsage collectionClassification = labels.getAnnotationUsage( CollectionClassification.class ); @@ -179,7 +179,7 @@ public class DynamicModelTests { assertThat( rootEntity.getClassDetails().getName() ).isEqualTo( Employee.class.getName() ); final FieldDetails oneToMany = rootEntity.getClassDetails().findFieldByName( "oneToMany" ); - assertThat( oneToMany.getType().getClassName() ).isEqualTo( List.class.getName() ); + assertThat( oneToMany.getType().determineRawClass().getClassName() ).isEqualTo( List.class.getName() ); final AnnotationUsage oneToManyAnn = oneToMany.getAnnotationUsage( OneToMany.class ); assertThat( oneToManyAnn.getAttributeValue( "fetch" ) ).isEqualTo( FetchType.EAGER ); assertThat( oneToMany.getAnnotationUsage( NotFound.class ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/globals/JpaEventListenerTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/globals/JpaEventListenerTests.java index 54ed6c1015..9636d237f7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/globals/JpaEventListenerTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/globals/JpaEventListenerTests.java @@ -16,13 +16,13 @@ import org.hibernate.boot.models.categorize.spi.JpaEventListener; import org.hibernate.boot.model.source.internal.annotations.AdditionalManagedResourcesImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.models.internal.jdk.VoidClassDetails; import org.hibernate.models.spi.MethodDetails; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor.processManagedResources; +import static org.hibernate.models.spi.ClassDetails.VOID_CLASS_DETAILS; /** * @author Steve Ebersole @@ -50,7 +50,7 @@ public class JpaEventListenerTests { final JpaEventListener registration = registrations.get( 0 ); final MethodDetails postPersistMethod = registration.getPostPersistMethod(); assertThat( postPersistMethod ).isNotNull(); - assertThat( postPersistMethod.getReturnType() ).isEqualTo( VoidClassDetails.VOID_CLASS_DETAILS ); + assertThat( postPersistMethod.getReturnType() ).isEqualTo( VOID_CLASS_DETAILS ); assertThat( postPersistMethod.getArgumentTypes() ).hasSize( 1 ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/write/staticinsert/SimpleNullabilityTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/write/staticinsert/SimpleNullabilityTest.java new file mode 100644 index 0000000000..6817185180 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/write/staticinsert/SimpleNullabilityTest.java @@ -0,0 +1,47 @@ +/* + * 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.orm.test.write.staticinsert; + +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.SecondaryTable; +import jakarta.persistence.Table; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +public class SimpleNullabilityTest { + @Test + @DomainModel(annotatedClasses = Tester.class) + void checkIt(DomainModelScope scope) { + final PersistentClass entityBinding = scope.getEntityBinding( Tester.class ); + final Property descriptionProperty = entityBinding.getProperty( "description" ); + assertThat( descriptionProperty.isOptional() ).isTrue(); + assertThat( descriptionProperty.getColumns().get( 0 ).isNullable() ).isTrue(); + } + + @Entity(name="Tester") + @Table(name="Tester") + @SecondaryTable(name="Tester2") + public static class Tester { + @Id + private Integer id; + private String name; + @Column(table = "Tester2") + private String description; + } +} diff --git a/settings.gradle b/settings.gradle index 57364e5030..28b616c97d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -70,7 +70,7 @@ dependencyResolutionManagement { def byteBuddyVersion = version "byteBuddy", "1.14.18" def classmateVersion = version "classmate", "1.5.1" def geolatteVersion = version "geolatte", "1.9.1" - def hibernateModelsVersion = version "hibernateModels", "0.5.6" + def hibernateModelsVersion = version "hibernateModels", "0.6.10" def jandexVersion = version "jandex", "3.2.0" def hcannVersion = version "hcann", "7.0.1.Final" def jacksonVersion = version "jackson", "2.17.0"