From b7e7b77e26e8308f3e2976db3bb6a16a5d5b1610 Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Mon, 20 Nov 2023 16:54:48 +0100 Subject: [PATCH] #34 - Create AnnotationUsage for one-to-many attributes --- .../xml/internal/XmlAnnotationHelper.java | 405 ++++++++++++++---- .../attr/CommonPluralAttributeProcessing.java | 112 +++-- .../ElementCollectionAttributeProcessing.java | 109 +++-- .../attr/ManyToOneAttributeProcessing.java | 85 +--- .../attr/OneToManyAttributeProcessing.java | 97 ++++- .../xml/internal/db/ColumnProcessing.java | 26 +- .../models/orm/xml/attr/ManyToOneTests.java | 9 +- .../orm/xml/dynamic/DynamicModelTests.java | 75 +++- .../models/orm/xml/dynamic/Employee.java | 6 + .../mappings/dynamic/dynamic-plurals.xml | 29 ++ 10 files changed, 660 insertions(+), 293 deletions(-) create mode 100644 src/test/resources/mappings/dynamic/dynamic-plurals.xml diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/XmlAnnotationHelper.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/XmlAnnotationHelper.java index 4139b1e..0854322 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/XmlAnnotationHelper.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/XmlAnnotationHelper.java @@ -11,6 +11,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.function.Function; @@ -18,6 +19,8 @@ import org.hibernate.AnnotationException; import org.hibernate.annotations.AttributeAccessor; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.CollectionType; import org.hibernate.annotations.Filter; @@ -42,6 +45,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributeOverrideImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbBasicMapping; import org.hibernate.boot.jaxb.mapping.spi.JaxbCachingImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbCascadeTypeImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbCheckConstraintImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionIdImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionUserTypeImpl; @@ -57,18 +61,28 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbHbmFilterImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbIdClassImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbIdImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbIndexImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinColumnImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinTableImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback; import org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallbackContainer; import org.hibernate.boot.jaxb.mapping.spi.JaxbLobImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyColumnImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyJoinColumnImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbNationalizedImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbNaturalId; import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGeneratorImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGeneratorImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbTableImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbUniqueConstraintImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbUserTypeImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbUuidGeneratorImpl; -import org.hibernate.boot.models.categorize.xml.spi.PersistenceUnitMetadata; +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.categorize.spi.JpaEventListener; +import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; +import org.hibernate.boot.models.categorize.xml.internal.db.ColumnProcessing; import org.hibernate.boot.models.categorize.xml.spi.XmlDocumentContext; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.internal.util.KeyedConsumer; @@ -79,9 +93,6 @@ import org.hibernate.models.internal.MutableAnnotationUsage; import org.hibernate.models.internal.MutableClassDetails; import org.hibernate.models.internal.MutableMemberDetails; -import org.hibernate.boot.models.categorize.spi.JpaEventListener; -import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; -import org.hibernate.boot.models.categorize.xml.internal.db.ColumnProcessing; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.ClassDetails; @@ -106,9 +117,14 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.IdClass; +import jakarta.persistence.Index; import jakarta.persistence.Inheritance; import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinColumns; +import jakarta.persistence.JoinTable; import jakarta.persistence.Lob; +import jakarta.persistence.MapKeyColumn; +import jakarta.persistence.MapKeyJoinColumn; import jakarta.persistence.PostLoad; import jakarta.persistence.PostPersist; import jakarta.persistence.PostRemove; @@ -121,6 +137,7 @@ import jakarta.persistence.TableGenerator; import jakarta.persistence.Temporal; import jakarta.persistence.TemporalType; +import jakarta.persistence.UniqueConstraint; import static java.util.Collections.emptyList; import static org.hibernate.internal.util.NullnessHelper.coalesce; @@ -184,62 +201,68 @@ public static MutableAnnotationUsage applyJoinColumn( return null; } - return createJoinColumnAnnotation( jaxbJoinColumn, memberDetails, xmlDocumentContext ); + return createJoinColumnAnnotation( jaxbJoinColumn, memberDetails, JoinColumn.class, xmlDocumentContext ); } - public static MutableAnnotationUsage createJoinColumnAnnotation( - JaxbJoinColumnImpl jaxbJoinColumn, + public static MutableAnnotationUsage createJoinColumnAnnotation( + JaxbColumnJoined jaxbJoinColumn, MutableMemberDetails memberDetails, + Class annotationType, XmlDocumentContext xmlDocumentContext) { - final MutableAnnotationUsage joinColumnAnn = XmlProcessingHelper.getOrMakeAnnotation( JoinColumn.class, memberDetails, xmlDocumentContext ); - final AnnotationDescriptor joinColumnDescriptor = xmlDocumentContext + final MutableAnnotationUsage joinColumnAnn = XmlProcessingHelper.getOrMakeAnnotation( annotationType, memberDetails, xmlDocumentContext ); + final AnnotationDescriptor joinColumnDescriptor = xmlDocumentContext .getModelBuildingContext() .getAnnotationDescriptorRegistry() - .getDescriptor( JoinColumn.class ); + .getDescriptor( annotationType ); + + ColumnProcessing.applyColumnDetails( jaxbJoinColumn, memberDetails, joinColumnAnn, xmlDocumentContext ); - applyOr( jaxbJoinColumn, JaxbJoinColumnImpl::getName, "name", joinColumnAnn, joinColumnDescriptor ); - applyOr( jaxbJoinColumn, JaxbJoinColumnImpl::getTable, "table", joinColumnAnn, joinColumnDescriptor ); - applyOr( jaxbJoinColumn, JaxbJoinColumnImpl::getReferencedColumnName, "referencedColumnName", joinColumnAnn, joinColumnDescriptor ); - applyOr( jaxbJoinColumn, JaxbJoinColumnImpl::getOptions, "options", joinColumnAnn, joinColumnDescriptor ); - applyOr( jaxbJoinColumn, JaxbJoinColumnImpl::getComment, "comment", joinColumnAnn, joinColumnDescriptor ); - applyOr( jaxbJoinColumn, JaxbJoinColumnImpl::getColumnDefinition, "columnDefinition", joinColumnAnn, joinColumnDescriptor ); + applyOr( jaxbJoinColumn, JaxbColumnJoined::getReferencedColumnName, "referencedColumnName", joinColumnAnn, joinColumnDescriptor ); final JaxbForeignKeyImpl jaxbForeignKey = jaxbJoinColumn.getForeignKey(); - final MutableAnnotationUsage foreignKeyAnn = XmlProcessingHelper.getOrMakeAnnotation( ForeignKey.class, memberDetails, xmlDocumentContext ); - final AnnotationDescriptor foreignKeyDescriptor = xmlDocumentContext - .getModelBuildingContext() - .getAnnotationDescriptorRegistry() - .getDescriptor( ForeignKey.class ); - joinColumnAnn.setAttributeValue( "foreignKey", foreignKeyAnn ); + if ( jaxbForeignKey != null ) { + joinColumnAnn.setAttributeValue( + "foreignKey", + createForeignKeyAnnotation( jaxbForeignKey, memberDetails, xmlDocumentContext ) + ); + } - applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getName, "name", foreignKeyAnn, foreignKeyDescriptor ); - applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getConstraintMode, "value", foreignKeyAnn, foreignKeyDescriptor ); - applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getForeignKeyDefinition, "foreignKeyDefinition", foreignKeyAnn, foreignKeyDescriptor ); - applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getOptions, "options", foreignKeyAnn, foreignKeyDescriptor ); + return joinColumnAnn; + } - if ( CollectionHelper.isNotEmpty( jaxbJoinColumn.getCheckConstraints() ) ) { - final List> constraints = new ArrayList<>( jaxbJoinColumn.getCheckConstraints().size() ); - joinColumnAnn.setAttributeValue( "check", constraints ); - for ( int i = 0; i < jaxbJoinColumn.getCheckConstraints().size(); i++ ) { - final JaxbCheckConstraintImpl jaxbCheckConstraint = jaxbJoinColumn.getCheckConstraints().get( i ); - final MutableAnnotationUsage checkConstraintAnn = XmlProcessingHelper.getOrMakeAnnotation( CheckConstraint.class, memberDetails, xmlDocumentContext ); - final AnnotationDescriptor checkConstraintDescriptor = xmlDocumentContext - .getModelBuildingContext() - .getAnnotationDescriptorRegistry() - .getDescriptor( CheckConstraint.class ); - constraints.add( checkConstraintAnn ); - - applyOr( jaxbCheckConstraint, JaxbCheckConstraintImpl::getName, "name", checkConstraintAnn, checkConstraintDescriptor ); - applyOr( jaxbCheckConstraint, JaxbCheckConstraintImpl::getConstraint, "constraint", checkConstraintAnn, checkConstraintDescriptor ); - applyOr( jaxbCheckConstraint, JaxbCheckConstraintImpl::getOptions, "options", checkConstraintAnn, checkConstraintDescriptor ); - } + public static void applyJoinColumns( + List jaxbJoinColumns, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( CollectionHelper.isEmpty( jaxbJoinColumns ) ) { + return; + } + + if ( jaxbJoinColumns.size() == 1 ) { + XmlAnnotationHelper.applyJoinColumn( jaxbJoinColumns.get( 0 ), memberDetails, xmlDocumentContext ); } else { - final MutableAnnotationUsage checkConstraintAnn = XmlProcessingHelper.getOrMakeAnnotation( CheckConstraint.class, memberDetails, xmlDocumentContext ); - joinColumnAnn.setAttributeValue( "check", List.of( checkConstraintAnn ) ); + final MutableAnnotationUsage columnsAnn = XmlProcessingHelper.makeAnnotation( + JoinColumns.class, + memberDetails, + xmlDocumentContext + ); + columnsAnn.setAttributeValue( "value", createJoinColumns( jaxbJoinColumns, memberDetails, xmlDocumentContext ) ); } + } - return joinColumnAnn; + public static List> createJoinColumns( + List jaxbJoinColumns, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( CollectionHelper.isEmpty( jaxbJoinColumns ) ) { + return Collections.emptyList(); + } + final List> joinColumns = new ArrayList<>( jaxbJoinColumns.size() ); + jaxbJoinColumns.forEach( jaxbJoinColumn -> { + joinColumns.add( applyJoinColumn( jaxbJoinColumn, memberDetails, xmlDocumentContext ) ); + } ); + return joinColumns; } public static void applyOr( @@ -362,6 +385,227 @@ public static void applyCollectionId( applyOr( jaxbCollectionId, JaxbCollectionIdImpl::getGenerator, "generator", collectionIdAnn, collectionIdDescriptor ); } + public static void applyForeignKey( + JaxbForeignKeyImpl jaxbForeignKey, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( jaxbForeignKey == null ) { + return; + } + + createForeignKeyAnnotation( jaxbForeignKey, memberDetails, xmlDocumentContext ); + } + + public static MutableAnnotationUsage createForeignKeyAnnotation( + JaxbForeignKeyImpl jaxbForeignKey, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + final MutableAnnotationUsage foreignKeyAnn = XmlProcessingHelper.getOrMakeAnnotation( ForeignKey.class, memberDetails, xmlDocumentContext ); + final AnnotationDescriptor foreignKeyDescriptor = xmlDocumentContext + .getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( ForeignKey.class ); + + applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getName, "name", foreignKeyAnn, foreignKeyDescriptor ); + applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getConstraintMode, "value", foreignKeyAnn, foreignKeyDescriptor ); + applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getForeignKeyDefinition, "foreignKeyDefinition", foreignKeyAnn, foreignKeyDescriptor ); + applyOr( jaxbForeignKey, JaxbForeignKeyImpl::getOptions, "options", foreignKeyAnn, foreignKeyDescriptor ); + + return foreignKeyAnn; + } + + public static void applyMapKeyColumn( + JaxbMapKeyColumnImpl jaxbMapKeyColumn, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( jaxbMapKeyColumn == null ) { + return; + } + + final MutableAnnotationUsage columnAnn = XmlProcessingHelper.getOrMakeAnnotation( MapKeyColumn.class, memberDetails, xmlDocumentContext ); + + ColumnProcessing.applyColumnDetails( jaxbMapKeyColumn, memberDetails, columnAnn, xmlDocumentContext ); + } + + public static void applyMapKeyJoinColumn( + JaxbMapKeyJoinColumnImpl jaxbMapKeyJoinColumn, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( jaxbMapKeyJoinColumn == null ) { + return; + } + + createJoinColumnAnnotation( jaxbMapKeyJoinColumn, memberDetails, MapKeyJoinColumn.class, xmlDocumentContext ); + } + + public static void applyCascading( + JaxbCascadeTypeImpl jaxbCascadeType, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( jaxbCascadeType == null ) { + return; + } + + // We always use Hibernate specific org.hibernate.annotations.CascadeType since + // it offers additional options than jakarta.persistence.CascadeType + final List cascadeTypes = new ArrayList<>(); + if ( jaxbCascadeType.getCascadeAll() != null ) { + cascadeTypes.add( CascadeType.ALL ); + } + if ( jaxbCascadeType.getCascadePersist() != null ) { + cascadeTypes.add( CascadeType.PERSIST ); + } + if ( jaxbCascadeType.getCascadeMerge() != null ) { + cascadeTypes.add( CascadeType.MERGE ); + } + if ( jaxbCascadeType.getCascadeRemove() != null ) { + cascadeTypes.add( CascadeType.REMOVE ); + } + if ( jaxbCascadeType.getCascadeRefresh() != null ) { + cascadeTypes.add( CascadeType.REFRESH ); + } + if ( jaxbCascadeType.getCascadeDetach() != null ) { + cascadeTypes.add( CascadeType.DETACH ); + } + if ( jaxbCascadeType.getCascadeReplicate() != null ) { + //noinspection deprecation + cascadeTypes.add( CascadeType.REPLICATE ); + } + if ( jaxbCascadeType.getCascadeLock() != null ) { + cascadeTypes.add( CascadeType.LOCK ); + } + + if ( !cascadeTypes.isEmpty() ) { + XmlProcessingHelper.getOrMakeAnnotation( Cascade.class, memberDetails, xmlDocumentContext ) + .setAttributeValue( "value", cascadeTypes ); + } + } + + public static void applyUniqueConstraints( + List jaxbUniqueConstraints, + MutableAnnotationTarget target, + MutableAnnotationUsage annotationUsage, + XmlDocumentContext xmlDocumentContext) { + if ( CollectionHelper.isEmpty( jaxbUniqueConstraints ) ) { + return; + } + + final List> uniqueConstraints = new ArrayList<>( jaxbUniqueConstraints.size() ); + jaxbUniqueConstraints.forEach( jaxbUniqueConstraint -> { + final MutableAnnotationUsage uniqueConstraintAnn = XmlProcessingHelper.getOrMakeAnnotation( + UniqueConstraint.class, + target, + xmlDocumentContext + ); + final AnnotationDescriptor uniqueConstraintDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( UniqueConstraint.class ); + applyOr( jaxbUniqueConstraint, JaxbUniqueConstraintImpl::getName, "name", uniqueConstraintAnn, uniqueConstraintDescriptor ); + uniqueConstraintAnn.setAttributeValue( "columnNames", jaxbUniqueConstraint.getColumnName() ); + uniqueConstraints.add( uniqueConstraintAnn ); + } ); + + annotationUsage.setAttributeValue( "uniqueConstraints", uniqueConstraints ); + } + + public static void applyIndexes( + List jaxbIndexes, + MutableAnnotationTarget target, + MutableAnnotationUsage annotationUsage, + XmlDocumentContext xmlDocumentContext) { + if ( CollectionHelper.isEmpty( jaxbIndexes ) ) { + return; + } + + final List> indexes = new ArrayList<>( jaxbIndexes.size() ); + jaxbIndexes.forEach( jaxbIndex -> { + final MutableAnnotationUsage indexAnn = XmlProcessingHelper.getOrMakeAnnotation( + Index.class, + target, + xmlDocumentContext + ); + final AnnotationDescriptor indexDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( Index.class ); + applyOr( jaxbIndex, JaxbIndexImpl::getName, "name", indexAnn, indexDescriptor ); + applyOr( jaxbIndex, JaxbIndexImpl::getColumnList, "columnList", indexAnn, indexDescriptor ); + applyOr( jaxbIndex, JaxbIndexImpl::isUnique, "unique", indexAnn, indexDescriptor ); + indexes.add( indexAnn ); + } ); + + annotationUsage.setAttributeValue( "indexes", indexes ); + } + + public static MutableAnnotationUsage applyJoinTable( + JaxbJoinTableImpl jaxbJoinTable, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( jaxbJoinTable == null ) { + return null; + } + + final MutableAnnotationUsage joinTableAnn = XmlProcessingHelper.getOrMakeAnnotation( + JoinTable.class, + memberDetails, + xmlDocumentContext + ); + final AnnotationDescriptor joinTableDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( JoinTable.class ); + + applyOr( jaxbJoinTable, JaxbJoinTableImpl::getName, "name", joinTableAnn, joinTableDescriptor ); + applyTableAttributes( jaxbJoinTable, memberDetails, joinTableAnn, joinTableDescriptor, xmlDocumentContext ); + + final List joinColumns = jaxbJoinTable.getJoinColumn(); + if ( CollectionHelper.isNotEmpty( joinColumns ) ) { + joinTableAnn.setAttributeValue( "joinColumns", createJoinColumns( joinColumns, memberDetails, xmlDocumentContext ) ); + } + + final List inverseJoinColumns = jaxbJoinTable.getInverseJoinColumn(); + if ( CollectionHelper.isNotEmpty( inverseJoinColumns ) ) { + joinTableAnn.setAttributeValue( "inverseJoinColumns", createJoinColumns( inverseJoinColumns, memberDetails, xmlDocumentContext ) ); + } + + if ( jaxbJoinTable.getForeignKey() != null ) { + joinTableAnn.setAttributeValue( + "foreignKey", + createForeignKeyAnnotation( jaxbJoinTable.getForeignKey(), memberDetails, xmlDocumentContext ) + ); + } + if ( jaxbJoinTable.getInverseForeignKey() != null ) { + joinTableAnn.setAttributeValue( + "inverseForeignKey", + createForeignKeyAnnotation( jaxbJoinTable.getInverseForeignKey(), memberDetails, xmlDocumentContext ) + ); + } + + applyUniqueConstraints( jaxbJoinTable.getUniqueConstraint(), memberDetails, joinTableAnn, xmlDocumentContext ); + + applyIndexes( jaxbJoinTable.getIndex(), memberDetails, joinTableAnn, xmlDocumentContext ); + + return joinTableAnn; + } + + public static void applyCheckConstraints( + JaxbCheckable jaxbCheckable, + MutableAnnotationTarget target, + MutableAnnotationUsage annotationUsage, + XmlDocumentContext xmlDocumentContext) { + if ( CollectionHelper.isNotEmpty( jaxbCheckable.getCheckConstraints() ) ) { + final List> checks = new ArrayList<>( jaxbCheckable.getCheckConstraints().size() ); + final AnnotationDescriptor checkConstraintDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( CheckConstraint.class ); + for ( JaxbCheckConstraintImpl jaxbCheck : jaxbCheckable.getCheckConstraints() ) { + final MutableAnnotationUsage checkAnn = XmlProcessingHelper.getOrMakeAnnotation( CheckConstraint.class, target, xmlDocumentContext ); + applyOr( jaxbCheck, JaxbCheckConstraintImpl::getName, "name", checkAnn, checkConstraintDescriptor ); + applyOr( jaxbCheck, JaxbCheckConstraintImpl::getConstraint, "constraint", checkAnn, checkConstraintDescriptor ); + applyOr( jaxbCheck, JaxbCheckConstraintImpl::getOptions, "options", checkAnn, checkConstraintDescriptor ); + checks.add( checkAnn ); + } + annotationUsage.setAttributeValue( "check", checks ); + } + } public static void applyTargetClass( String name, @@ -475,8 +719,8 @@ public static void applyTableGenerator( annotationUsage.setAttributeValue( "pkColumnValue", jaxbGenerator.getPkColumnValue() ); annotationUsage.setAttributeValue( "initialValue", jaxbGenerator.getInitialValue() ); annotationUsage.setAttributeValue( "allocationSize", jaxbGenerator.getInitialValue() ); - // todo : uniqueConstraints - // todo : indexes + applyUniqueConstraints( jaxbGenerator.getUniqueConstraint(), memberDetails, annotationUsage, xmlDocumentContext ); + applyIndexes( jaxbGenerator.getIndex(), memberDetails, annotationUsage, xmlDocumentContext ); } public static void applyUuidGenerator( @@ -524,14 +768,6 @@ public static void applyAssociationOverrides( List jaxbOverrides, MutableMemberDetails memberDetails, XmlDocumentContext xmlDocumentContext) { - applyAssociationOverrides( jaxbOverrides, memberDetails, null, xmlDocumentContext ); - } - - public static void applyAssociationOverrides( - List jaxbOverrides, - MutableMemberDetails memberDetails, - String namePrefix, - XmlDocumentContext xmlDocumentContext) { if ( CollectionHelper.isEmpty( jaxbOverrides ) ) { return; } @@ -543,10 +779,23 @@ public static void applyAssociationOverrides( xmlDocumentContext ); memberDetails.addAnnotationUsage( annotationUsage ); - annotationUsage.setAttributeValue( "name", prefixIfNotAlready( jaxbOverride.getName(), namePrefix ) ); - // todo : join columns - // todo : join table - // todo : foreign key + annotationUsage.setAttributeValue( "name", jaxbOverride.getName() ); + final List joinColumns = jaxbOverride.getJoinColumns(); + if ( CollectionHelper.isNotEmpty( joinColumns)) { + annotationUsage.setAttributeValue( "joinColumns", createJoinColumns( joinColumns, memberDetails, xmlDocumentContext ) ); + } + if ( jaxbOverride.getJoinTable() != null ) { + annotationUsage.setAttributeValue( + "joinTable", + applyJoinTable( jaxbOverride.getJoinTable(), memberDetails, xmlDocumentContext ) + ); + } + if ( jaxbOverride.getForeignKeys() != null ) { + annotationUsage.setAttributeValue( + "foreignKey", + createForeignKeyAnnotation( jaxbOverride.getForeignKeys(), memberDetails, xmlDocumentContext ) + ); + } } ); } @@ -598,12 +847,12 @@ public static void applyTable( MutableAnnotationTarget target, XmlDocumentContext xmlDocumentContext) { final MutableAnnotationUsage tableAnn = XmlProcessingHelper.makeAnnotation( Table.class, target, xmlDocumentContext ); - target.addAnnotationUsage( tableAnn ); - - applyTableAttributes( tableAnn, jaxbTable, xmlDocumentContext ); + final AnnotationDescriptor
tableDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( Table.class ); - // todo : uniqueConstraints - // todo : indexes + applyOr( jaxbTable, JaxbTableImpl::getName, "name", tableAnn, tableDescriptor ); + applyTableAttributes( jaxbTable, target, tableAnn, tableDescriptor, xmlDocumentContext ); } public static void applyTableOverride( @@ -615,21 +864,25 @@ public static void applyTableOverride( } final MutableAnnotationUsage
tableAnn = XmlProcessingHelper.getOrMakeAnnotation( Table.class, target, xmlDocumentContext ); + final AnnotationDescriptor
tableDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( Table.class ); - applyTableAttributes( tableAnn, jaxbTable, xmlDocumentContext ); - - // todo : uniqueConstraints - // todo : indexes + applyOr( jaxbTable, JaxbTableImpl::getName, "name", tableAnn, tableDescriptor ); + applyTableAttributes( jaxbTable, target, tableAnn, tableDescriptor, xmlDocumentContext ); } - private static void applyTableAttributes( - MutableAnnotationUsage
tableAnn, - JaxbTableImpl jaxbTable, + public static void applyTableAttributes( + JaxbTableMapping jaxbTable, + MutableAnnotationTarget target, + MutableAnnotationUsage tableAnn, + AnnotationDescriptor annotationDescriptor, XmlDocumentContext xmlDocumentContext) { - final PersistenceUnitMetadata persistenceUnitMetadata = xmlDocumentContext.getPersistenceUnitMetadata(); - applyAttributeIfSpecified( tableAnn, "name", jaxbTable.getName() ); - applyAttributeIfSpecified( tableAnn, "catalog", jaxbTable.getCatalog(), persistenceUnitMetadata.getDefaultCatalog() ); - applyAttributeIfSpecified( tableAnn, "schema", jaxbTable.getSchema(), persistenceUnitMetadata.getDefaultSchema() ); + applyOr( jaxbTable, JaxbTableMapping::getCatalog, "catalog", tableAnn, annotationDescriptor ); + applyOr( jaxbTable, JaxbTableMapping::getSchema, "schema", tableAnn, annotationDescriptor ); + applyOr( jaxbTable, JaxbTableMapping::getOptions, "options", tableAnn, annotationDescriptor ); + applyOr( jaxbTable, JaxbTableMapping::getComment, "comment", tableAnn, annotationDescriptor ); + applyCheckConstraints( jaxbTable, target, tableAnn, xmlDocumentContext ); } private static void applyAttributeIfSpecified( @@ -889,7 +1142,7 @@ public static void applyFilter( applyFilter( jaxbFilter, target, Filter.class, xmlDocumentContext ); } - static void applyJoinTableFilter( + public static void applyJoinTableFilter( JaxbHbmFilterImpl jaxbFilter, MutableAnnotationTarget target, XmlDocumentContext xmlDocumentContext) { diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/CommonPluralAttributeProcessing.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/CommonPluralAttributeProcessing.java index 8819d32..0afcf22 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/CommonPluralAttributeProcessing.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/CommonPluralAttributeProcessing.java @@ -16,6 +16,7 @@ import org.hibernate.annotations.SortNatural; import org.hibernate.boot.internal.CollectionClassification; import org.hibernate.boot.internal.LimitedCollectionClassification; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbOrderColumnImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute; import org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper; @@ -23,6 +24,7 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.models.internal.MutableAnnotationUsage; import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; import org.hibernate.models.spi.SourceModelBuildingContext; @@ -34,8 +36,8 @@ import jakarta.persistence.OrderBy; import jakarta.persistence.OrderColumn; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyOr; import static org.hibernate.boot.models.categorize.xml.internal.XmlProcessingHelper.getOrMakeAnnotation; -import static org.hibernate.boot.models.categorize.xml.internal.XmlProcessingHelper.setIf; /** * @author Marco Belladelli @@ -44,12 +46,12 @@ public class CommonPluralAttributeProcessing { public static void applyPluralAttributeStructure( JaxbPluralAttribute jaxbPluralAttribute, MutableMemberDetails memberDetails, - XmlDocumentContext documentContext) { - final SourceModelBuildingContext buildingContext = documentContext.getModelBuildingContext(); + XmlDocumentContext xmlDocumentContext) { + final SourceModelBuildingContext buildingContext = xmlDocumentContext.getModelBuildingContext(); final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); if ( jaxbPluralAttribute.getFetchMode() != null ) { - final MutableAnnotationUsage fetchAnn = getOrMakeAnnotation( Fetch.class, memberDetails, documentContext ); + final MutableAnnotationUsage fetchAnn = getOrMakeAnnotation( Fetch.class, memberDetails, xmlDocumentContext ); fetchAnn.setAttributeValue( "value", jaxbPluralAttribute.getFetchMode() ); } @@ -57,80 +59,74 @@ public static void applyPluralAttributeStructure( final MutableAnnotationUsage collectionClassificationAnn = getOrMakeAnnotation( CollectionClassification.class, memberDetails, - documentContext + xmlDocumentContext ); - setIf( jaxbPluralAttribute.getClassification(), "value", collectionClassificationAnn ); + collectionClassificationAnn.setAttributeValue( "value", jaxbPluralAttribute.getClassification() ); if ( jaxbPluralAttribute.getClassification() == LimitedCollectionClassification.BAG ) { - getOrMakeAnnotation( Bag.class, memberDetails, documentContext ); + getOrMakeAnnotation( Bag.class, memberDetails, xmlDocumentContext ); } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // collection-structure - XmlAnnotationHelper.applyCollectionUserType( jaxbPluralAttribute.getCollectionType(), memberDetails, documentContext ); + XmlAnnotationHelper.applyCollectionUserType( jaxbPluralAttribute.getCollectionType(), memberDetails, xmlDocumentContext ); - XmlAnnotationHelper.applyCollectionId( jaxbPluralAttribute.getCollectionId(), memberDetails, documentContext ); + XmlAnnotationHelper.applyCollectionId( jaxbPluralAttribute.getCollectionId(), memberDetails, xmlDocumentContext ); if ( StringHelper.isNotEmpty( jaxbPluralAttribute.getOrderBy() ) ) { final MutableAnnotationUsage orderByAnn = getOrMakeAnnotation( OrderBy.class, memberDetails, - documentContext + xmlDocumentContext ); orderByAnn.setAttributeValue( "value", jaxbPluralAttribute.getOrderBy() ); } - final JaxbOrderColumnImpl orderColumn = jaxbPluralAttribute.getOrderColumn(); - if ( orderColumn != null ) { - final MutableAnnotationUsage orderByAnn = getOrMakeAnnotation( - OrderColumn.class, - memberDetails, - documentContext - ); - setIf( orderColumn.getName(), "name", orderByAnn ); - setIf( orderColumn.isNullable(), "nullable", orderByAnn ); - setIf( orderColumn.isInsertable(), "insertable", orderByAnn ); - setIf( orderColumn.isUpdatable(), "updatable", orderByAnn ); - setIf( orderColumn.getColumnDefinition(), "columnDefinition", orderByAnn ); - } + applyOrderColumn( jaxbPluralAttribute, memberDetails, xmlDocumentContext ); if ( StringHelper.isNotEmpty( jaxbPluralAttribute.getSort() ) ) { final MutableAnnotationUsage sortAnn = getOrMakeAnnotation( SortComparator.class, memberDetails, - documentContext + xmlDocumentContext ); final ClassDetails comparatorClassDetails = classDetailsRegistry.resolveClassDetails( jaxbPluralAttribute.getSort() ); sortAnn.setAttributeValue( "value", comparatorClassDetails ); } if ( jaxbPluralAttribute.getSortNatural() != null ) { - getOrMakeAnnotation( SortNatural.class, memberDetails, documentContext ); + getOrMakeAnnotation( SortNatural.class, memberDetails, xmlDocumentContext ); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // map-key if ( jaxbPluralAttribute.getMapKey() != null ) { - final MutableAnnotationUsage mapKeyAnn = getOrMakeAnnotation( MapKey.class, memberDetails, documentContext ); - setIf( jaxbPluralAttribute.getMapKey().getName(), "name", mapKeyAnn ); + final MutableAnnotationUsage mapKeyAnn = getOrMakeAnnotation( MapKey.class, memberDetails, xmlDocumentContext ); + applyOr( + jaxbPluralAttribute.getMapKey(), + JaxbMapKeyImpl::getName, + "name", + mapKeyAnn, + buildingContext.getAnnotationDescriptorRegistry().getDescriptor( MapKey.class ) + ); } if ( jaxbPluralAttribute.getMapKeyClass() != null ) { final ClassDetails mapKeyClass = classDetailsRegistry.resolveClassDetails( jaxbPluralAttribute.getMapKeyClass().getClazz() ); - getOrMakeAnnotation( MapKeyClass.class, memberDetails, documentContext ).setAttributeValue( "value", mapKeyClass ); + getOrMakeAnnotation( MapKeyClass.class, memberDetails, xmlDocumentContext ).setAttributeValue( "value", mapKeyClass ); } if ( jaxbPluralAttribute.getMapKeyTemporal() != null ) { - getOrMakeAnnotation( MapKeyTemporal.class, memberDetails, documentContext ).setAttributeValue( + getOrMakeAnnotation( MapKeyTemporal.class, memberDetails, xmlDocumentContext ).setAttributeValue( "value", jaxbPluralAttribute.getMapKeyTemporal() ); } if ( jaxbPluralAttribute.getMapKeyEnumerated() != null ) { - getOrMakeAnnotation( MapKeyEnumerated.class, memberDetails, documentContext ).setAttributeValue( + getOrMakeAnnotation( MapKeyEnumerated.class, memberDetails, xmlDocumentContext ).setAttributeValue( "value", jaxbPluralAttribute.getMapKeyEnumerated() ); @@ -140,35 +136,59 @@ public static void applyPluralAttributeStructure( jaxbPluralAttribute.getMapKeyAttributeOverrides(), memberDetails, "key", - documentContext + xmlDocumentContext ); jaxbPluralAttribute.getMapKeyConverts().forEach( (jaxbConvert) -> { - XmlAnnotationHelper.applyConvert( jaxbConvert, memberDetails, "key", documentContext ); + XmlAnnotationHelper.applyConvert( jaxbConvert, memberDetails, "key", xmlDocumentContext ); } ); + XmlAnnotationHelper.applyMapKeyColumn( jaxbPluralAttribute.getMapKeyColumn(), memberDetails, xmlDocumentContext ); - // todo : map-key-column, map-key-join-column, map-key-foreign-key -// XmlAnnotationHelper.applyMapKeyColumn( jaxbPluralAttribute.getMapKeyColumn(), memberDetails, buildingContext ); -// -// jaxbPluralAttribute.getMapKeyJoinColumns().forEach( jaxbMapKeyJoinColumn -> { -// XmlAnnotationHelper.applyMapKeyJoinColumn( jaxbMapKeyJoinColumn, memberDetails, buildingContext ); -// } ); -// -// XmlAnnotationHelper.applyForeignKey( jaxbPluralAttribute.getMapKeyForeignKey(), memberDetails, buildingContext ); + jaxbPluralAttribute.getMapKeyJoinColumns().forEach( jaxbMapKeyJoinColumn -> { + XmlAnnotationHelper.applyMapKeyJoinColumn( jaxbMapKeyJoinColumn, memberDetails, xmlDocumentContext ); + } ); + + XmlAnnotationHelper.applyForeignKey( jaxbPluralAttribute.getMapKeyForeignKey(), memberDetails, xmlDocumentContext ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // filters and custom sql jaxbPluralAttribute.getFilters().forEach( (jaxbFilter) -> { - XmlAnnotationHelper.applyFilter( jaxbFilter, memberDetails, documentContext ); + XmlAnnotationHelper.applyFilter( jaxbFilter, memberDetails, xmlDocumentContext ); } ); - XmlAnnotationHelper.applySqlRestriction( jaxbPluralAttribute.getSqlRestriction(), memberDetails, documentContext ); + XmlAnnotationHelper.applySqlRestriction( jaxbPluralAttribute.getSqlRestriction(), memberDetails, xmlDocumentContext ); + + XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlInsert(), memberDetails, SQLInsert.class, xmlDocumentContext ); + XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlUpdate(), memberDetails, SQLUpdate.class, xmlDocumentContext ); + XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlDelete(), memberDetails, SQLDelete.class, xmlDocumentContext ); + XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlDeleteAll(), memberDetails, SQLDeleteAll.class, xmlDocumentContext ); + } - XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlInsert(), memberDetails, SQLInsert.class, documentContext ); - XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlUpdate(), memberDetails, SQLUpdate.class, documentContext ); - XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlDelete(), memberDetails, SQLDelete.class, documentContext ); - XmlAnnotationHelper.applyCustomSql( jaxbPluralAttribute.getSqlDeleteAll(), memberDetails, SQLDeleteAll.class, documentContext ); + private static void applyOrderColumn( + JaxbPluralAttribute jaxbPluralAttribute, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + final JaxbOrderColumnImpl jaxbOrderColumn = jaxbPluralAttribute.getOrderColumn(); + if ( jaxbOrderColumn == null ) { + return; + } + + final MutableAnnotationUsage orderColumnAnn = getOrMakeAnnotation( + OrderColumn.class, + memberDetails, + xmlDocumentContext + ); + final AnnotationDescriptor orderColumnDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( OrderColumn.class ); + + applyOr( jaxbOrderColumn, JaxbOrderColumnImpl::getName, "name", orderColumnAnn, orderColumnDescriptor ); + applyOr( jaxbOrderColumn, JaxbOrderColumnImpl::isNullable, "nullable", orderColumnAnn, orderColumnDescriptor ); + applyOr( jaxbOrderColumn, JaxbOrderColumnImpl::isInsertable, "insertable", orderColumnAnn, orderColumnDescriptor ); + applyOr( jaxbOrderColumn, JaxbOrderColumnImpl::isUpdatable, "updatable", orderColumnAnn, orderColumnDescriptor ); + applyOr( jaxbOrderColumn, JaxbOrderColumnImpl::getColumnDefinition, "columnDefinition", orderColumnAnn, orderColumnDescriptor ); + applyOr( jaxbOrderColumn, JaxbOrderColumnImpl::getOptions, "options", orderColumnAnn, orderColumnDescriptor ); } } diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ElementCollectionAttributeProcessing.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ElementCollectionAttributeProcessing.java index 5d2c774..8979979 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ElementCollectionAttributeProcessing.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ElementCollectionAttributeProcessing.java @@ -6,23 +6,9 @@ */ package org.hibernate.boot.models.categorize.xml.internal.attr; -import org.hibernate.annotations.Bag; -import org.hibernate.annotations.CollectionId; -import org.hibernate.annotations.Fetch; -import org.hibernate.annotations.Nationalized; -import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.SQLDeleteAll; -import org.hibernate.annotations.SQLInsert; -import org.hibernate.annotations.SQLUpdate; -import org.hibernate.annotations.SortComparator; -import org.hibernate.annotations.SortNatural; -import org.hibernate.boot.internal.CollectionClassification; -import org.hibernate.boot.internal.LimitedCollectionClassification; import org.hibernate.boot.internal.Target; -import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionIdImpl; -import org.hibernate.boot.jaxb.mapping.spi.JaxbColumnImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionTableImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollectionImpl; -import org.hibernate.boot.jaxb.mapping.spi.JaxbGeneratedValueImpl; import org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.categorize.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.categorize.xml.spi.XmlDocumentContext; @@ -30,18 +16,17 @@ 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.AnnotationDescriptor; import jakarta.persistence.AccessType; -import jakarta.persistence.Column; +import jakarta.persistence.CollectionTable; import jakarta.persistence.ElementCollection; -import jakarta.persistence.Enumerated; -import jakarta.persistence.Lob; -import jakarta.persistence.OrderBy; -import jakarta.persistence.OrderColumn; -import jakarta.persistence.Temporal; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyIndexes; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyOr; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyUniqueConstraints; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.createForeignKeyAnnotation; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.createJoinColumns; import static org.hibernate.internal.util.NullnessHelper.coalesce; /** @@ -82,36 +67,17 @@ public static MutableMemberDetails processElementCollectionAttribute( CommonPluralAttributeProcessing.applyPluralAttributeStructure( jaxbElementCollection, memberDetails, xmlDocumentContext ); + applyCollectionTable( jaxbElementCollection.getCollectionTable(), memberDetails, xmlDocumentContext ); + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // elements - if ( jaxbElementCollection.getEnumerated() != null ) { - final MutableAnnotationUsage enumeratedAnn = XmlProcessingHelper.getOrMakeAnnotation( - Enumerated.class, - memberDetails, - xmlDocumentContext - ); - enumeratedAnn.setAttributeValue( "value", jaxbElementCollection.getEnumerated() ); - } - - if ( jaxbElementCollection.getLob() != null ) { - XmlProcessingHelper.getOrMakeAnnotation( Lob.class, memberDetails, xmlDocumentContext ); - } - - if ( jaxbElementCollection.getNationalized() != null ) { - XmlProcessingHelper.getOrMakeAnnotation( Nationalized.class, memberDetails, xmlDocumentContext ); - } - - if ( jaxbElementCollection.getTemporal() != null ) { - final MutableAnnotationUsage temporalAnn = XmlProcessingHelper.getOrMakeAnnotation( - Temporal.class, - memberDetails, - xmlDocumentContext - ); - temporalAnn.setAttributeValue( "value", jaxbElementCollection.getTemporal() ); - } - + XmlAnnotationHelper.applyEnumerated( jaxbElementCollection.getEnumerated(), memberDetails, xmlDocumentContext ); + XmlAnnotationHelper.applyLob( jaxbElementCollection.getLob(), memberDetails, xmlDocumentContext ); + XmlAnnotationHelper.applyNationalized( jaxbElementCollection.getNationalized(), memberDetails, xmlDocumentContext ); + XmlAnnotationHelper.applyTemporal( jaxbElementCollection.getTemporal(), memberDetails, xmlDocumentContext ); XmlAnnotationHelper.applyBasicTypeComposition( jaxbElementCollection, memberDetails, xmlDocumentContext ); + if ( StringHelper.isNotEmpty( jaxbElementCollection.getTargetClass() ) ) { final MutableAnnotationUsage targetAnn = XmlProcessingHelper.getOrMakeAnnotation( Target.class, memberDetails, xmlDocumentContext ); targetAnn.setAttributeValue( "value", jaxbElementCollection.getTargetClass() ); @@ -121,20 +87,45 @@ public static MutableMemberDetails processElementCollectionAttribute( XmlAnnotationHelper.applyConvert( jaxbConvert, memberDetails, xmlDocumentContext ); } ); - XmlAnnotationHelper.applyAttributeOverrides( - jaxbElementCollection.getAttributeOverrides(), - memberDetails, - "value", - xmlDocumentContext - ); + XmlAnnotationHelper.applyAttributeOverrides( jaxbElementCollection.getAttributeOverrides(), memberDetails, xmlDocumentContext ); - XmlAnnotationHelper.applyAssociationOverrides( - jaxbElementCollection.getAssociationOverrides(), + XmlAnnotationHelper.applyAssociationOverrides( jaxbElementCollection.getAssociationOverrides(), memberDetails, xmlDocumentContext ); + + return memberDetails; + } + + public static void applyCollectionTable( + JaxbCollectionTableImpl jaxbCollectionTable, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + if ( jaxbCollectionTable == null ) { + return; + } + + final MutableAnnotationUsage collectionTableAnn = XmlProcessingHelper.getOrMakeAnnotation( + CollectionTable.class, memberDetails, - "value", xmlDocumentContext ); + final AnnotationDescriptor collectionTableDescriptor = xmlDocumentContext.getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( CollectionTable.class ); - return memberDetails; + applyOr( jaxbCollectionTable, JaxbCollectionTableImpl::getName, "name", collectionTableAnn, collectionTableDescriptor ); + applyOr( jaxbCollectionTable, JaxbCollectionTableImpl::getSchema, "schema", collectionTableAnn, collectionTableDescriptor ); + applyOr( jaxbCollectionTable, JaxbCollectionTableImpl::getOptions, "options", collectionTableAnn, collectionTableDescriptor ); + + collectionTableAnn.setAttributeValue( "joinColumns", createJoinColumns( jaxbCollectionTable.getJoinColumns(), memberDetails, xmlDocumentContext ) ); + + if ( jaxbCollectionTable.getForeignKeys() != null ) { + collectionTableAnn.setAttributeValue( + "foreignKey", + createForeignKeyAnnotation( jaxbCollectionTable.getForeignKeys(), memberDetails, xmlDocumentContext ) + ); + } + + applyUniqueConstraints( jaxbCollectionTable.getUniqueConstraints(), memberDetails, collectionTableAnn, xmlDocumentContext ); + + applyIndexes( jaxbCollectionTable.getIndexes(), memberDetails, collectionTableAnn, xmlDocumentContext ); } } diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ManyToOneAttributeProcessing.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ManyToOneAttributeProcessing.java index 1d4c50b..ed4696a 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ManyToOneAttributeProcessing.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/ManyToOneAttributeProcessing.java @@ -6,18 +6,14 @@ */ package org.hibernate.boot.models.categorize.xml.internal.attr; -import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; import org.hibernate.boot.internal.Target; -import org.hibernate.boot.jaxb.mapping.spi.JaxbCascadeTypeImpl; -import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinColumnImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToOneImpl; import org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.categorize.xml.internal.XmlProcessingHelper; @@ -30,10 +26,10 @@ import org.hibernate.models.spi.AnnotationDescriptor; import jakarta.persistence.AccessType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.JoinColumns; import jakarta.persistence.ManyToOne; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyCascading; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyJoinColumns; import static org.hibernate.internal.util.NullnessHelper.coalesce; /** @@ -61,11 +57,11 @@ public static MutableMemberDetails processManyToOneAttribute( CommonAttributeProcessing.applyAttributeBasics( jaxbManyToOne, memberDetails, manyToOneAnn, accessType, xmlDocumentContext ); - applyJoinColumns( memberDetails, jaxbManyToOne, manyToOneAnn, xmlDocumentContext ); + applyJoinColumns( jaxbManyToOne.getJoinColumns(), memberDetails, xmlDocumentContext ); applyNotFound( memberDetails, jaxbManyToOne, manyToOneAnn, xmlDocumentContext ); applyOnDelete( memberDetails, jaxbManyToOne, manyToOneAnn, xmlDocumentContext ); applyTarget( memberDetails, jaxbManyToOne, manyToOneAnn, xmlDocumentContext ); - applyCascading( memberDetails, jaxbManyToOne, manyToOneAnn, xmlDocumentContext ); + applyCascading( jaxbManyToOne.getCascade(), memberDetails, xmlDocumentContext ); return memberDetails; } @@ -93,34 +89,6 @@ private static MutableAnnotationUsage applyManyToOne( return manyToOneAnn; } - private static void applyJoinColumns( - MutableMemberDetails memberDetails, - JaxbManyToOneImpl jaxbManyToOne, - MutableAnnotationUsage manyToOneAnn, - XmlDocumentContext xmlDocumentContext) { - if ( CollectionHelper.isEmpty( jaxbManyToOne.getJoinColumns() ) ) { - XmlProcessingHelper.makeAnnotation( JoinColumn.class, memberDetails, xmlDocumentContext ); - } - else { - final MutableAnnotationUsage columnsAnn = XmlProcessingHelper.makeAnnotation( - JoinColumns.class, - memberDetails, - xmlDocumentContext - ); - final List> columnList = new ArrayList<>( jaxbManyToOne.getJoinColumns().size() ); - columnsAnn.setAttributeValue( "value", columnList ); - for ( int i = 0; i < jaxbManyToOne.getJoinColumns().size(); i++ ) { - final JaxbJoinColumnImpl jaxbJoinColumn = jaxbManyToOne.getJoinColumns().get( i ); - final MutableAnnotationUsage joinColumnAnn = XmlAnnotationHelper.applyJoinColumn( - jaxbJoinColumn, - memberDetails, - xmlDocumentContext - ); - columnList.add( joinColumnAnn ); - } - } - } - private static void applyNotFound( MutableMemberDetails memberDetails, JaxbManyToOneImpl jaxbManyToOne, @@ -165,51 +133,6 @@ private static void applyTarget( targetAnn.setAttributeValue( "value", targetEntityName ); } - @SuppressWarnings("unused") - private static void applyCascading( - MutableMemberDetails memberDetails, - JaxbManyToOneImpl jaxbManyToOne, - MutableAnnotationUsage manyToOneAnn, - XmlDocumentContext xmlDocumentContext) { - final JaxbCascadeTypeImpl cascadeContainer = jaxbManyToOne.getCascade(); - if ( cascadeContainer == null ) { - return; - } - - final EnumSet cascadeTypes; - - if ( cascadeContainer.getCascadeAll() != null ) { - cascadeTypes = EnumSet.allOf( CascadeType.class ); - } - else { - cascadeTypes = EnumSet.noneOf( CascadeType.class ); - if ( cascadeContainer.getCascadePersist() != null ) { - cascadeTypes.add( CascadeType.PERSIST ); - } - if ( cascadeContainer.getCascadeMerge() != null ) { - cascadeTypes.add( CascadeType.MERGE ); - } - if ( cascadeContainer.getCascadeRemove() != null ) { - cascadeTypes.add( CascadeType.REMOVE ); - } - if ( cascadeContainer.getCascadeLock() != null ) { - cascadeTypes.add( CascadeType.LOCK ); - } - if ( cascadeContainer.getCascadeRefresh() != null ) { - cascadeTypes.add( CascadeType.REFRESH ); - } - if ( cascadeContainer.getCascadeReplicate() != null ) { - //noinspection deprecation - cascadeTypes.add( CascadeType.REPLICATE ); - } - if ( cascadeContainer.getCascadeDetach() != null ) { - cascadeTypes.add( CascadeType.DETACH ); - } - } - - manyToOneAnn.setAttributeValue( "cascade", asList( cascadeTypes ) ); - } - private static > List asList(EnumSet enums) { final List list = CollectionHelper.arrayList( enums.size() ); list.addAll( enums ); diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/OneToManyAttributeProcessing.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/OneToManyAttributeProcessing.java index cb38f9e..3f4d4da 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/OneToManyAttributeProcessing.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/attr/OneToManyAttributeProcessing.java @@ -6,24 +6,113 @@ */ package org.hibernate.boot.models.categorize.xml.internal.attr; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.OnDelete; import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToManyImpl; +import org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper; +import org.hibernate.boot.models.categorize.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.categorize.xml.spi.XmlDocumentContext; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.models.internal.MutableAnnotationUsage; import org.hibernate.models.internal.MutableClassDetails; import org.hibernate.models.internal.MutableMemberDetails; +import org.hibernate.models.spi.AnnotationDescriptor; import jakarta.persistence.AccessType; +import jakarta.persistence.OneToMany; + +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyOr; +import static org.hibernate.boot.models.categorize.xml.internal.XmlProcessingHelper.getOrMakeAnnotation; +import static org.hibernate.internal.util.NullnessHelper.coalesce; /** * @author Steve Ebersole */ public class OneToManyAttributeProcessing { - - @SuppressWarnings("UnusedReturnValue") public static MutableMemberDetails processOneToManyAttribute( JaxbOneToManyImpl jaxbOneToMany, - MutableClassDetails mutableClassDetails, + MutableClassDetails declarer, AccessType classAccessType, XmlDocumentContext xmlDocumentContext) { - throw new UnsupportedOperationException( "Support for one-to-many attributes not yet implemented" ); + final AccessType accessType = coalesce( jaxbOneToMany.getAccess(), classAccessType ); + final MutableMemberDetails memberDetails = XmlProcessingHelper.getAttributeMember( + jaxbOneToMany.getName(), + accessType, + declarer + ); + + final MutableAnnotationUsage oneToManyAnn = applyManyToOne( + jaxbOneToMany, + memberDetails, + xmlDocumentContext + ); + + applyTargetEntity( jaxbOneToMany, oneToManyAnn, xmlDocumentContext ); + + XmlAnnotationHelper.applyCascading( jaxbOneToMany.getCascade(), memberDetails, xmlDocumentContext ); + + CommonAttributeProcessing.applyAttributeBasics( jaxbOneToMany, memberDetails, oneToManyAnn, accessType, xmlDocumentContext ); + + CommonPluralAttributeProcessing.applyPluralAttributeStructure( jaxbOneToMany, memberDetails, xmlDocumentContext ); + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // join-table + + XmlAnnotationHelper.applyJoinTable( jaxbOneToMany.getJoinTable(), memberDetails, xmlDocumentContext ); + + XmlAnnotationHelper.applySqlJoinTableRestriction( jaxbOneToMany.getSqlJoinTableRestriction(), memberDetails, xmlDocumentContext ); + + jaxbOneToMany.getJoinTableFilters().forEach( (jaxbFilter) -> { + XmlAnnotationHelper.applyJoinTableFilter( jaxbFilter, memberDetails, xmlDocumentContext ); + } ); + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // other properties + + jaxbOneToMany.getJoinColumn().forEach( jaxbJoinColumn -> { + XmlAnnotationHelper.applyJoinColumn( jaxbJoinColumn, memberDetails, xmlDocumentContext ); + } ); + + if ( jaxbOneToMany.getOnDelete() != null ) { + getOrMakeAnnotation( OnDelete.class, memberDetails, xmlDocumentContext ).setAttributeValue( "action", jaxbOneToMany.getOnDelete() ); + } + + if ( jaxbOneToMany.getNotFound() != null ) { + getOrMakeAnnotation( NotFound.class, memberDetails, xmlDocumentContext ).setAttributeValue( "action", jaxbOneToMany.getNotFound() ); + } + + return memberDetails; + } + + private static MutableAnnotationUsage applyManyToOne( + JaxbOneToManyImpl jaxbOneToMany, + MutableMemberDetails memberDetails, + XmlDocumentContext xmlDocumentContext) { + final MutableAnnotationUsage oneToManyAnn = getOrMakeAnnotation( OneToMany.class, memberDetails, xmlDocumentContext ); + final AnnotationDescriptor oneToManyDescriptor = xmlDocumentContext + .getModelBuildingContext() + .getAnnotationDescriptorRegistry() + .getDescriptor( OneToMany.class ); + + applyOr( jaxbOneToMany, JaxbOneToManyImpl::getFetch, "fetch", oneToManyAnn, oneToManyDescriptor ); + applyOr( jaxbOneToMany, JaxbOneToManyImpl::getMappedBy, "mappedBy", oneToManyAnn, oneToManyDescriptor ); + applyOr( jaxbOneToMany, JaxbOneToManyImpl::isOrphanRemoval, "orphanRemoval", oneToManyAnn, oneToManyDescriptor ); + + return oneToManyAnn; + } + + private static void applyTargetEntity( + JaxbOneToManyImpl jaxbOneToMany, + MutableAnnotationUsage oneToManyAnn, + XmlDocumentContext xmlDocumentContext) { + final String targetEntity = jaxbOneToMany.getTargetEntity(); + if ( StringHelper.isNotEmpty( targetEntity ) ) { + oneToManyAnn.setAttributeValue( + "targetEntity", + xmlDocumentContext.getModelBuildingContext() + .getClassDetailsRegistry() + .resolveClassDetails( targetEntity ) + ); + } } } diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/db/ColumnProcessing.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/db/ColumnProcessing.java index 30a397e..1098d9b 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/db/ColumnProcessing.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/db/ColumnProcessing.java @@ -30,6 +30,8 @@ import org.hibernate.models.internal.MutableAnnotationUsage; import org.hibernate.models.spi.AnnotationUsage; +import static org.hibernate.boot.models.categorize.xml.internal.XmlAnnotationHelper.applyCheckConstraints; + /** * @author Steve Ebersole */ @@ -50,7 +52,7 @@ public static void applyColumnDetails( applyColumnDefinition( jaxbColumn, target, columnAnn, xmlDocumentContext ); applyColumnUniqueness( jaxbColumn, target, columnAnn, xmlDocumentContext ); applyColumnComment( jaxbColumn, target, columnAnn, xmlDocumentContext ); - applyColumnChecks( jaxbColumn, target, columnAnn, xmlDocumentContext ); + applyCheckConstraints( jaxbColumn, target, columnAnn, xmlDocumentContext ); if ( jaxbColumn instanceof JaxbColumnSizable sizable ) { applyColumnSizing( sizable, target, columnAnn, xmlDocumentContext ); @@ -74,7 +76,7 @@ public static void applyColumnDetails( applyColumnSizing( jaxbColumn, target, columnAnn, xmlDocumentContext ); applyColumnUniqueness( jaxbColumn, target, columnAnn, xmlDocumentContext ); applyColumnComment( jaxbColumn, target, columnAnn, xmlDocumentContext ); - applyColumnChecks( jaxbColumn, target, columnAnn, xmlDocumentContext ); + applyCheckConstraints( jaxbColumn, target, columnAnn, xmlDocumentContext ); } public static void applyColumnDetails( @@ -113,7 +115,7 @@ public static void applyColumnDetails( } if ( jaxbColumn instanceof JaxbCheckable checkable ) { - applyColumnChecks( checkable, target, columnAnn, xmlDocumentContext ); + applyCheckConstraints( checkable, target, columnAnn, xmlDocumentContext ); } } @@ -207,22 +209,4 @@ private static void applyColumnComment( columnAnn.setAttributeValue( "comment", jaxbColumn.getComment() ); } } - - private static void applyColumnChecks( - JaxbCheckable jaxbColumn, - MutableAnnotationTarget target, - MutableAnnotationUsage columnAnn, - XmlDocumentContext xmlDocumentContext) { - if ( CollectionHelper.isNotEmpty( jaxbColumn.getCheckConstraints() ) ) { - final List> checks = new ArrayList<>( jaxbColumn.getCheckConstraints().size() ); - for ( int i = 0; i < jaxbColumn.getCheckConstraints().size(); i++ ) { - final JaxbCheckConstraintImpl jaxbCheck = jaxbColumn.getCheckConstraints().get( i ); - final MutableAnnotationUsage checkAnn = XmlProcessingHelper.getOrMakeAnnotation( Check.class, target, xmlDocumentContext ); - checkAnn.setAttributeValue( "name", jaxbCheck.getName() ); - checkAnn.setAttributeValue( "constraints", jaxbCheck.getConstraint() ); - checks.add( checkAnn ); - } - columnAnn.setAttributeValue( "check", checks ); - } - } } diff --git a/src/test/java/org/hibernate/models/orm/xml/attr/ManyToOneTests.java b/src/test/java/org/hibernate/models/orm/xml/attr/ManyToOneTests.java index 2699672..f8f8690 100644 --- a/src/test/java/org/hibernate/models/orm/xml/attr/ManyToOneTests.java +++ b/src/test/java/org/hibernate/models/orm/xml/attr/ManyToOneTests.java @@ -8,6 +8,7 @@ import java.util.List; +import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; @@ -76,8 +77,7 @@ void testSimpleManyToOne(ServiceRegistryScope scope) { assertThat( joinColumnAnn ).isNotNull(); assertThat( joinColumnAnn.getString( "name" ) ).isEqualTo( "parent_fk" ); - assertThat( parentField.getAnnotationUsage( JoinColumns.class ) ).isNotNull(); - assertThat( parentField.getAnnotationUsage( JoinColumns.class ).getList( "value" ) ).hasSize( 1 ); + assertThat( parentField.getAnnotationUsage( JoinColumn.class ) ).isNotNull(); final AnnotationUsage notFoundAnn = parentField.getAnnotationUsage( NotFound.class ); assertThat( notFoundAnn ).isNotNull(); @@ -99,9 +99,10 @@ void testSimpleManyToOne(ServiceRegistryScope scope) { assertThat( targetAnn ).isNotNull(); assertThat( targetAnn.getString( "value" ) ).isEqualTo( "org.hibernate.models.orm.xml.attr.ManyToOneTests$SimpleEntity" ); - final List cascadeTypes = manyToOneAnn.getList( "cascade" ); + final AnnotationUsage cascadeAnn = parentField.getAnnotationUsage( Cascade.class ); + final List cascadeTypes = cascadeAnn.getList( "value" ); assertThat( cascadeTypes ).isNotEmpty(); - assertThat( cascadeTypes ).contains( CascadeType.PERSIST, CascadeType.MERGE, CascadeType.LOCK ); + assertThat( cascadeTypes ).containsOnly( CascadeType.ALL ); } @SuppressWarnings("unused") diff --git a/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java b/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java index 8bde5f3..443f237 100644 --- a/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java +++ b/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java @@ -6,10 +6,20 @@ */ package org.hibernate.models.orm.xml.dynamic; +import java.util.List; import java.util.Set; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.JavaType; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import org.hibernate.annotations.SortNatural; import org.hibernate.boot.internal.BootstrapContextImpl; +import org.hibernate.boot.internal.CollectionClassification; +import org.hibernate.boot.internal.LimitedCollectionClassification; import org.hibernate.boot.internal.MetadataBuilderImpl; import org.hibernate.boot.internal.Target; import org.hibernate.boot.model.process.spi.ManagedResources; @@ -25,7 +35,15 @@ import org.junit.jupiter.api.Test; +import jakarta.persistence.CheckConstraint; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.ConstraintMode; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; import jakarta.persistence.IdClass; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; import static org.assertj.core.api.Assertions.assertThat; import static org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor.processManagedResources; @@ -99,8 +117,18 @@ void testSemiSimpleDynamicModel() { assertThat( nameField.getType().getFields() ).hasSize( 2 ); - final FieldDetails labelsField = rootEntity.getClassDetails().findFieldByName( "labels" ); - assertThat( labelsField.getType().getClassName() ).isEqualTo( Set.class.getName() ); + final FieldDetails labels = rootEntity.getClassDetails().findFieldByName( "labels" ); + assertThat( labels.getType().getClassName() ).isEqualTo( Set.class.getName() ); + final AnnotationUsage elementCollection = labels.getAnnotationUsage( ElementCollection.class ); + assertThat( elementCollection.getAttributeValue( "targetClass" ).getName() ).isEqualTo( String.class.getName() ); + final AnnotationUsage collectionClassification = labels.getAnnotationUsage( CollectionClassification.class ); + assertThat( collectionClassification.getAttributeValue( "value" ) ).isEqualTo( LimitedCollectionClassification.SET ); + final AnnotationUsage collectionTable = labels.getAnnotationUsage( CollectionTable.class ); + assertThat( collectionTable.getAttributeValue( "name" ) ).isEqualTo( "labels" ); + assertThat( labels.getAnnotationUsage( SortNatural.class ) ).isNotNull(); + final List> joinColumns = collectionTable.getList( "joinColumns" ); + assertThat( joinColumns ).hasSize( 1 ); + assertThat( joinColumns.get( 0 ).getAttributeValue( "name" ) ).isEqualTo( "contact_fk" ); } } @@ -130,4 +158,47 @@ void testIdClass() { .getName() ).isEqualTo( EmployeePK.class.getName() ); } } + + @Test + void testOneToMany() { + final ManagedResources managedResources = new ManagedResourcesImpl.Builder() + .addXmlMappings( "mappings/dynamic/dynamic-plurals.xml" ) + .build(); + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { + final BootstrapContextImpl bootstrapContext = new BootstrapContextImpl( + serviceRegistry, + new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) + ); + final CategorizedDomainModel categorizedDomainModel = processManagedResources( + managedResources, + bootstrapContext + ); + + assertThat( categorizedDomainModel.getEntityHierarchies() ).hasSize( 1 ); + final EntityTypeMetadata rootEntity = categorizedDomainModel.getEntityHierarchies().iterator().next().getRoot(); + assertThat( rootEntity.getClassDetails().getName() ).isEqualTo( Employee.class.getName() ); + + final FieldDetails oneToMany = rootEntity.getClassDetails().findFieldByName( "oneToMany" ); + assertThat( oneToMany.getType().getClassName() ).isEqualTo( List.class.getName() ); + final AnnotationUsage oneToManyAnn = oneToMany.getAnnotationUsage( OneToMany.class ); + assertThat( oneToManyAnn.getAttributeValue( "fetch" ) ).isEqualTo( FetchType.EAGER ); + assertThat( oneToMany.getAnnotationUsage( NotFound.class ) + .getAttributeValue( "action" ) ).isEqualTo( NotFoundAction.IGNORE ); + assertThat( oneToMany.getAnnotationUsage( OnDelete.class ) + .getAttributeValue( "action" ) ).isEqualTo( OnDeleteAction.CASCADE ); + final AnnotationUsage joinColumn = oneToMany.getAnnotationUsage( JoinColumn.class ); + assertThat( joinColumn.getAttributeValue( "name" ) ).isEqualTo( "employee_id" ); + assertThat( joinColumn.getAttributeValue( "insertable" ) ).isEqualTo( Boolean.FALSE ); + assertThat( joinColumn.getAttributeValue( "updatable" ) ).isEqualTo( Boolean.FALSE ); + final AnnotationUsage foreignKey = joinColumn.getAttributeValue( "foreignKey" ); + assertThat( foreignKey.getAttributeValue( "name" ) ).isEqualTo( "employee_fk" ); + assertThat( foreignKey.getAttributeValue( "value" ) ).isEqualTo( ConstraintMode.NO_CONSTRAINT ); + final List> checkConstraints = joinColumn.getList( "check" ); + assertThat( checkConstraints ).hasSize( 1 ); + assertThat( checkConstraints.get( 0 ).getAttributeValue( "name" ) ).isEqualTo( "employee_id_nn" ); + assertThat( checkConstraints.get( 0 ).getAttributeValue( "constraint" ) ).isEqualTo( "employee_id is not null" ); + assertThat( oneToMany.getAnnotationUsage( Cascade.class ).getList( "value" ) ) + .contains( CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.LOCK ); + } + } } diff --git a/src/test/java/org/hibernate/models/orm/xml/dynamic/Employee.java b/src/test/java/org/hibernate/models/orm/xml/dynamic/Employee.java index 83525a6..658f675 100644 --- a/src/test/java/org/hibernate/models/orm/xml/dynamic/Employee.java +++ b/src/test/java/org/hibernate/models/orm/xml/dynamic/Employee.java @@ -6,6 +6,10 @@ */ package org.hibernate.models.orm.xml.dynamic; +import java.util.List; + +import org.hibernate.models.orm.xml.SimpleEntity; + import jakarta.persistence.Entity; import jakarta.persistence.Id; @@ -15,4 +19,6 @@ public class Employee { private String name; @Id private int number; + + private List oneToMany; } diff --git a/src/test/resources/mappings/dynamic/dynamic-plurals.xml b/src/test/resources/mappings/dynamic/dynamic-plurals.xml new file mode 100644 index 0000000..25a8d2a --- /dev/null +++ b/src/test/resources/mappings/dynamic/dynamic-plurals.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + CASCADE + + + + \ No newline at end of file