HHH-17504 - Ongoing JPA 32 work
HHH-17350 - Work on hibernate-models, XSD and JAXB HHH-16114 - Improve boot metamodel binding HHH-15996 - Develop an abstraction for Annotation in annotation processing HHH-16012 - Develop an abstraction for domain model Class refs HHH-15997 - Support for dynamic models in orm.xml HHH-15698 - Support for entity-name in mapping.xsd
This commit is contained in:
parent
540b87e78a
commit
e5d9586ba3
|
@ -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']
|
||||
}
|
||||
|
|
|
@ -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<TableGenerator> 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<AnnotationUsage<UniqueConstraint>> uniqueConstraints = tableGeneratorAnnotation.getList( "uniqueConstraints" );
|
||||
if ( CollectionHelper.isNotEmpty( uniqueConstraints ) ) {
|
||||
LOG.ignoringTableGeneratorConstraints( tableGeneratorAnnotation.getString( "name" ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void interpretSequenceGenerator(
|
||||
SequenceGenerator sequenceGeneratorAnnotation,
|
||||
AnnotationUsage<SequenceGenerator> 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" ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String,PersistentClass> entityBindingMap = new HashMap<>();
|
||||
private final List<Component> composites = new ArrayList<>();
|
||||
private final Map<Class<?>, Component> genericComponentsMap = new HashMap<>();
|
||||
private final Map<XClass, List<XClass>> embeddableSubtypes = new HashMap<>();
|
||||
private final Map<ClassDetails, List<ClassDetails>> embeddableSubtypes = new HashMap<>();
|
||||
private final Map<Class<?>, DiscriminatorType<?>> embeddableDiscriminatorTypesMap = new HashMap<>();
|
||||
private final Map<String,Collection> collectionBindingMap = new HashMap<>();
|
||||
|
||||
|
@ -168,20 +184,28 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
|||
private final Set<String> defaultSqlResultSetMappingNames = new HashSet<>();
|
||||
private final Set<String> defaultNamedProcedureNames = new HashSet<>();
|
||||
private Map<Class<?>, MappedSuperclass> mappedSuperClasses;
|
||||
private Map<XClass, Map<String, PropertyData>> propertiesAnnotatedWithMapsId;
|
||||
private Map<XClass, Map<String, PropertyData>> propertiesAnnotatedWithIdAndToOne;
|
||||
private Map<ClassDetails, Map<String, PropertyData>> propertiesAnnotatedWithMapsId;
|
||||
private Map<ClassDetails, Map<String, PropertyData>> propertiesAnnotatedWithIdAndToOne;
|
||||
private Map<String, String> mappedByResolver;
|
||||
private Map<String, String> propertyRefResolver;
|
||||
private Set<DelayedPropertyReferenceHandler> delayedPropertyReferenceHandlers;
|
||||
private List<Function<MetadataBuildingContext, Boolean>> 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<String, SqmFunctionDescriptor> 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<XClass> getEmbeddableSubclasses(XClass superclass) {
|
||||
final List<XClass> subclasses = embeddableSubtypes.get( superclass );
|
||||
public List<ClassDetails> getEmbeddableSubclasses(ClassDetails superclass) {
|
||||
final List<ClassDetails> subclasses = embeddableSubtypes.get( superclass );
|
||||
return subclasses != null ? subclasses : List.of();
|
||||
}
|
||||
|
||||
|
@ -490,9 +549,9 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
|||
private Map<CollectionClassification, CollectionTypeRegistrationDescriptor> collectionTypeRegistrations;
|
||||
|
||||
@Override
|
||||
public void addCollectionTypeRegistration(CollectionTypeRegistration registrationAnnotation) {
|
||||
public void addCollectionTypeRegistration(AnnotationUsage<CollectionTypeRegistration> 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<String,String> 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<CollectionTypeRegistration> registrationAnnotation) {
|
||||
return new CollectionTypeRegistrationDescriptor(
|
||||
registrationAnnotation.getClassDetails( "type" ).toJavaClass(),
|
||||
extractParameters( registrationAnnotation.getList( "parameters" ) )
|
||||
);
|
||||
}
|
||||
|
||||
private Map<String,String> extractParameters(List<AnnotationUsage<Parameter>> annotationUsages) {
|
||||
if ( CollectionHelper.isEmpty( annotationUsages ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String,String> result = mapOfSize( annotationUsages.size() );
|
||||
for ( AnnotationUsage<Parameter> 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<String, PropertyData> 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<String, PropertyData> 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<String, PropertyData> map = propertiesAnnotatedWithMapsId.get( entityType );
|
||||
if ( map == null ) {
|
||||
map = new HashMap<>();
|
||||
propertiesAnnotatedWithMapsId.put( entityType, map );
|
||||
}
|
||||
final Map<String, PropertyData> 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<String, PropertyData> map = propertiesAnnotatedWithIdAndToOne.get( entityType );
|
||||
if ( map == null ) {
|
||||
map = new HashMap<>();
|
||||
propertiesAnnotatedWithIdAndToOne.put( entityType, map );
|
||||
}
|
||||
final Map<String, PropertyData> map = propertiesAnnotatedWithIdAndToOne.computeIfAbsent(
|
||||
entityType,
|
||||
k -> new HashMap<>()
|
||||
);
|
||||
map.put( property.getPropertyName(), property );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<String, Object> 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<NamedStoredProcedureQuery> 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<NamedStoredProcedureQuery> annotation) {
|
||||
final List<ClassDetails> 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<NamedStoredProcedureQuery> annotation) {
|
||||
final List<String> 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<AnnotationUsage<StoredProcedureParameter>> parameters) {
|
||||
if ( CollectionHelper.isEmpty( parameters ) ) {
|
||||
parameterStrategy = ParameterStrategy.POSITIONAL;
|
||||
parameterDefinitions = new ParameterDefinition[0];
|
||||
}
|
||||
else {
|
||||
parameterStrategy = StringHelper.isNotEmpty( parameters[0].name() )
|
||||
final AnnotationUsage<StoredProcedureParameter> 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<T> type;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ParameterDefinition(int position, StoredProcedureParameter annotation) {
|
||||
ParameterDefinition(int position, AnnotationUsage<StoredProcedureParameter> annotation) {
|
||||
this.position = position;
|
||||
this.name = normalize( annotation.name() );
|
||||
this.parameterMode = annotation.mode();
|
||||
this.type = (Class<T>) annotation.type();
|
||||
this.name = normalize( annotation.getString( "name" ) );
|
||||
this.parameterMode = annotation.getEnum( "mode" );
|
||||
this.type = annotation.getClassDetails( "type" ).toJavaClass();
|
||||
}
|
||||
|
||||
public ParameterMemento toMemento(SessionFactoryImplementor sessionFactory) {
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<? extends JaxbQueryHint> getHints();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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<? extends Annotation> annotationType() {
|
||||
return TableGenerator.class;
|
||||
}
|
||||
},
|
||||
builder
|
||||
);
|
||||
|
||||
final MutableAnnotationUsage<TableGenerator> 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<? extends Annotation> annotationType() {
|
||||
return SequenceGenerator.class;
|
||||
}
|
||||
},
|
||||
builder
|
||||
final MutableAnnotationUsage<SequenceGenerator> sequenceGeneratorUsage = JpaAnnotations.SEQUENCE_GENERATOR.createUsage(
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
sequenceGeneratorUsage.setAttributeValue( "name", name );
|
||||
GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretSequenceGenerator( sequenceGeneratorUsage, builder );
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ConverterDescriptor> RENDERER = value -> value.getAttributeConverterClass().getName();
|
||||
|
||||
private ConverterDescriptor locateMatchingConverter(
|
||||
XProperty xProperty,
|
||||
MemberDetails memberDetails,
|
||||
ConversionSite conversionSite,
|
||||
Function<AutoApplicableConverterDescriptor, ConverterDescriptor> 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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() ) ) {
|
||||
|
|
|
@ -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<? extends Member> resolveMember(XProperty xProperty, MetadataBuildingContext buildingContext) {
|
||||
public static ResolvedMember<? extends Member> 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<ResolvedType> resolveConverterClassParamTypes(
|
||||
Class<? extends AttributeConverter<?, ?>> converterClass,
|
||||
ClassmateContext context) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<String, Column[]> holderColumnOverride;
|
||||
private Map<String, Column[]> currentPropertyColumnOverride;
|
||||
private Map<String, ColumnTransformer> holderColumnTransformerOverride;
|
||||
private Map<String, ColumnTransformer> currentPropertyColumnTransformerOverride;
|
||||
private Map<String, JoinColumn[]> holderJoinColumnOverride;
|
||||
private Map<String, JoinColumn[]> currentPropertyJoinColumnOverride;
|
||||
private Map<String, JoinTable> holderJoinTableOverride;
|
||||
private Map<String, JoinTable> currentPropertyJoinTableOverride;
|
||||
private Map<String, ForeignKey> holderForeignKeyOverride;
|
||||
private Map<String, ForeignKey> currentPropertyForeignKeyOverride;
|
||||
private final String path;
|
||||
protected final AbstractPropertyHolder parent;
|
||||
private final MetadataBuildingContext context;
|
||||
|
||||
private Boolean isInIdClass;
|
||||
|
||||
private Map<String, List<AnnotationUsage<Column>>> holderColumnOverride;
|
||||
private Map<String, List<AnnotationUsage<Column>>> currentPropertyColumnOverride;
|
||||
private Map<String, AnnotationUsage<ColumnTransformer>> holderColumnTransformerOverride;
|
||||
private Map<String, AnnotationUsage<ColumnTransformer>> currentPropertyColumnTransformerOverride;
|
||||
private Map<String, List<AnnotationUsage<JoinColumn>>> holderJoinColumnOverride;
|
||||
private Map<String, List<AnnotationUsage<JoinColumn>>> currentPropertyJoinColumnOverride;
|
||||
private Map<String, AnnotationUsage<JoinTable>> holderJoinTableOverride;
|
||||
private Map<String, AnnotationUsage<JoinTable>> currentPropertyJoinTableOverride;
|
||||
private Map<String, AnnotationUsage<ForeignKey>> holderForeignKeyOverride;
|
||||
private Map<String, AnnotationUsage<ForeignKey>> 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<AnnotationUsage<Column>> getOverriddenColumn(String propertyName) {
|
||||
final List<AnnotationUsage<Column>> 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<ColumnTransformer> getOverriddenColumnTransformer(String logicalColumnName) {
|
||||
AnnotationUsage<ColumnTransformer> 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<AnnotationUsage<Column>> getExactOverriddenColumn(String propertyName) {
|
||||
List<AnnotationUsage<Column>> 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<AnnotationUsage<JoinColumn>> getOverriddenJoinColumn(String propertyName) {
|
||||
final List<AnnotationUsage<JoinColumn>> 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<AnnotationUsage<JoinColumn>> getExactOverriddenJoinColumn(String propertyName) {
|
||||
List<AnnotationUsage<JoinColumn>> 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<ForeignKey> getOverriddenForeignKey(String propertyName) {
|
||||
final AnnotationUsage<ForeignKey> 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<ForeignKey> getExactOverriddenForeignKey(String propertyName) {
|
||||
AnnotationUsage<ForeignKey> 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
|
||||
*
|
||||
* <p>
|
||||
* 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<JoinTable> getJoinTable(MemberDetails attributeMember) {
|
||||
final String propertyName = qualify( getPath(), attributeMember.getName() );
|
||||
final AnnotationUsage<JoinTable> 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<JoinTable> getOverriddenJoinTable(String propertyName) {
|
||||
final AnnotationUsage<JoinTable> 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<JoinTable> getExactOverriddenJoinTable(String propertyName) {
|
||||
AnnotationUsage<JoinTable> 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<String, Column[]> columnOverride = new HashMap<>();
|
||||
Map<String, ColumnTransformer> columnTransformerOverride = new HashMap<>();
|
||||
Map<String, JoinColumn[]> joinColumnOverride = new HashMap<>();
|
||||
Map<String, JoinTable> joinTableOverride = new HashMap<>();
|
||||
Map<String, ForeignKey> 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<String, List<AnnotationUsage<Column>>> columnOverride = new HashMap<>();
|
||||
Map<String, AnnotationUsage<ColumnTransformer>> columnTransformerOverride = new HashMap<>();
|
||||
Map<String, List<AnnotationUsage<JoinColumn>>> joinColumnOverride = new HashMap<>();
|
||||
Map<String, AnnotationUsage<JoinTable>> joinTableOverride = new HashMap<>();
|
||||
Map<String, AnnotationUsage<ForeignKey>> 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<String, Column[]> currentOverride = buildColumnOverride( current, getPath(), context );
|
||||
Map<String, ColumnTransformer> currentTransformerOverride = buildColumnTransformerOverride( current );
|
||||
Map<String, JoinColumn[]> currentJoinOverride = buildJoinColumnOverride( current, getPath() );
|
||||
Map<String, JoinTable> currentJoinTableOverride = buildJoinTableOverride( current, getPath() );
|
||||
Map<String, ForeignKey> currentForeignKeyOverride = buildForeignKeyOverride( current, getPath() );
|
||||
Map<String, List<AnnotationUsage<Column>>> currentOverride = buildColumnOverride( current, getPath(), context );
|
||||
Map<String, AnnotationUsage<ColumnTransformer>> currentTransformerOverride = buildColumnTransformerOverride( current );
|
||||
Map<String, List<AnnotationUsage<JoinColumn>>> currentJoinOverride = buildJoinColumnOverride( current, getPath() );
|
||||
Map<String, AnnotationUsage<JoinTable>> currentJoinTableOverride = buildJoinTableOverride( current, getPath() );
|
||||
Map<String, AnnotationUsage<ForeignKey>> 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<String, Column[]> buildColumnOverride(
|
||||
XAnnotatedElement element,
|
||||
private static Map<String, List<AnnotationUsage<Column>>> buildColumnOverride(
|
||||
AnnotationTarget element,
|
||||
String path,
|
||||
MetadataBuildingContext context) {
|
||||
final Map<String, Column[]> 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<String, List<AnnotationUsage<Column>>> columnOverrideMap = new HashMap<>();
|
||||
if ( element == null ) {
|
||||
return columnOverrideMap;
|
||||
}
|
||||
|
||||
if ( overrides != null ) {
|
||||
final Map<String, List<Column>> columnOverrideList = new HashMap<>();
|
||||
final List<AnnotationUsage<AttributeOverride>> overrides = element.getRepeatedAnnotationUsages( AttributeOverride.class );
|
||||
if ( CollectionHelper.isNotEmpty( overrides ) ) {
|
||||
final Map<String, List<AnnotationUsage<Column>>> columnOverrideList = new HashMap<>();
|
||||
for ( AnnotationUsage<AttributeOverride> depAttr : overrides ) {
|
||||
final String qualifiedName = StringHelper.qualify( path, depAttr.getString( "name" ) );
|
||||
final AnnotationUsage<Column> 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<Column> list = new ArrayList<>();
|
||||
list.add( depAttr.column() );
|
||||
columnOverrideList.put( qualifiedName, list );
|
||||
}
|
||||
}
|
||||
|
||||
for ( Map.Entry<String, List<Column>> 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<AnnotationUsage<Column>> 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> 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<Column> 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<Column> createTimeZoneColumn(
|
||||
AnnotationTarget element,
|
||||
AnnotationUsage<Column> column,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotationUsage<TimeZoneColumn> 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<Column> createTemporalColumn(
|
||||
AnnotationTarget element,
|
||||
String path,
|
||||
MetadataBuildingContext context) {
|
||||
int precision;
|
||||
final Column annotatedColumn = element.getAnnotation( Column.class );
|
||||
final AnnotationUsage<Column> 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<String, ColumnTransformer> buildColumnTransformerOverride(XAnnotatedElement element) {
|
||||
Map<String, ColumnTransformer> columnOverride = new HashMap<>();
|
||||
private static Map<String, AnnotationUsage<ColumnTransformer>> buildColumnTransformerOverride(AnnotationTarget element) {
|
||||
final Map<String, AnnotationUsage<ColumnTransformer>> 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<String, List<AnnotationUsage<JoinColumn>>> buildJoinColumnOverride(AnnotationTarget element, String path) {
|
||||
final Map<String, List<AnnotationUsage<JoinColumn>>> columnOverride = new HashMap<>();
|
||||
if ( element != null ) {
|
||||
final List<AnnotationUsage<AssociationOverride>> overrides = buildAssociationOverrides( element, path );
|
||||
for ( AnnotationUsage<AssociationOverride> override : overrides ) {
|
||||
columnOverride.put(
|
||||
qualify( path, override.getString( "name" ) ),
|
||||
override.getList( "joinColumns" )
|
||||
);
|
||||
}
|
||||
}
|
||||
return columnOverride;
|
||||
}
|
||||
|
||||
private static Map<String, JoinColumn[]> buildJoinColumnOverride(XAnnotatedElement element, String path) {
|
||||
Map<String, JoinColumn[]> columnOverride = new HashMap<>();
|
||||
private static Map<String, AnnotationUsage<ForeignKey>> buildForeignKeyOverride(AnnotationTarget element, String path) {
|
||||
final Map<String, AnnotationUsage<ForeignKey>> 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<String, ForeignKey> buildForeignKeyOverride(XAnnotatedElement element, String path) {
|
||||
Map<String, ForeignKey> 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<AnnotationUsage<AssociationOverride>> overrides = buildAssociationOverrides( element, path );
|
||||
for ( AnnotationUsage<AssociationOverride> 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<AnnotationUsage<AssociationOverride>> buildAssociationOverrides(AnnotationTarget element, String path) {
|
||||
final List<AnnotationUsage<AssociationOverride>> overrides = new ArrayList<>();
|
||||
element.forEachAnnotationUsage( AssociationOverride.class, overrides::add );
|
||||
return overrides;
|
||||
}
|
||||
|
||||
private static Map<String, JoinTable> buildJoinTableOverride(XAnnotatedElement element, String path) {
|
||||
Map<String, JoinTable> tableOverride = new HashMap<>();
|
||||
private static Map<String, AnnotationUsage<JoinTable>> buildJoinTableOverride(AnnotationTarget element, String path) {
|
||||
final Map<String, AnnotationUsage<JoinTable>> 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<AnnotationUsage<AssociationOverride>> overrides = buildAssociationOverrides( element, path );
|
||||
for ( AnnotationUsage<AssociationOverride> override : overrides ) {
|
||||
final List<AnnotationUsage<JoinColumn>> joinColumns = override.getList( "joinColumns" );
|
||||
if ( CollectionHelper.isNotEmpty( joinColumns ) ) {
|
||||
result.put(
|
||||
qualify( path, override.getString( "name" ) ),
|
||||
override.getNestedUsage( "joinTable" )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tableOverride;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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> struct = property.getAnnotationUsage( Struct.class );
|
||||
if ( struct != null ) {
|
||||
return toQualifiedName( struct, context );
|
||||
}
|
||||
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
|
||||
final AnnotationUsage<JdbcTypeCode> 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<AnnotatedColumn> columnList = columns.getColumns();
|
||||
final String sqlType;
|
||||
|
@ -148,60 +152,72 @@ public final class AggregateComponentBinder {
|
|||
}
|
||||
}
|
||||
}
|
||||
final Struct struct = returnedClassOrElement.getAnnotation( Struct.class );
|
||||
|
||||
final AnnotationUsage<Struct> 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> 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> struct = property.getAnnotationUsage( Struct.class );
|
||||
if ( struct != null ) {
|
||||
return struct.attributes();
|
||||
final List<String> attributes = struct.getList( "attributes" );
|
||||
return attributes.toArray( new String[0] );
|
||||
}
|
||||
}
|
||||
final Struct struct = returnedClassOrElement.getAnnotation( Struct.class );
|
||||
|
||||
final AnnotationUsage<Struct> struct = returnedClassOrElement.getAnnotationUsage( Struct.class );
|
||||
if ( struct != null ) {
|
||||
return struct.attributes();
|
||||
final List<String> 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> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> 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
|
||||
)
|
||||
);
|
||||
|
|
|
@ -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<org.hibernate.annotations.Formula> formulaAnn,
|
||||
// Comment commentAnn,
|
||||
Nullability nullability,
|
||||
PropertyHolder propertyHolder,
|
||||
|
@ -512,7 +512,7 @@ public class AnnotatedColumn {
|
|||
}
|
||||
|
||||
public static AnnotatedColumns buildColumnFromNoAnnotation(
|
||||
FractionalSeconds fractionalSeconds,
|
||||
AnnotationUsage<FractionalSeconds> 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<jakarta.persistence.Column> column,
|
||||
AnnotationUsage<FractionalSeconds> 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<AnnotationUsage<jakarta.persistence.Column>> columns,
|
||||
AnnotationUsage<FractionalSeconds> fractionalSeconds,
|
||||
// Comment commentAnn,
|
||||
Nullability nullability,
|
||||
PropertyHolder propertyHolder,
|
||||
|
@ -577,7 +577,7 @@ public class AnnotatedColumn {
|
|||
}
|
||||
|
||||
public static AnnotatedColumns buildColumnsFromAnnotations(
|
||||
jakarta.persistence.Column[] columns,
|
||||
List<AnnotationUsage<jakarta.persistence.Column>> 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<jakarta.persistence.Column> column,
|
||||
AnnotationUsage<org.hibernate.annotations.Formula> formulaAnn,
|
||||
AnnotationUsage<FractionalSeconds> fractionalSeconds,
|
||||
// Comment commentAnn,
|
||||
Nullability nullability,
|
||||
PropertyHolder propertyHolder,
|
||||
|
@ -610,7 +610,7 @@ public class AnnotatedColumn {
|
|||
Map<String, Join> 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<AnnotationUsage<jakarta.persistence.Column>> columns,
|
||||
AnnotationUsage<org.hibernate.annotations.Formula> formulaAnn,
|
||||
AnnotationUsage<FractionalSeconds> 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<AnnotationUsage<jakarta.persistence.Column>> 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<AnnotationUsage<jakarta.persistence.Column>> overrideColumns(
|
||||
List<AnnotationUsage<jakarta.persistence.Column>> columns,
|
||||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData ) {
|
||||
final String path = getPath( propertyHolder, inferredData );
|
||||
final jakarta.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn( path );
|
||||
final List<AnnotationUsage<jakarta.persistence.Column>> 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<String, Join> secondaryTables,
|
||||
MetadataBuildingContext context,
|
||||
jakarta.persistence.Column[] actualCols,
|
||||
FractionalSeconds fractionalSeconds) {
|
||||
List<AnnotationUsage<jakarta.persistence.Column>> actualCols,
|
||||
AnnotationUsage<FractionalSeconds> 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<jakarta.persistence.Column> 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<jakarta.persistence.Column> 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<jakarta.persistence.Column> 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<jakarta.persistence.Column> column,
|
||||
AnnotationUsage<FractionalSeconds> 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<jakarta.persistence.Column> 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<jakarta.persistence.Column> 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> 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> 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<Checks> checksAnn = attributeMember.getAnnotationUsage( Checks.class );
|
||||
if ( checksAnn != null ) {
|
||||
final List<AnnotationUsage<Check>> checkAnns = checksAnn.getList( "value" );
|
||||
for ( AnnotationUsage<Check> 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<Check> 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<ColumnTransformer> 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> fractionalSeconds,
|
||||
PropertyData inferredData,
|
||||
String suffixForDefaultColumnName,
|
||||
Map<String, Join> 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> index, boolean inSecondPass) {
|
||||
if ( index != null ) {
|
||||
addIndex( index.name(), inSecondPass );
|
||||
addIndex( index.getString( "name" ), inSecondPass );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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> discriminatorColumn,
|
||||
AnnotationUsage<DiscriminatorFormula> discriminatorFormula,
|
||||
AnnotationUsage<Column> 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> discriminatorColumn,
|
||||
AnnotationUsage<Column> 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:
|
||||
|
|
|
@ -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> 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<AnnotationUsage<JoinColumn>> 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> 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> joinColumn,
|
||||
// Comment comment,
|
||||
String mappedBy,
|
||||
AnnotatedJoinColumns parent,
|
||||
|
@ -123,7 +126,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
}
|
||||
|
||||
private static AnnotatedJoinColumn explicitJoinColumn(
|
||||
JoinColumn joinColumn,
|
||||
AnnotationUsage<JoinColumn> 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> 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> primaryKeyJoinColumn,
|
||||
AnnotationUsage<JoinColumn> 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> primaryKeyJoinColumn,
|
||||
AnnotationUsage<JoinColumn> 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> joinColumn) {
|
||||
final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
|
||||
column.setImplicit( true );
|
||||
// column.setPropertyHolder( propertyHolder );
|
||||
|
|
|
@ -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<AnnotationUsage<JoinColumnOrFormula>> joinColumnOrFormulas,
|
||||
String mappedBy,
|
||||
Map<String, Join> 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<JoinColumnOrFormula> columnOrFormula : joinColumnOrFormulas ) {
|
||||
final AnnotationUsage<JoinFormula> formula = columnOrFormula.getNestedUsage( "formula" );
|
||||
final AnnotationUsage<JoinColumn> 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> joinFormula,
|
||||
Map<String, Join> secondaryTables,
|
||||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData,
|
||||
|
@ -117,7 +119,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
|
|||
}
|
||||
|
||||
public static AnnotatedJoinColumns buildJoinColumns(
|
||||
JoinColumn[] joinColumns,
|
||||
List<AnnotationUsage<JoinColumn>> joinColumns,
|
||||
// Comment comment,
|
||||
String mappedBy,
|
||||
Map<String, Join> joins,
|
||||
|
@ -137,7 +139,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
|
|||
}
|
||||
|
||||
public static AnnotatedJoinColumns buildJoinColumnsWithDefaultColumnSuffix(
|
||||
JoinColumn[] joinColumns,
|
||||
List<AnnotationUsage<JoinColumn>> joinColumns,
|
||||
// Comment comment,
|
||||
String mappedBy,
|
||||
Map<String, Join> 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<AnnotationUsage<JoinColumn>> overrides = propertyHolder.getOverriddenJoinColumn( path );
|
||||
final List<AnnotationUsage<JoinColumn>> 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<JoinColumn> 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<AnnotationUsage<JoinColumn>> joinColumns,
|
||||
Map<String, Join> 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> joinColumn : joinColumns ) {
|
||||
AnnotatedJoinColumn.buildExplicitJoinTableJoinColumn( parent, propertyHolder, inferredData, joinColumn );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<SequenceGenerator> generators = ( List<SequenceGenerator> ) 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<TableGenerator> generators = ( List<TableGenerator> ) 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<TableGenerators> generators = (List<TableGenerators>) 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<SequenceGenerators> generators = (List<SequenceGenerators>) 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<NamedQuery> queries = ( List<NamedQuery> ) defaults.get( NamedQuery.class );
|
||||
if ( queries != null ) {
|
||||
for ( NamedQuery ann : queries ) {
|
||||
QueryBinder.bindQuery( ann, context, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<NamedNativeQuery> nativeQueries = ( List<NamedNativeQuery> ) 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<SqlResultSetMapping> mappings = ( List<SqlResultSetMapping> ) 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<NamedStoredProcedureQuery> storedProcedureQueries =
|
||||
(List<NamedStoredProcedureQuery>) defaults.get( NamedStoredProcedureQuery.class );
|
||||
if ( storedProcedureQueries != null ) {
|
||||
for ( NamedStoredProcedureQuery annotation : storedProcedureQueries ) {
|
||||
bindNamedStoredProcedureQuery( annotation, context, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<NamedStoredProcedureQueries> storedProcedureQueries =
|
||||
(List<NamedStoredProcedureQueries>) 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<GenericGenerator> 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 <em>after</em> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
ClassDetails classDetails,
|
||||
Map<ClassDetails, InheritanceState> 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<String, IdentifierGeneratorDefinition> generators = buildGenerators( annotatedClass, context );
|
||||
if ( context.getMetadataCollector().getClassType( annotatedClass ) == ENTITY ) {
|
||||
EntityBinder.bindEntityClass( annotatedClass, inheritanceStatePerClass, generators, context );
|
||||
final Map<String, IdentifierGeneratorDefinition> 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<? extends JdbcType> jdbcTypeClass = annotation.value();
|
||||
AnnotationUsage<JdbcTypeRegistration> annotation) {
|
||||
final Class<? extends JdbcType> 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<? extends BasicJavaType<?>> javaTypeClass = annotation.descriptorClass();
|
||||
final BasicJavaType<?> javaType =
|
||||
!context.getBuildingOptions().isAllowExtensionsInCdi()
|
||||
? FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( javaTypeClass )
|
||||
: managedBeanRegistry.getBean( javaTypeClass ).getBeanInstance();
|
||||
context.getMetadataCollector().addJavaTypeRegistration( annotation.javaType(), javaType );
|
||||
AnnotationUsage<JavaTypeRegistration> annotation) {
|
||||
final Class<? extends BasicJavaType<?>> 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<EmbeddableInstantiatorRegistration> 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<TypeRegistration> 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> 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<ConverterRegistration> 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> 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<AnnotationUsage<FetchOverride>> fetchOverrides = fetchProfile.getList( "fetchOverrides" );
|
||||
for ( AnnotationUsage<FetchOverride> 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<XClass, InheritanceState> buildInheritanceStates(
|
||||
List<XClass> orderedClasses,
|
||||
public static Map<ClassDetails, InheritanceState> buildInheritanceStates(
|
||||
List<ClassDetails> orderedClasses,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final Map<XClass, InheritanceState> 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<ClassDetails, InheritanceState> 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)" );
|
||||
|
|
|
@ -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<String, String> extractParameterMap(List<AnnotationUsage<Parameter>> parameters) {
|
||||
final HashMap<String,String> paramMap = mapOfSize( parameters.size() );
|
||||
parameters.forEach( (usage) -> {
|
||||
paramMap.put( usage.getString( "name" ), usage.getString( "value" ) );
|
||||
} );
|
||||
return paramMap;
|
||||
}
|
||||
}
|
|
@ -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<Cascade> hibernateCascade = property.getAnnotationUsage( Cascade.class );
|
||||
final AnnotationUsage<OnDelete> onDeleteAnn = property.getAnnotationUsage( OnDelete.class );
|
||||
final AnnotationUsage<JoinTable> 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<org.hibernate.annotations.Any> 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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<? extends AttributeConverter<?,?>> converterClass;
|
||||
private final boolean conversionDisabled;
|
||||
|
||||
private final String attributeName;
|
||||
|
||||
private final XAnnotatedElement source;
|
||||
private final AnnotationTarget source;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public AttributeConversionInfo(
|
||||
Class<? extends AttributeConverter> converterClass,
|
||||
boolean conversionDisabled,
|
||||
String attributeName,
|
||||
XAnnotatedElement source) {
|
||||
AnnotationTarget source) {
|
||||
this.converterClass = (Class<? extends AttributeConverter<?, ?>>) converterClass;
|
||||
this.conversionDisabled = conversionDisabled;
|
||||
this.attributeName = attributeName;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AttributeConversionInfo(Convert convertAnnotation, XAnnotatedElement xAnnotatedElement) {
|
||||
public AttributeConversionInfo(AnnotationUsage<Convert> 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;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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<jakarta.persistence.Column> discriminatorColumn,
|
||||
AnnotationUsage<Formula> 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<Object,Class<?>> 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<AnyDiscriminatorValue> consumer) {
|
||||
final AnyDiscriminatorValue valueAnn = findAnnotation( property, AnyDiscriminatorValue.class );
|
||||
MemberDetails property,
|
||||
Consumer<AnnotationUsage<AnyDiscriminatorValue>> consumer) {
|
||||
final AnnotationUsage<AnyDiscriminatorValue> valueAnn = property.locateAnnotationUsage( AnyDiscriminatorValue.class );
|
||||
if ( valueAnn != null ) {
|
||||
consumer.accept( valueAnn );
|
||||
return;
|
||||
}
|
||||
|
||||
final AnyDiscriminatorValues valuesAnn = findAnnotation( property, AnyDiscriminatorValues.class );
|
||||
final AnnotationUsage<AnyDiscriminatorValues> valuesAnn = property.locateAnnotationUsage( AnyDiscriminatorValues.class );
|
||||
if ( valuesAnn != null ) {
|
||||
for ( AnyDiscriminatorValue discriminatorValue : valuesAnn.value() ) {
|
||||
consumer.accept( discriminatorValue );
|
||||
}
|
||||
final List<AnnotationUsage<AnyDiscriminatorValue>> nestedList = valuesAnn.getList( "value" );
|
||||
nestedList.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
public static MappedSuperclass getMappedSuperclassOrNull(
|
||||
XClass declaringClass,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
ClassDetails declaringClass,
|
||||
Map<ClassDetails, InheritanceState> 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<String,String> toAliasTableMap(SqlFragmentAlias[] aliases){
|
||||
public static Map<String,String> toAliasTableMap(List<AnnotationUsage<SqlFragmentAlias>> aliases){
|
||||
final Map<String,String> ret = new HashMap<>();
|
||||
for ( SqlFragmentAlias alias : aliases ) {
|
||||
if ( isNotEmpty( alias.table() ) ) {
|
||||
ret.put( alias.alias(), alias.table() );
|
||||
for ( AnnotationUsage<SqlFragmentAlias> aliasAnnotation : aliases ) {
|
||||
final String table = aliasAnnotation.getString( "table" );
|
||||
if ( isNotEmpty( table ) ) {
|
||||
ret.put( aliasAnnotation.getString( "alias" ), table );
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Map<String,String> toAliasEntityMap(SqlFragmentAlias[] aliases){
|
||||
public static Map<String,String> toAliasEntityMap(List<AnnotationUsage<SqlFragmentAlias>> aliases){
|
||||
final Map<String,String> result = new HashMap<>();
|
||||
for ( SqlFragmentAlias alias : aliases ) {
|
||||
if ( alias.entity() != void.class ) {
|
||||
result.put( alias.alias(), alias.entity().getName() );
|
||||
for ( AnnotationUsage<SqlFragmentAlias> 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 extends Annotation> T getOverridableAnnotation(
|
||||
XAnnotatedElement element,
|
||||
Class<T> annotationType,
|
||||
MetadataBuildingContext context) {
|
||||
final Dialect dialect = context.getMetadataCollector().getDatabase().getDialect();
|
||||
final Iterator<Annotation> 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<? extends Annotation> type = annotation.annotationType();
|
||||
final DialectOverride.OverridesAnnotation overridesAnnotation =
|
||||
type.getAnnotation(DialectOverride.OverridesAnnotation.class);
|
||||
if ( overridesAnnotation != null
|
||||
&& overridesAnnotation.value().equals(annotationType) ) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
final Class<? extends Dialect> overrideDialect = (Class<? extends Dialect>)
|
||||
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<AnnotationCacheValue> 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<CascadeType> convertToHibernateCascadeType(jakarta.persistence.CascadeType[] ejbCascades) {
|
||||
private static EnumSet<CascadeType> convertToHibernateCascadeType(List<jakarta.persistence.CascadeType> ejbCascades) {
|
||||
final EnumSet<CascadeType> 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<jakarta.persistence.CascadeType> ejbCascades,
|
||||
AnnotationUsage<Cascade> hibernateCascadeAnnotation,
|
||||
boolean orphanRemoval,
|
||||
boolean forcePersist) {
|
||||
final EnumSet<CascadeType> cascadeTypes = convertToHibernateCascadeType( ejbCascades );
|
||||
final CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ? null : hibernateCascadeAnnotation.value();
|
||||
if ( hibernateCascades != null && hibernateCascades.length > 0 ) {
|
||||
cascadeTypes.addAll( Arrays.asList( hibernateCascades ) );
|
||||
final List<CascadeType> 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> 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 extends Annotation> A extractFromPackage(
|
||||
public static <A extends Annotation> AnnotationUsage<A> extractFromPackage(
|
||||
Class<A> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, Join> joins;
|
||||
private transient Map<String, Join> joinsPerRealTableName;
|
||||
private EntityBinder entityBinder;
|
||||
private final Map<XClass, InheritanceState> inheritanceStatePerClass;
|
||||
private final Map<ClassDetails, InheritanceState> inheritanceStatePerClass;
|
||||
|
||||
private final Map<String,AttributeConversionInfo> attributeConversionInfoMap;
|
||||
|
||||
public ClassPropertyHolder(
|
||||
PersistentClass persistentClass,
|
||||
XClass entityXClass,
|
||||
ClassDetails entityXClass,
|
||||
Map<String, Join> joins,
|
||||
MetadataBuildingContext context,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
Map<ClassDetails, InheritanceState> 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<String, AttributeConversionInfo> buildAttributeConversionInfoMap(XClass entityXClass) {
|
||||
protected Map<String, AttributeConversionInfo> buildAttributeConversionInfoMap(ClassDetails entityClassDetails) {
|
||||
final HashMap<String, AttributeConversionInfo> map = new HashMap<>();
|
||||
collectAttributeConversionInfo( map, entityXClass );
|
||||
collectAttributeConversionInfo( map, entityClassDetails );
|
||||
return map;
|
||||
}
|
||||
|
||||
private void collectAttributeConversionInfo(Map<String, AttributeConversionInfo> infoMap, XClass xClass) {
|
||||
if ( xClass == null ) {
|
||||
private void collectAttributeConversionInfo(Map<String, AttributeConversionInfo> 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<JoinTable> 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> 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<Property> 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<Property> propertyConsumer,
|
||||
MetadataBuildingContext context) {
|
||||
if ( typeDetails.determineRawClass().getTypeParameters().isEmpty() ) {
|
||||
propertyConsumer.accept( prop );
|
||||
return;
|
||||
}
|
||||
|
||||
final ClassDetails declaringClassDetails = memberDetails.getDeclaringType();
|
||||
final List<MemberDetails> 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<Property> propertyIterator = component.getProperties().iterator();
|
||||
while ( propertyIterator.hasNext() ) {
|
||||
try {
|
||||
propertyIterator.next().getGetter( componentClass );
|
||||
}
|
||||
else {
|
||||
final Iterator<Property> 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<XProperty> getDeclaredProperties(XClass declaringClass, String accessType) {
|
||||
final List<XProperty> properties = new ArrayList<>();
|
||||
XClass superclass = declaringClass;
|
||||
private static List<MemberDetails> getDeclaredAttributeMembers(
|
||||
ClassDetails declaringType,
|
||||
String propertyAccessorName) {
|
||||
final List<MemberDetails> 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<MemberDetails> 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 );
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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<String,AttributeConversionInfo> elementAttributeConversionInfoMap,
|
||||
Map<String,AttributeConversionInfo> 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<Convert> convertAnnotation,
|
||||
MemberDetails collectionProperty,
|
||||
boolean isComposite,
|
||||
Map<String,AttributeConversionInfo> elementAttributeConversionInfoMap,
|
||||
Map<String,AttributeConversionInfo> 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<JoinTable> 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<JoinTable> 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() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Column> columnAnn = property.getAnnotationUsage( Column.class );
|
||||
final AnnotationUsage<Formula> formulaAnn = property.getAnnotationUsage( Formula.class );
|
||||
final AnnotationUsage<Columns> 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> 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<JoinTable> 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<OneToOne> 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<AnnotationUsage<JoinColumn>> 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<AnnotationUsage<JoinColumnOrFormula>> 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> 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<AnnotationUsage<JoinColumnOrFormula>> 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> joinColumnsOrFormulas = property.getAnnotationUsage( JoinColumnsOrFormulas.class );
|
||||
final List<AnnotationUsage<JoinColumnOrFormula>> 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<AnnotationUsage<JoinColumn>> 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> joinColumns = property.getAnnotationUsage( JoinColumns.class );
|
||||
final List<AnnotationUsage<JoinColumn>> 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<PrimaryKeyJoinColumn> 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> primaryKeyJoinColumns = property.getAnnotationUsage( PrimaryKeyJoinColumns.class );
|
||||
// final List<PrimaryKeyJoinColumn> 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<? extends Annotation> annotationType() {
|
||||
return JoinColumn.class;
|
||||
|
|
|
@ -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<XClass, InheritanceState> 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<? extends Annotation> annotationType) {
|
||||
if ( memberDetails == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memberDetails.hasAnnotationUsage( annotationType );
|
||||
}
|
||||
|
||||
private boolean hasAnnotation(
|
||||
MemberDetails memberDetails,
|
||||
Class<? extends Annotation> annotationType1,
|
||||
Class<? extends Annotation> annotationType2) {
|
||||
return hasAnnotation( memberDetails, annotationType1 )
|
||||
|| hasAnnotation( memberDetails, annotationType2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called from our constructor and handles (in order):<ol>
|
||||
* <li>@Convert annotation at the Embeddable class level</li>
|
||||
|
@ -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<String,AttributeConversionInfo> processAttributeConversions(XProperty embeddedXProperty) {
|
||||
private Map<String,AttributeConversionInfo> processAttributeConversions(MemberDetails embeddedMemberDetails) {
|
||||
final Map<String,AttributeConversionInfo> 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<String, AttributeConversionInfo> 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<String, AttributeConversionInfo> 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<String,AttributeConversionInfo> processAttributeConversions(XClass embeddableXClass) {
|
||||
private Map<String,AttributeConversionInfo> processAttributeConversions(TypeDetails embeddableTypeDetails) {
|
||||
final Map<String,AttributeConversionInfo> 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> joinTable, boolean noDelayInPkColumnCreation) {
|
||||
return parent.addJoin( joinTable, noDelayInPkColumnCreation );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Join addJoin(JoinTable joinTable, Table table, boolean noDelayInPkColumnCreation) {
|
||||
public Join addJoin(AnnotationUsage<JoinTable> 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<AnnotationUsage<Column>> getOverriddenColumn(String propertyName) {
|
||||
//FIXME this is yukky
|
||||
Column[] result = super.getOverriddenColumn( propertyName );
|
||||
List<AnnotationUsage<Column>> 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 ) + ")";
|
||||
|
|
|
@ -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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
XProperty property,
|
||||
Map<ClassDetails, InheritanceState> inheritanceStatePerClass,
|
||||
MemberDetails property,
|
||||
AnnotatedColumns columns,
|
||||
XClass returnedClass,
|
||||
ClassDetails returnedClass,
|
||||
PropertyBinder propertyBinder,
|
||||
boolean isOverridden,
|
||||
Class<? extends CompositeUserType<?>> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
Map<ClassDetails, InheritanceState> inheritanceStatePerClass,
|
||||
String referencedEntityName, //is a component who is overridden by a @MapsId
|
||||
String propertyName,
|
||||
Class<? extends EmbeddableInstantiator> 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<AnnotationUsage<?>> metaAnnotatedAnnotations = annotatedClass.determineRawClass().getMetaAnnotated( TypeBinderType.class );
|
||||
for ( AnnotationUsage<?> metaAnnotated : metaAnnotatedAnnotations ) {
|
||||
final AnnotationUsage<TypeBinderType> 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<? extends TypeBinder<Annotation>> binderJavaType = binderImpl.toJavaClass();
|
||||
final TypeBinder<Annotation> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
Map<ClassDetails, InheritanceState> 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<? extends CompositeUserType<?>> compositeUserTypeClass,
|
||||
AnnotatedColumns columns,
|
||||
MetadataBuildingContext context,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
Map<ClassDetails, InheritanceState> inheritanceStatePerClass) {
|
||||
return fillEmbeddable(
|
||||
propertyHolder,
|
||||
inferredData,
|
||||
|
@ -332,7 +344,7 @@ public class EmbeddableBinder {
|
|||
Class<? extends CompositeUserType<?>> compositeUserTypeClass,
|
||||
AnnotatedColumns columns,
|
||||
MetadataBuildingContext context,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
Map<ClassDetails, InheritanceState> 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<String, String> subclassToSuperclass = component.isPolymorphic() ? new HashMap<>() : null;
|
||||
final TypeDetails annotatedType = inferredData.getPropertyType();
|
||||
final List<PropertyData> classElements = collectClassElements(
|
||||
propertyAccessor,
|
||||
context,
|
||||
returnedClassOrElement,
|
||||
annotatedClass,
|
||||
isIdClass,
|
||||
subclassToSuperclass
|
||||
annotatedType,
|
||||
isIdClass
|
||||
);
|
||||
|
||||
if ( component.isPolymorphic() ) {
|
||||
|
@ -429,10 +438,10 @@ public class EmbeddableBinder {
|
|||
}
|
||||
|
||||
final List<PropertyData> 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> discriminatorColumn = annotatedClass.getAnnotationUsage( DiscriminatorColumn.class );
|
||||
final AnnotationUsage<DiscriminatorFormula> 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<AnnotationUsage<Column>> 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<PropertyData> collectClassElements(
|
||||
AccessType propertyAccessor,
|
||||
MetadataBuildingContext context,
|
||||
XClass returnedClassOrElement,
|
||||
XClass annotatedClass,
|
||||
ClassDetails returnedClassOrElement,
|
||||
TypeDetails annotatedClass,
|
||||
boolean isIdClass,
|
||||
Map<String, String> subclassToSuperclass) {
|
||||
final List<PropertyData> 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<PropertyData> classElements,
|
||||
BasicType<?> discriminatorType,
|
||||
Map<Object, String> discriminatorValues,
|
||||
Map<String, String> 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<Object, String> 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<PropertyData> 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> 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<? extends EmbeddableInstantiator> 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<org.hibernate.annotations.EmbeddableInstantiator> 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<org.hibernate.annotations.EmbeddableInstantiator> 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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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<FetchOverride> fetch;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
|
||||
public FetchOverrideSecondPass(
|
||||
String fetchProfileName,
|
||||
FetchOverride fetch,
|
||||
AnnotationUsage<FetchOverride> fetch,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
this.fetchProfileName = fetchProfileName;
|
||||
this.fetch = fetch;
|
||||
|
@ -34,20 +36,21 @@ public class FetchOverrideSecondPass implements SecondPass {
|
|||
|
||||
@Override
|
||||
public void doSecondPass(Map<String, PersistentClass> 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" )
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<FetchProfileOverride> fetch;
|
||||
private final PropertyHolder propertyHolder;
|
||||
private final String propertyName;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
|
||||
public FetchSecondPass(
|
||||
FetchProfileOverride fetch,
|
||||
AnnotationUsage<FetchProfileOverride> fetch,
|
||||
PropertyHolder propertyHolder,
|
||||
String propertyName,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
|
@ -41,21 +42,20 @@ public class FetchSecondPass implements SecondPass {
|
|||
|
||||
@Override
|
||||
public void doSecondPass(Map<String, PersistentClass> 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
|
||||
|
|
|
@ -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> 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<String, JdbcMapping> explicitParamJaMappings;
|
||||
final Map<String, JdbcMapping> paramJdbcMappings;
|
||||
final Map<String, ManagedBean<? extends Supplier<?>>> parameterResolvers;
|
||||
if ( filterDef.parameters().length == 0 ) {
|
||||
explicitParamJaMappings = emptyMap();
|
||||
final List<AnnotationUsage<ParamDef>> 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<ParamDef> 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> filterDef = annotatedElement.getAnnotationUsage( FilterDef.class );
|
||||
final AnnotationUsage<FilterDefs> filterDefs = getOverridableAnnotation( annotatedElement, FilterDefs.class, context );
|
||||
if ( filterDef != null ) {
|
||||
bindFilterDef( filterDef, context );
|
||||
}
|
||||
if ( filterDefs != null ) {
|
||||
for ( FilterDef def : filterDefs.value() ) {
|
||||
final List<AnnotationUsage<FilterDef>> nestedDefs = filterDefs.getList( "value" );
|
||||
for ( AnnotationUsage<FilterDef> def : nestedDefs ) {
|
||||
bindFilterDef( def, context );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, IdentifierGeneratorDefinition> 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<String, IdentifierGeneratorDefinition> 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> 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<GeneratedValue> generatedValueAnn) {
|
||||
// todo (jpa32) : when can this ever be null?
|
||||
final GenerationType strategy = generatedValueAnn.getEnum( "strategy" );
|
||||
return strategy == null ? GenerationType.AUTO : strategy;
|
||||
}
|
||||
|
||||
public static Map<String, IdentifierGeneratorDefinition> buildGenerators(
|
||||
XAnnotatedElement annotatedElement,
|
||||
AnnotationTarget annotatedElement,
|
||||
MetadataBuildingContext context) {
|
||||
|
||||
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
||||
final Map<String, IdentifierGeneratorDefinition> 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> 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> 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<TableGenerator>) 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<SequenceGenerator>) 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> genericGenerator = (AnnotationUsage<GenericGenerator>) generatorAnnotation;
|
||||
definitionBuilder.setName( genericGenerator.getString( "name" ) );
|
||||
final Class<? extends Generator> 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<? extends Annotation> annotationType = annotation.annotationType();
|
||||
static GeneratorCreator generatorCreator(
|
||||
MemberDetails memberDetails,
|
||||
AnnotationUsage<?> annotation,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final Class<? extends Annotation> 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<? extends Annotation> annotation,
|
||||
BeanContainer beanContainer) {
|
||||
final Member member = HCANNHelper.getUnderlyingMember( idProperty );
|
||||
final Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final Class<? extends Annotation> annotationType = annotation.getAnnotationType();
|
||||
final IdGeneratorType idGeneratorType = annotationType.getAnnotation( IdGeneratorType.class );
|
||||
assert idGeneratorType != null;
|
||||
return creationContext -> {
|
||||
final Class<? extends Generator> 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<? extends Annotation> annotation,
|
||||
BeanContainer beanContainer,
|
||||
CustomIdGeneratorCreationContext creationContext,
|
||||
Class<? extends Generator> generatorClass,
|
||||
Member member,
|
||||
MemberDetails memberDetails,
|
||||
Class<? extends Annotation> 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<? extends Annotation> annotation,
|
||||
BeanContainer beanContainer,
|
||||
CustomIdGeneratorCreationContext creationContext,
|
||||
Class<? extends Generator> generatorClass,
|
||||
Member member,
|
||||
MemberDetails memberDetails,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
return beanContainer.getBean( generatorClass,
|
||||
new BeanContainer.LifecycleOptions() {
|
||||
|
@ -455,11 +433,11 @@ public class GeneratorBinder {
|
|||
public <B> B produceBeanInstance(Class<B> beanType) {
|
||||
return (B) instantiateGenerator(
|
||||
annotation,
|
||||
member,
|
||||
memberDetails,
|
||||
annotationType,
|
||||
creationContext,
|
||||
CustomIdGeneratorCreationContext.class,
|
||||
generatorClass
|
||||
generatorClass,
|
||||
creationContext
|
||||
);
|
||||
}
|
||||
@Override
|
||||
|
@ -471,30 +449,30 @@ public class GeneratorBinder {
|
|||
}
|
||||
|
||||
private static <C, G extends Generator> G instantiateGenerator(
|
||||
Annotation annotation,
|
||||
Member member,
|
||||
AnnotationUsage<?> annotation,
|
||||
MemberDetails memberDetails,
|
||||
Class<? extends Annotation> annotationType,
|
||||
C creationContext,
|
||||
Class<C> contextClass,
|
||||
Class<? extends G> generatorClass) {
|
||||
Class<? extends G> 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 <A extends Annotation> void callInitialize(
|
||||
A annotation,
|
||||
Member member,
|
||||
AnnotationUsage<A> 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<A> generation = (AnnotationBasedGenerator<A>) 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<String, IdentifierGeneratorDefinition> 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> 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<String, IdentifierGeneratorDefinition> 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 extends Annotation> T findAnnotation(
|
||||
XAnnotatedElement annotatedElement,
|
||||
Class<T> 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<Annotation> findContainingAnnotations(
|
||||
XAnnotatedElement annotatedElement,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
final List<Annotation> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, PersistentClass> persistentClasses) {
|
||||
boolean result = super.bindStarToManySecondPass( persistentClasses );
|
||||
|
||||
final CollectionId collectionIdAnn = property.getAnnotation( CollectionId.class );
|
||||
final AnnotationUsage<CollectionId> 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": {
|
||||
|
|
|
@ -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<String, PersistentClass> idGeneratorDefinitionMap) throws MappingException {
|
||||
makeIdGenerator( id, idXProperty, generatorType, generatorName, buildingContext, localIdentifierGeneratorDefinition );
|
||||
makeIdGenerator( id, idAttributeMember, generatorType, generatorName, buildingContext, localIdentifierGeneratorDefinition );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> 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> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String> 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<String> 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<String> 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<AnnotationUsage<jakarta.persistence.Index>> indexes) {
|
||||
for ( AnnotationUsage<jakarta.persistence.Index> index : indexes ) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer( index.getString( "columnList" ), "," );
|
||||
final List<String> 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<String> 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<AnnotationUsage<UniqueConstraint>> constraints) {
|
||||
for ( AnnotationUsage<UniqueConstraint> constraint : constraints ) {
|
||||
final String name = constraint.getString( "name" );
|
||||
final List<String> columnNames = constraint.getList( "columnNames" );
|
||||
createIndexOrUniqueKey(
|
||||
table,
|
||||
name,
|
||||
!name.isEmpty(),
|
||||
columnNames,
|
||||
null,
|
||||
true,
|
||||
columns( table, name, columnNames )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeColumns(String[] columns, String[] ordering, List<String> list) {
|
||||
private void initializeColumns(List<String> columns, String[] ordering, List<String> 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<String> columnNames;
|
||||
private final String originalKeyName;
|
||||
|
||||
public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) {
|
||||
public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, List<String> columnNames, String originalKeyName) {
|
||||
this.buildingContext = buildingContext;
|
||||
this.table = table;
|
||||
this.columnNames = columnNames;
|
||||
|
@ -275,12 +292,12 @@ class IndexBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Identifier> toIdentifiers(String[] names) {
|
||||
private List<Identifier> toIdentifiers(List<String> names) {
|
||||
if ( names == null ) {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
final List<Identifier> columnNames = arrayList( names.length );
|
||||
final List<Identifier> columnNames = arrayList( names.size() );
|
||||
for ( String name : names ) {
|
||||
columnNames.add( getDatabase().toIdentifier( name ) );
|
||||
}
|
||||
|
|
|
@ -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> orderColumn,
|
||||
AnnotationUsage<org.hibernate.annotations.IndexColumn> indexColumn,
|
||||
AnnotationUsage<ListIndexBase> listIndexBase,
|
||||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData,
|
||||
Map<String, Join> 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> orderColumn,
|
||||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData,
|
||||
Map<String, Join> 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<org.hibernate.annotations.IndexColumn> 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 );
|
||||
|
|
|
@ -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<XClass, InheritanceState> inheritanceStatePerClass;
|
||||
private final List<XClass> classesToProcessForMappedSuperclass = new ArrayList<>();
|
||||
private final Map<ClassDetails, InheritanceState> inheritanceStatePerClass;
|
||||
private final List<ClassDetails> classesToProcessForMappedSuperclass = new ArrayList<>();
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
private AccessType accessType;
|
||||
private ElementsToProcess elementsToProcess;
|
||||
private Boolean hasIdClassOrEmbeddedId;
|
||||
|
||||
public InheritanceState(
|
||||
XClass clazz,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
ClassDetails classDetails,
|
||||
Map<ClassDetails, InheritanceState> 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<Inheritance> inheritanceAnn = classDetails.getAnnotationUsage( Inheritance.class );
|
||||
final AnnotationUsage<MappedSuperclass> 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<XClass, InheritanceState> states) {
|
||||
XClass superclass = clazz;
|
||||
public static InheritanceState getInheritanceStateOfSuperEntity(
|
||||
ClassDetails classDetails,
|
||||
Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> states) {
|
||||
XClass superclass = clazz;
|
||||
public static InheritanceState getSuperclassInheritanceState(
|
||||
ClassDetails classDetails,
|
||||
Map<ClassDetails, InheritanceState> 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<PropertyData> 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;
|
||||
|
|
|
@ -2222,7 +2222,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
|
|||
|
||||
List<StoredProcedureParameter> 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();
|
||||
|
|
|
@ -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<OrderBy> orderByAnn) {
|
||||
if ( orderByAnn != null ) {
|
||||
throw new AnnotationException( "A collection of type 'List' is annotated '@OrderBy'" );
|
||||
}
|
||||
|
|
|
@ -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<String, PersistentClass> 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<String, PersistentClass> 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<Object> 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<MapKeyClass> 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<String, PersistentClass> 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> 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<? extends CompositeUserType<?>> compositeUserType =
|
||||
resolveCompositeUserType( property, keyClass, buildingContext );
|
||||
final Class<? extends CompositeUserType<?>> 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<? extends CompositeUserType<?>> 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<? extends CompositeUserType<?>> resolveCompositeUserType(
|
||||
XProperty property,
|
||||
XClass returnedClass,
|
||||
MemberDetails property,
|
||||
TypeDetails returnedClass,
|
||||
MetadataBuildingContext context) {
|
||||
final MapKeyCompositeType compositeType = property.getAnnotation( MapKeyCompositeType.class );
|
||||
final AnnotationUsage<MapKeyCompositeType> 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<jakarta.persistence.ForeignKey> getMapKeyForeignKey(MemberDetails property) {
|
||||
final AnnotationUsage<MapKeyJoinColumns> mapKeyJoinColumns = property.getAnnotationUsage( MapKeyJoinColumns.class );
|
||||
final AnnotationUsage<MapKeyJoinColumn> 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<AttributeOverrides> annotations = property.getAnnotationUsage( AttributeOverrides.class );
|
||||
for ( AnnotationUsage<AttributeOverride> attributeOverride : annotations.<AnnotationUsage<AttributeOverride>>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<AttributeOverride> annotation) {
|
||||
return annotation.getString( "name" ).startsWith( "key." );
|
||||
}
|
||||
|
||||
private Value createFormulatedValue(
|
||||
|
|
|
@ -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<? extends Annotation> annotationType() {
|
||||
return Column.class;
|
||||
}
|
||||
}
|
|
@ -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<MapKeyJoinColumn> column) {
|
||||
this( column.toAnnotation() );
|
||||
}
|
||||
|
||||
public MapKeyJoinColumnDelegator(MapKeyJoinColumn column) {
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public static MutableAnnotationUsage<JoinColumn> fromMapKeyJoinColumn(
|
||||
AnnotationUsage<MapKeyJoinColumn> mapKeyJoinColumn,
|
||||
MemberDetails attributeMember,
|
||||
MetadataBuildingContext context) {
|
||||
final MutableAnnotationUsage<JoinColumn> 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();
|
||||
|
|
|
@ -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<LazyGroup> 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() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<XClass, InheritanceState> inheritanceStatePerClass;
|
||||
private Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
public void setInheritanceStatePerClass(Map<ClassDetails, InheritanceState> 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<String, PersistentClass> 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<? extends EmbeddableInstantiator> resolveCustomInstantiator(XProperty property, XClass embeddableClass) {
|
||||
if ( property.isAnnotationPresent( org.hibernate.annotations.EmbeddableInstantiator.class ) ) {
|
||||
return property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ).value();
|
||||
private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(MemberDetails property, ClassDetails embeddableClass) {
|
||||
if ( property.hasAnnotationUsage( org.hibernate.annotations.EmbeddableInstantiator.class ) ) {
|
||||
final AnnotationUsage<org.hibernate.annotations.EmbeddableInstantiator> 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<org.hibernate.annotations.EmbeddableInstantiator> 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> 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> 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<PropertyData> 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<Id> incomingIdProperty = property.getAnnotationUsage( Id.class );
|
||||
final AnnotationUsage<Id> 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<AnnotationUsage<JoinColumn>> joinColumnAnnotations = property.getRepeatedAnnotationUsages( JoinColumn.class );
|
||||
for ( AnnotationUsage<JoinColumn> 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<XClass, InheritanceState> inheritanceStatePerClass) throws MappingException {
|
||||
Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
XProperty property,
|
||||
XClass returnedClass) {
|
||||
|
||||
Map<ClassDetails, InheritanceState> 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<LazyGroup> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
XProperty property,
|
||||
XClass returnedClass,
|
||||
Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
XProperty property,
|
||||
Map<ClassDetails, InheritanceState> 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<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
XProperty property,
|
||||
XClass returnedClass,
|
||||
Map<ClassDetails, InheritanceState> 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<String, IdentifierGeneratorDefinition> 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<Basic> 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<Basic> 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<Basic> 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> 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> 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<? extends CompositeUserType<?>> 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> compositeType = attributeMember.locateAnnotationUsage( CompositeType.class );
|
||||
if ( compositeType != null ) {
|
||||
return compositeType.value();
|
||||
return compositeType.getClassDetails( "value" ).toJavaClass();
|
||||
}
|
||||
final Class<? extends CompositeUserType<?>> compositeUserType =
|
||||
resolveTimeZoneStorageCompositeUserType( property, returnedClass, context );
|
||||
final Class<? extends CompositeUserType<?>> 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<Annotation> idGeneratorAnnotations = findContainingAnnotations( idProperty, IdGeneratorType.class );
|
||||
final List<Annotation> generatorAnnotations = findContainingAnnotations( idProperty, ValueGenerationType.class );
|
||||
final MemberDetails idAttributeMember = inferredData.getAttributeMember();
|
||||
final List<AnnotationUsage<? extends Annotation>> idGeneratorAnnotations = idAttributeMember.getMetaAnnotated( IdGeneratorType.class );
|
||||
final List<AnnotationUsage<? extends Annotation>> 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<Annotation> generatorAnnotations, List<Annotation> 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<AnnotationUsage<? extends Annotation>> generatorAnnotations,
|
||||
List<AnnotationUsage<? extends Annotation>> idGeneratorAnnotations) {
|
||||
for ( AnnotationUsage<? extends Annotation> id : idGeneratorAnnotations ) {
|
||||
final Iterator<AnnotationUsage<? extends Annotation>> iterator = generatorAnnotations.iterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
final AnnotationUsage<? extends Annotation> gen = iterator.next();
|
||||
if ( gen.getAnnotationType().equals( id.getAnnotationType() ) ) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<XProperty> persistentAttributes;
|
||||
private final List<MemberDetails> 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<XProperty> fields = xClass.getDeclaredProperties( AccessType.FIELD.getType() );
|
||||
final List<XProperty> getters = xClass.getDeclaredProperties( AccessType.PROPERTY.getType() );
|
||||
final List<XProperty> recordComponents = xClass.getDeclaredProperties( AccessType.RECORD.getType() );
|
||||
private static List<MemberDetails> resolveAttributeMembers(
|
||||
ClassDetails classDetails,
|
||||
AccessType classLevelAccessType) {
|
||||
final List<FieldDetails> fields = collectPotentialAttributeMembers( classDetails.getFields() );
|
||||
final List<MethodDetails> getters = collectPotentialAttributeMembers( classDetails.getMethods() );
|
||||
final List<RecordComponentDetails> recordComponents = collectPotentialAttributeMembers( classDetails.getRecordComponents() );
|
||||
|
||||
preFilter( fields, getters, recordComponents );
|
||||
final Map<String, MemberDetails> attributeMemberMap = buildAttributeMemberMap(
|
||||
recordComponents,
|
||||
fields,
|
||||
getters
|
||||
);
|
||||
|
||||
final Map<String,XProperty> persistentAttributesFromGetters = new HashMap<>();
|
||||
final Map<String,XProperty> persistentAttributesFromComponents = new HashMap<>();
|
||||
final Map<String,MethodDetails> persistentAttributesFromGetters = new HashMap<>();
|
||||
final Map<String,RecordComponentDetails> persistentAttributesFromComponents = new HashMap<>();
|
||||
|
||||
final Map<String, XProperty> 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<XProperty> fields, List<XProperty> getters, List<XProperty> recordComponents) {
|
||||
Iterator<XProperty> propertyIterator = fields.iterator();
|
||||
while ( propertyIterator.hasNext() ) {
|
||||
final XProperty property = propertyIterator.next();
|
||||
if ( mustBeSkipped( property ) ) {
|
||||
propertyIterator.remove();
|
||||
}
|
||||
private static Map<String, MemberDetails> buildAttributeMemberMap(
|
||||
List<RecordComponentDetails> recordComponents,
|
||||
List<FieldDetails> fields,
|
||||
List<MethodDetails> getters) {
|
||||
final Map<String, MemberDetails> 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 <E extends MemberDetails> List<E> collectPotentialAttributeMembers(List<E> source) {
|
||||
final List<E> 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<String, XProperty> persistentAttributeMap,
|
||||
Map<String,XProperty> persistentAttributesFromGetters,
|
||||
Map<String,XProperty> persistentAttributesFromComponents,
|
||||
List<XProperty> fields,
|
||||
List<XProperty> getters,
|
||||
List<XProperty> recordComponents) {
|
||||
ClassDetails classDetails,
|
||||
Map<String, MemberDetails> persistentAttributeMap,
|
||||
Map<String,MethodDetails> persistentAttributesFromGetters,
|
||||
Map<String,RecordComponentDetails> persistentAttributesFromComponents,
|
||||
List<FieldDetails> fields,
|
||||
List<MethodDetails> getters,
|
||||
List<RecordComponentDetails> recordComponents) {
|
||||
|
||||
// Check fields...
|
||||
Iterator<XProperty> 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<Access> 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<Access> 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<Access> 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<String, XProperty> persistentAttributeMap,
|
||||
Map<String,XProperty> persistentAttributesFromGetters,
|
||||
Map<String,XProperty> persistentAttributesFromComponents,
|
||||
List<XProperty> fields,
|
||||
List<XProperty> getters,
|
||||
List<XProperty> recordComponents) {
|
||||
Map<String, MemberDetails> persistentAttributeMap,
|
||||
Map<String,MethodDetails> persistentAttributesFromGetters,
|
||||
Map<String,RecordComponentDetails> persistentAttributesFromComponents,
|
||||
List<FieldDetails> fields,
|
||||
List<MethodDetails> getters,
|
||||
List<RecordComponentDetails> 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<XProperty> propertyIterator() {
|
||||
return persistentAttributes;
|
||||
public Iterable<MemberDetails> propertyIterator() {
|
||||
return attributeMembers;
|
||||
}
|
||||
|
||||
private static List<XProperty> verifyAndInitializePersistentAttributes(XClass xClass, Map<String, XProperty> localAttributeMap) {
|
||||
ArrayList<XProperty> 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<MemberDetails> verifyAndInitializePersistentAttributes(
|
||||
ClassDetails classDetails,
|
||||
Map<String, MemberDetails> attributeMemberMap) {
|
||||
ArrayList<MemberDetails> 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<String, XProperty> 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<String, XProperty> propertiesMap = new TreeMap<String, XProperty>();
|
||||
// List<XProperty> 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> 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<OneToOne> oneToOneAnn = memberDetails.getAnnotationUsage( OneToOne.class );
|
||||
if ( oneToOneAnn != null ) {
|
||||
final ClassDetails targetEntity = oneToOneAnn.getClassDetails( "targetEntity" );
|
||||
return targetEntity != ClassDetails.VOID_CLASS_DETAILS;
|
||||
}
|
||||
|
||||
|
||||
final AnnotationUsage<OneToMany> oneToManyAnn = memberDetails.getAnnotationUsage( OneToMany.class );
|
||||
if ( oneToManyAnn != null ) {
|
||||
final ClassDetails targetEntity = oneToManyAnn.getClassDetails( "targetEntity" );
|
||||
return targetEntity != ClassDetails.VOID_CLASS_DETAILS;
|
||||
}
|
||||
|
||||
|
||||
final AnnotationUsage<ManyToOne> manToOneAnn = memberDetails.getAnnotationUsage( ManyToOne.class );
|
||||
if ( manToOneAnn != null ) {
|
||||
final ClassDetails targetEntity = manToOneAnn.getClassDetails( "targetEntity" );
|
||||
return targetEntity != ClassDetails.VOID_CLASS_DETAILS;
|
||||
}
|
||||
|
||||
final AnnotationUsage<ManyToMany> 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<ManyToAny> 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() ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AnnotationUsage<Column>> getOverriddenColumn(String propertyName);
|
||||
|
||||
/**
|
||||
* return null if the column is not overridden, or an array of column if true
|
||||
*/
|
||||
JoinColumn[] getOverriddenJoinColumn(String propertyName);
|
||||
List<AnnotationUsage<JoinColumn>> 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<ForeignKey> getOverriddenForeignKey(String propertyName) {
|
||||
// todo: does this necessarily need to be a default method?
|
||||
return null;
|
||||
}
|
||||
|
||||
ColumnTransformer getOverriddenColumnTransformer(String logicalColumnName);
|
||||
AnnotationUsage<ColumnTransformer> 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<JoinTable> getJoinTable(MemberDetails attributeMember);
|
||||
|
||||
String getEntityName();
|
||||
|
||||
Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation);
|
||||
Join addJoin(AnnotationUsage<JoinTable> joinTableAnn, boolean noDelayInPkColumnCreation);
|
||||
|
||||
Join addJoin(JoinTable joinTable, Table table, boolean noDelayInPkColumnCreation);
|
||||
Join addJoin(AnnotationUsage<JoinTable> 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);
|
||||
}
|
||||
|
|
|
@ -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<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
Map<ClassDetails, InheritanceState> 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<String, Join> joins,
|
||||
MetadataBuildingContext context,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
Map<ClassDetails, InheritanceState> inheritanceStatePerClass) {
|
||||
return new ClassPropertyHolder( persistentClass, null, joins, context, inheritanceStatePerClass );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> 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<org.hibernate.boot.internal.Target> 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<Target> 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<org.hibernate.boot.internal.Target> 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<Target> 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<TypeDetails> 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<E, L extends List<E>> {
|
||||
// // 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<Long> {...}
|
||||
// //
|
||||
// // 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<TypeDetails> 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<Long> {...}
|
||||
// //
|
||||
// // 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<Target> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> 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> 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> 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<SqlResultSetMapping> 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<org.hibernate.annotations.NamedNativeQuery> 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<String> querySpacesList = namedNativeQuery.getList( "querySpaces" );
|
||||
final HashSet<String> 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> namedQueries, MetadataBuildingContext context, boolean isDefault) {
|
||||
if ( namedQueries == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<NamedQuery>> nestedValues = namedQueries.getList( "value" );
|
||||
for ( AnnotationUsage<NamedQuery> nestedValue : nestedValues ) {
|
||||
bindQuery( nestedValue, context, isDefault );
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindNativeQueries(
|
||||
NamedNativeQueries namedNativeQueries,
|
||||
AnnotationUsage<NamedNativeQueries> namedNativeQueries,
|
||||
MetadataBuildingContext context,
|
||||
boolean isDefault) {
|
||||
if ( namedNativeQueries != null ) {
|
||||
for ( NamedNativeQuery namedNativeQuery : namedNativeQueries.value() ) {
|
||||
bindNativeQuery( namedNativeQuery, context, isDefault );
|
||||
}
|
||||
if ( namedNativeQueries == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<NamedNativeQuery>> nestedValues = namedNativeQueries.getList( "value" );
|
||||
for ( AnnotationUsage<NamedNativeQuery> nestedValue : nestedValues ) {
|
||||
bindNativeQuery( nestedValue, context, isDefault );
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindNativeQueries(
|
||||
org.hibernate.annotations.NamedNativeQueries namedNativeQueries,
|
||||
AnnotationUsage<org.hibernate.annotations.NamedNativeQueries> namedNativeQueries,
|
||||
MetadataBuildingContext context) {
|
||||
if ( namedNativeQueries != null ) {
|
||||
for ( org.hibernate.annotations.NamedNativeQuery namedNativeQuery : namedNativeQueries.value() ) {
|
||||
bindNativeQuery( namedNativeQuery, context );
|
||||
}
|
||||
if ( namedNativeQueries == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<org.hibernate.annotations.NamedNativeQuery>> nestedValues = namedNativeQueries.getList( "value" );
|
||||
for ( AnnotationUsage<org.hibernate.annotations.NamedNativeQuery> nestedValue : nestedValues ) {
|
||||
bindNativeQuery( nestedValue, context );
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindQuery(
|
||||
String name,
|
||||
HQLSelect hqlSelect,
|
||||
AnnotationUsage<HQLSelect> 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<org.hibernate.annotations.NamedQuery> 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<org.hibernate.annotations.NamedQueries> namedQueries,
|
||||
MetadataBuildingContext context) {
|
||||
if ( namedQueries != null ) {
|
||||
for (org.hibernate.annotations.NamedQuery namedQuery : namedQueries.value()) {
|
||||
bindQuery( namedQuery, context );
|
||||
}
|
||||
if ( namedQueries == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<org.hibernate.annotations.NamedQuery>> nestedValues = namedQueries.getList( "value" );
|
||||
for ( AnnotationUsage<org.hibernate.annotations.NamedQuery> nestedValue : nestedValues ) {
|
||||
bindQuery( nestedValue, context );
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindNamedStoredProcedureQuery(
|
||||
NamedStoredProcedureQuery namedStoredProcedureQuery,
|
||||
AnnotationUsage<NamedStoredProcedureQuery> 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<SqlResultSetMappings> resultSetMappings,
|
||||
MetadataBuildingContext context,
|
||||
boolean isDefault) {
|
||||
if ( resultSetMappings != null ) {
|
||||
for ( SqlResultSetMapping resultSetMapping : resultSetMappings.value() ) {
|
||||
bindSqlResultSetMapping( resultSetMapping, context, isDefault );
|
||||
}
|
||||
if ( resultSetMappings == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<SqlResultSetMapping>> mappings = resultSetMappings.getList( "value" );
|
||||
for ( AnnotationUsage<SqlResultSetMapping> mapping : mappings ) {
|
||||
bindSqlResultSetMapping( mapping, context, isDefault );
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindSqlResultSetMapping(
|
||||
SqlResultSetMapping resultSetMapping,
|
||||
AnnotationUsage<SqlResultSetMapping> 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<org.hibernate.annotations.NamedNativeQuery> queryAnn) {
|
||||
return new AnnotationException( "Callable 'NamedNativeQuery' named '" + queryAnn.getString( "name" )
|
||||
+ "' does not use the JDBC call syntax" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, Object> hintsMap;
|
||||
|
||||
public QueryHintDefinition(String queryName, final QueryHint[] hints) {
|
||||
public QueryHintDefinition(String queryName, final List<AnnotationUsage<QueryHint>> hints) {
|
||||
this.queryName = queryName;
|
||||
if ( hints == null || hints.length == 0 ) {
|
||||
if ( CollectionHelper.isEmpty( hints ) ) {
|
||||
hintsMap = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
final Map<String, Object> hintsMap = new HashMap<>();
|
||||
for ( QueryHint hint : hints ) {
|
||||
hintsMap.put( hint.name(), hint.value() );
|
||||
final Map<String, Object> hintsMap = mapOfSize( hints.size() );
|
||||
for ( AnnotationUsage<QueryHint> 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<NamedQuery> namedQueryAnnotation) {
|
||||
final LockModeType lockModeType = namedQueryAnnotation.getEnum( "lockMode" );
|
||||
final Integer lockTimeoutHint = specLockTimeout();
|
||||
final Boolean followOnLocking = getBooleanWrapper( HibernateHints.HINT_FOLLOW_ON_LOCKING );
|
||||
|
||||
|
|
|
@ -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<SqlResultSetMapping> annotation;
|
||||
private final MetadataBuildingContext context;
|
||||
private final boolean isDefault;
|
||||
|
||||
public ResultSetMappingSecondPass(SqlResultSetMapping annotation, MetadataBuildingContext context, boolean isDefault) {
|
||||
public ResultSetMappingSecondPass(AnnotationUsage<SqlResultSetMapping> annotation, MetadataBuildingContext context, boolean isDefault) {
|
||||
this.annotation = annotation;
|
||||
this.context = context;
|
||||
this.isDefault = isDefault;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<OrderBy> orderByAnn) {
|
||||
if ( orderByAnn != null ) {
|
||||
super.setSqlOrderBy( orderByAnn );
|
||||
}
|
||||
|
|
|
@ -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<SoftDelete> 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,
|
||||
|
|
|
@ -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<AnnotationUsage<UniqueConstraint>> uniqueConstraints;
|
||||
private List<AnnotationUsage<Index>> 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<AnnotationUsage<UniqueConstraint>> uniqueConstraints) {
|
||||
this.uniqueConstraints = uniqueConstraints;
|
||||
}
|
||||
|
||||
public void setJpaIndex(Index[] indexes){
|
||||
public void setJpaIndex(List<AnnotationUsage<Index>> indexes){
|
||||
this.indexes = indexes;
|
||||
}
|
||||
|
||||
|
@ -431,7 +432,7 @@ public class TableBinder {
|
|||
String catalog,
|
||||
Identifier logicalName,
|
||||
boolean isAbstract,
|
||||
UniqueConstraint[] uniqueConstraints,
|
||||
List<AnnotationUsage<UniqueConstraint>> uniqueConstraints,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
return buildAndFillTable(
|
||||
schema,
|
||||
|
@ -451,7 +452,7 @@ public class TableBinder {
|
|||
String catalog,
|
||||
Identifier logicalName,
|
||||
boolean isAbstract,
|
||||
UniqueConstraint[] uniqueConstraints,
|
||||
List<AnnotationUsage<UniqueConstraint>> 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<AnnotationUsage<UniqueConstraint>> uniqueConstraints,
|
||||
List<AnnotationUsage<Index>> 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<AnnotationUsage<org.hibernate.annotations.Index>> indexes, MetadataBuildingContext context) {
|
||||
for ( AnnotationUsage<org.hibernate.annotations.Index> indexUsage : indexes ) {
|
||||
final String name = indexUsage.getString( "name" );
|
||||
final String[] columnNames = indexUsage.<String>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<AnnotationUsage<jakarta.persistence.Index>> indexes, MetadataBuildingContext context) {
|
||||
for ( AnnotationUsage<jakarta.persistence.Index> 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
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<? extends CompositeUserType<?>> 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> 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> 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<Cascade> hibernateCascade = property.getAnnotationUsage( Cascade.class );
|
||||
final AnnotationUsage<NotFound> 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> onDelete = property.getAnnotationUsage( OnDelete.class );
|
||||
final AnnotationUsage<JoinTable> 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> 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> mapsId = property.getAnnotationUsage( MapsId.class );
|
||||
final List<AnnotatedJoinColumn> 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> 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> joinColumn = property.getSingleAnnotationUsage( JoinColumn.class );
|
||||
final AnnotationUsage<JoinColumns> 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> joinColumns, AnnotationUsage<JoinColumn> 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<JoinColumn> column : joinColumns.<AnnotationUsage<JoinColumn>>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<Fetch> 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<LazyToOne> 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> manyToOne = property.getAnnotationUsage( ManyToOne.class );
|
||||
final AnnotationUsage<OneToOne> 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> 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<Cascade> hibernateCascade = property.getAnnotationUsage( Cascade.class );
|
||||
final AnnotationUsage<NotFound> 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> onDelete = property.getAnnotationUsage( OnDelete.class );
|
||||
final AnnotationUsage<JoinTable> 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> 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> 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> joinColumn = property.getSingleAnnotationUsage( JoinColumn.class );
|
||||
final AnnotationUsage<JoinColumns> 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<org.hibernate.annotations.ForeignKey> 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<ForeignKey> 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<ForeignKey> 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> 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> 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() );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> annotatedPackages = new LinkedHashSet<>();
|
||||
private final List<XClass> xClasses = new ArrayList<>();
|
||||
private final LinkedHashSet<ClassDetails> 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<String> 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<String> processedEntityNames) {
|
||||
final List<XClass> orderedClasses = orderAndFillHierarchy( xClasses );
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass = AnnotationBinder.buildInheritanceStates(
|
||||
final List<ClassDetails> orderedClasses = orderAndFillHierarchy( knownClasses );
|
||||
Map<ClassDetails, InheritanceState> 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<XClass> orderAndFillHierarchy(List<XClass> classes) {
|
||||
private List<ClassDetails> orderAndFillHierarchy(LinkedHashSet<ClassDetails> original) {
|
||||
|
||||
LinkedHashSet<ClassDetails> copy = new LinkedHashSet<>( original.size() );
|
||||
insertMappedSuperclasses( original, copy );
|
||||
|
||||
// order the hierarchy
|
||||
List<ClassDetails> workingCopy = new ArrayList<>( copy );
|
||||
List<ClassDetails> newList = new ArrayList<>( copy.size() );
|
||||
while ( !workingCopy.isEmpty() ) {
|
||||
ClassDetails clazz = workingCopy.get( 0 );
|
||||
orderHierarchy( workingCopy, newList, copy, clazz );
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
private void insertMappedSuperclasses(LinkedHashSet<ClassDetails> original, LinkedHashSet<ClassDetails> copy) {
|
||||
final boolean debug = log.isDebugEnabled();
|
||||
|
||||
LinkedHashSet<XClass> orderedClasses = CollectionHelper.linkedSetOfSize( classes.size() * 2 );
|
||||
List<XClass> 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<ClassDetails> copy, List<ClassDetails> newList, LinkedHashSet<ClassDetails> 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<ClassDetails> knownClasses,
|
||||
MetadataBuildingContextRootImpl rootMetadataBuildingContext) {
|
||||
final ClassDetailsRegistry classDetailsRegistry = domainModelSource.getClassDetailsRegistry();
|
||||
domainModelSource.getManagedClassNames().forEach( (className) -> {
|
||||
knownClasses.add( classDetailsRegistry.resolveClassDetails( className ) );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> allKnownClassNames;
|
||||
|
||||
public DomainModelSource(
|
||||
ClassDetailsRegistry classDetailsRegistry,
|
||||
IndexView jandexIndex,
|
||||
List<String> 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<String> getManagedClassNames() {
|
||||
return allKnownClassNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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> ANY = createOrmDescriptor( Any.class );
|
||||
AnnotationDescriptor<AnyDiscriminator> ANY_DISCRIMINATOR = createOrmDescriptor( AnyDiscriminator.class );
|
||||
|
@ -159,7 +163,6 @@ public interface HibernateAnnotations {
|
|||
AnnotationDescriptor<Synchronize> SYNCHRONIZE = createOrmDescriptor( Synchronize.class );
|
||||
AnnotationDescriptor<Tables> TABLES = createOrmDescriptor( Tables.class );
|
||||
AnnotationDescriptor<Table> TABLE = createOrmDescriptor( Table.class, TABLES );
|
||||
AnnotationDescriptor<TenantId> TENANT_ID = createOrmDescriptor( TenantId.class );
|
||||
AnnotationDescriptor<TimeZoneColumn> TZ_COLUMN = createOrmDescriptor( TimeZoneColumn.class );
|
||||
AnnotationDescriptor<TimeZoneStorage> TZ_STORAGE = createOrmDescriptor( TimeZoneStorage.class );
|
||||
AnnotationDescriptor<Type> TYPE = createOrmDescriptor( Type.class );
|
||||
|
|
|
@ -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<CollectionTable> COLLECTION_TABLE = createOrmDescriptor( CollectionTable.class );
|
||||
AnnotationDescriptor<Column> COLUMN = createOrmDescriptor( Column.class );
|
||||
AnnotationDescriptor<ColumnResult> COLUMN_RESULT = createOrmDescriptor( ColumnResult.class );
|
||||
AnnotationDescriptor<ConstructorResult> CONSTRUCTOR_RESULT = createOrmDescriptor( ConstructorResult.class );
|
||||
AnnotationDescriptor<Converts> CONVERTS = createOrmDescriptor( Converts.class );
|
||||
AnnotationDescriptor<Convert> CONVERT = createOrmDescriptor( Convert.class, CONVERTS );
|
||||
AnnotationDescriptor<Converter> CONVERTER = createOrmDescriptor( Converter.class );
|
||||
|
|
|
@ -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<Object> tenantIdType = typeConfiguration
|
||||
.getBasicTypeRegistry()
|
||||
.getRegisteredType( returnedClassName );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<ConverterRegistration> jpaConverters;
|
||||
|
||||
private Map<String, SqlResultSetMappingRegistration> sqlResultSetMappingRegistrations;
|
||||
private Map<String, NamedQueryRegistration> namedQueryRegistrations;
|
||||
private Map<String, NamedNativeQueryRegistration> namedNativeQueryRegistrations;
|
||||
private Map<String, NamedStoredProcedureQueryRegistration> 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<String, SqlResultSetMappingRegistration> getSqlResultSetMappingRegistrations() {
|
||||
return sqlResultSetMappingRegistrations == null ? emptyMap() : sqlResultSetMappingRegistrations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, NamedQueryRegistration > getNamedQueryRegistrations() {
|
||||
return namedQueryRegistrations == null ? emptyMap() : namedQueryRegistrations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, NamedNativeQueryRegistration> getNamedNativeQueryRegistrations() {
|
||||
return namedNativeQueryRegistrations == null ? emptyMap() : namedNativeQueryRegistrations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, NamedStoredProcedureQueryRegistration> getNamedStoredProcedureQueryRegistrations() {
|
||||
return namedStoredProcedureQueryRegistrations== null ? emptyMap() : namedStoredProcedureQueryRegistrations;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// JavaTypeRegistration
|
||||
|
@ -581,7 +635,7 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations {
|
|||
}
|
||||
|
||||
sequenceGenerators.forEach( (generator) -> {
|
||||
final MutableAnnotationUsage<SequenceGenerator> annotationUsage = makeAnnotation( SequenceGenerator.class );
|
||||
final MutableAnnotationUsage<SequenceGenerator> 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 <A extends Annotation> MutableAnnotationUsage<A> makeAnnotation(Class<A> annotationType) {
|
||||
final AnnotationDescriptor<A> descriptor = descriptorRegistry.getDescriptor( annotationType );
|
||||
return new DynamicAnnotationUsage<>( descriptor );
|
||||
private <A extends Annotation> MutableAnnotationUsage<A> makeAnnotation(AnnotationDescriptor<A> annotationDescriptor) {
|
||||
return annotationDescriptor.createUsage( null, null );
|
||||
}
|
||||
|
||||
public void collectSequenceGenerator(AnnotationUsage<SequenceGenerator> 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<TableGenerator> annotationUsage = makeAnnotation( TableGenerator.class );
|
||||
final MutableAnnotationUsage<TableGenerator> 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<GenericGenerator> annotationUsage = makeAnnotation( GenericGenerator.class );
|
||||
final MutableAnnotationUsage<GenericGenerator> 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<JaxbSqlResultSetMappingImpl> jaxbSqlResultSetMappings) {
|
||||
if ( isEmpty( jaxbSqlResultSetMappings ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( sqlResultSetMappingRegistrations == null ) {
|
||||
sqlResultSetMappingRegistrations = new HashMap<>();
|
||||
}
|
||||
|
||||
jaxbSqlResultSetMappings.forEach( (jaxbMapping) -> {
|
||||
final MutableAnnotationUsage<SqlResultSetMapping> 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<JaxbEntityResultImpl> jaxbEntityResults,
|
||||
Consumer<List<AnnotationUsage<EntityResult>>> annotationListConsumer) {
|
||||
if ( jaxbEntityResults.isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<EntityResult>> entityResults = arrayList( jaxbEntityResults.size() );
|
||||
|
||||
for ( JaxbEntityResultImpl jaxbEntityResult : jaxbEntityResults ) {
|
||||
final MutableAnnotationUsage<EntityResult> 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<AnnotationUsage<FieldResult>> fieldResults = arrayList( jaxbEntityResult.getFieldResult().size() );
|
||||
entityResultAnnotation.setAttributeValue( "fields", fieldResults );
|
||||
|
||||
for ( JaxbFieldResultImpl jaxbFieldResult : jaxbEntityResult.getFieldResult() ) {
|
||||
final MutableAnnotationUsage<FieldResult> fieldResultAnnotation = makeAnnotation( JpaAnnotations.FIELD_RESULT );
|
||||
fieldResultAnnotation.setAttributeValue( "name", jaxbFieldResult.getName() );
|
||||
fieldResultAnnotation.setAttributeValue( "column", jaxbFieldResult.getColumn() );
|
||||
}
|
||||
}
|
||||
}
|
||||
annotationListConsumer.accept( entityResults );
|
||||
}
|
||||
|
||||
private void applyConstructorResults(
|
||||
List<JaxbConstructorResultImpl> jaxbConstructorResults,
|
||||
Consumer<List<AnnotationUsage<ConstructorResult>>> annotationListConsumer) {
|
||||
if ( isEmpty( jaxbConstructorResults ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<ConstructorResult>> results = arrayList( jaxbConstructorResults.size() );
|
||||
for ( JaxbConstructorResultImpl jaxbConstructorResult : jaxbConstructorResults ) {
|
||||
final MutableAnnotationUsage<ConstructorResult> 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<JaxbColumnResultImpl> jaxbColumnResults,
|
||||
Consumer<List<AnnotationUsage<ColumnResult>>> annotationListConsumer) {
|
||||
if ( isEmpty( jaxbColumnResults ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AnnotationUsage<ColumnResult>> columnResults = arrayList( jaxbColumnResults.size() );
|
||||
for ( JaxbColumnResultImpl jaxbColumn : jaxbColumnResults ) {
|
||||
final MutableAnnotationUsage<ColumnResult> 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<JaxbNamedQueryImpl> jaxbNamedQueries) {
|
||||
if ( isEmpty( jaxbNamedQueries ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( namedQueryRegistrations == null ) {
|
||||
namedQueryRegistrations = new HashMap<>();
|
||||
}
|
||||
|
||||
for ( JaxbNamedQueryImpl jaxbNamedQuery : jaxbNamedQueries ) {
|
||||
final MutableAnnotationUsage<NamedQuery> 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<AnnotationUsage<QueryHint>> hints = extractQueryHints( jaxbNamedQuery );
|
||||
queryAnnotation.setAttributeValue( "hints", hints );
|
||||
|
||||
if ( jaxbNamedQuery.isCacheable() == Boolean.TRUE ) {
|
||||
final MutableAnnotationUsage<QueryHint> cacheableHint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
cacheableHint.setAttributeValue( "name", AvailableHints.HINT_CACHEABLE );
|
||||
cacheableHint.setAttributeValue( "value", Boolean.TRUE.toString() );
|
||||
|
||||
if ( jaxbNamedQuery.getCacheMode() != null ) {
|
||||
final MutableAnnotationUsage<QueryHint> 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<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", AvailableHints.HINT_CACHE_REGION );
|
||||
hint.setAttributeValue( "value", jaxbNamedQuery.getCacheRegion() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( StringHelper.isNotEmpty( jaxbNamedQuery.getComment() ) ) {
|
||||
final MutableAnnotationUsage<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", AvailableHints.HINT_COMMENT );
|
||||
hint.setAttributeValue( "value", jaxbNamedQuery.getComment() );
|
||||
}
|
||||
|
||||
if ( jaxbNamedQuery.getFetchSize() != null ) {
|
||||
final MutableAnnotationUsage<QueryHint> 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<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", AvailableHints.HINT_READ_ONLY );
|
||||
hint.setAttributeValue( "value", Boolean.TRUE.toString() );
|
||||
}
|
||||
|
||||
if ( jaxbNamedQuery.getFlushMode() != null ) {
|
||||
final MutableAnnotationUsage<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", AvailableHints.HINT_FLUSH_MODE );
|
||||
hint.setAttributeValue( "value", jaxbNamedQuery.getFlushMode().name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectNamedNativeQueries(List<JaxbNamedNativeQueryImpl> namedNativeQueries) {
|
||||
if ( isEmpty( namedNativeQueries ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( namedNativeQueryRegistrations == null ) {
|
||||
namedNativeQueryRegistrations = new HashMap<>();
|
||||
}
|
||||
|
||||
for ( JaxbNamedNativeQueryImpl jaxbNamedQuery : namedNativeQueries ) {
|
||||
final MutableAnnotationUsage<NamedNativeQuery> 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<AnnotationUsage<QueryHint>> hints = extractQueryHints( jaxbNamedQuery );
|
||||
queryAnnotation.setAttributeValue( "hints", hints );
|
||||
|
||||
if ( jaxbNamedQuery.isCacheable() == Boolean.TRUE ) {
|
||||
final MutableAnnotationUsage<QueryHint> cacheableHint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
cacheableHint.setAttributeValue( "name", AvailableHints.HINT_CACHEABLE );
|
||||
cacheableHint.setAttributeValue( "value", Boolean.TRUE.toString() );
|
||||
|
||||
if ( jaxbNamedQuery.getCacheMode() != null ) {
|
||||
final MutableAnnotationUsage<QueryHint> 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<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", AvailableHints.HINT_CACHE_REGION );
|
||||
hint.setAttributeValue( "value", jaxbNamedQuery.getCacheRegion() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( jaxbNamedQuery.isReadOnly() == Boolean.TRUE ) {
|
||||
final MutableAnnotationUsage<QueryHint> 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<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", AvailableHints.HINT_COMMENT );
|
||||
hint.setAttributeValue( "value", jaxbNamedQuery.getComment() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectStoredProcedureQueries(List<JaxbNamedStoredProcedureQueryImpl> namedProcedureQueries) {
|
||||
if ( isEmpty( namedProcedureQueries ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( namedStoredProcedureQueryRegistrations == null ) {
|
||||
namedStoredProcedureQueryRegistrations = new HashMap<>();
|
||||
}
|
||||
|
||||
for ( JaxbNamedStoredProcedureQueryImpl jaxbQuery : namedProcedureQueries ) {
|
||||
final MutableAnnotationUsage<NamedStoredProcedureQuery> 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<ClassDetails> 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<AnnotationUsage<StoredProcedureParameter>> parameters = arrayList( jaxbQuery.getProcedureParameters().size() );
|
||||
queryAnnotation.setAttributeValue( "parameters", parameters );
|
||||
for ( JaxbStoredProcedureParameterImpl jaxbProcedureParameter : jaxbQuery.getProcedureParameters() ) {
|
||||
final MutableAnnotationUsage<StoredProcedureParameter> 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<AnnotationUsage<QueryHint>> extractQueryHints(JaxbNamedQueryBase jaxbQuery) {
|
||||
final List<AnnotationUsage<QueryHint>> hints = new ArrayList<>();
|
||||
for ( JaxbQueryHint jaxbHint : jaxbQuery.getHints() ) {
|
||||
final MutableAnnotationUsage<QueryHint> hint = makeAnnotation( JpaAnnotations.QUERY_HINT );
|
||||
hint.setAttributeValue( "name", jaxbHint.getName() );
|
||||
hint.setAttributeValue( "value", jaxbHint.getValue() );
|
||||
}
|
||||
return hints;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<GenericGenerator> configuration;
|
||||
|
||||
public GenericGeneratorRegistration(String name, AnnotationUsage<GenericGenerator> configuration) {
|
||||
this.name = name;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public AnnotationUsage<GenericGenerator> getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
public record GenericGeneratorRegistration(String name, AnnotationUsage<GenericGenerator> configuration) {
|
||||
}
|
||||
|
|
|
@ -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<ConverterRegistration> getJpaConverters();
|
||||
|
||||
Map<String, SqlResultSetMappingRegistration> getSqlResultSetMappingRegistrations();
|
||||
|
||||
Map<String, NamedQueryRegistration> getNamedQueryRegistrations();
|
||||
|
||||
Map<String, NamedNativeQueryRegistration> getNamedNativeQueryRegistrations();
|
||||
|
||||
Map<String, NamedStoredProcedureQueryRegistration> getNamedStoredProcedureQueryRegistrations();
|
||||
|
||||
// todo : named entity graphs
|
||||
// todo : named queries
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<EntityHierarchy> 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;
|
||||
|
|
|
@ -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<NamedNativeQuery> configuration) {
|
||||
public String getQueryString() {
|
||||
return configuration.getString( "query" );
|
||||
}
|
||||
|
||||
public ClassDetails getResultClass() {
|
||||
return configuration.getClassDetails( "resultClass" );
|
||||
}
|
||||
|
||||
public String getResultSetMapping() {
|
||||
return configuration.getString( "resultSetMapping" );
|
||||
}
|
||||
|
||||
public Map<String,String> getQueryHints() {
|
||||
final List<AnnotationUsage<QueryHint>> hints = configuration.getList( "hints" );
|
||||
if ( CollectionHelper.isEmpty( hints ) ) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final Map<String,String> result = CollectionHelper.linkedMapOfSize( hints.size() );
|
||||
for ( AnnotationUsage<QueryHint> hint : hints ) {
|
||||
result.put( hint.getString( "name" ), hint.getString( "value" ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -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<NamedQuery> configuration) {
|
||||
public String getQueryString() {
|
||||
return configuration.getString( "query" );
|
||||
}
|
||||
|
||||
public LockModeType getLockModeType() {
|
||||
return configuration.getEnum( "lockMode" );
|
||||
}
|
||||
|
||||
public Map<String,String> getQueryHints() {
|
||||
final List<AnnotationUsage<QueryHint>> hints = configuration.getList( "hints" );
|
||||
if ( CollectionHelper.isEmpty( hints ) ) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final Map<String,String> result = CollectionHelper.linkedMapOfSize( hints.size() );
|
||||
for ( AnnotationUsage<QueryHint> hint : hints ) {
|
||||
result.put( hint.getString( "name" ), hint.getString( "value" ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -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<NamedStoredProcedureQuery> configuration) {
|
||||
}
|
|
@ -15,20 +15,5 @@ import jakarta.persistence.SequenceGenerator;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SequenceGeneratorRegistration {
|
||||
private final String name;
|
||||
private final AnnotationUsage<SequenceGenerator> configuration;
|
||||
|
||||
public SequenceGeneratorRegistration(String name, AnnotationUsage<SequenceGenerator> configuration) {
|
||||
this.name = name;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public AnnotationUsage<SequenceGenerator> getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
public record SequenceGeneratorRegistration(String name, AnnotationUsage<SequenceGenerator> configuration) {
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public interface SingleAttributeKeyMapping extends KeyMapping {
|
|||
}
|
||||
|
||||
default ClassDetails getKeyType() {
|
||||
return getAttribute().getMember().getType();
|
||||
return getAttribute().getMember().getType().determineRawClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<SqlResultSetMapping> configuration) {
|
||||
}
|
|
@ -15,20 +15,5 @@ import jakarta.persistence.TableGenerator;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TableGeneratorRegistration {
|
||||
private final String name;
|
||||
private final AnnotationUsage<TableGenerator> configuration;
|
||||
|
||||
public TableGeneratorRegistration(String name, AnnotationUsage<TableGenerator> configuration) {
|
||||
this.name = name;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public AnnotationUsage<TableGenerator> getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
public record TableGeneratorRegistration(String name, AnnotationUsage<TableGenerator> configuration) {
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() ) ) {
|
||||
// <id/>
|
||||
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 {
|
||||
// <embedded-id/>
|
||||
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 {
|
|||
// <natural-id/>
|
||||
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 {
|
|||
// <tenant-id>
|
||||
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<Extends> extendsAnn = XmlProcessingHelper.makeAnnotation(
|
||||
Extends.class,
|
||||
final MutableAnnotationUsage<Extends> extendsAnn = HibernateAnnotations.EXTENDS.createUsage(
|
||||
classDetails,
|
||||
xmlDocumentContext
|
||||
xmlDocumentContext.getModelBuildingContext()
|
||||
);
|
||||
extendsAnn.setAttributeValue( "superType", jaxbEntity.getExtends() );
|
||||
}
|
||||
|
|
|
@ -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<DiscriminatorFormula> 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<DiscriminatorFormula> discriminatorFormulaAnn = HibernateAnnotations.DISCRIMINATOR_FORMULA.createUsage(
|
||||
target,
|
||||
xmlDocumentContext.getModelBuildingContext()
|
||||
);
|
||||
|
||||
discriminatorFormulaAnn.setAttributeValue( "value", jaxbDiscriminatorFormula.getFragment() );
|
||||
discriminatorFormulaAnn.setAttributeValue( "discriminatorType", jaxbDiscriminatorFormula.getDiscriminatorType() );
|
||||
|
||||
if ( jaxbDiscriminatorFormula.isForceSelection() ) {
|
||||
final MutableAnnotationUsage<DiscriminatorOptions> existingOptionsAnnotation = (MutableAnnotationUsage<DiscriminatorOptions>) target.getAnnotationUsage( DiscriminatorOptions.class );
|
||||
final MutableAnnotationUsage<DiscriminatorOptions> optionsAnnotation = existingOptionsAnnotation != null
|
||||
? existingOptionsAnnotation
|
||||
: HibernateAnnotations.DISCRIMINATOR_OPTIONS.createUsage( target, xmlDocumentContext.getModelBuildingContext() );
|
||||
optionsAnnotation.setAttributeValue( "force", true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue