Skip to content

Commit bbd07c3

Browse files
committed
HHH-20324 AnnotationException: overrides mapping specified using '@JoinColumnOrFormula' thrown when join column is overridden via XML mapping
1 parent 49bc227 commit bbd07c3

4 files changed

Lines changed: 91 additions & 70 deletions

File tree

‎hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/JoinColumnProcessing.java‎

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
import jakarta.persistence.PrimaryKeyJoinColumn;
3434
import jakarta.persistence.PrimaryKeyJoinColumns;
3535

36+
import static org.hibernate.boot.models.JpaAnnotations.JOIN_COLUMN;
37+
import static org.hibernate.boot.models.JpaAnnotations.JOIN_COLUMNS;
38+
3639
/**
3740
* XML -> AnnotationUsage support for {@linkplain JaxbColumnJoined}: <ul>
3841
* <li>{@code <join-column/>}</li>
@@ -53,8 +56,8 @@ public static void applyJoinColumns(
5356
}
5457

5558
final JoinColumnsJpaAnnotation columnsAnn = (JoinColumnsJpaAnnotation) memberDetails.replaceAnnotationUsage(
56-
JpaAnnotations.JOIN_COLUMN,
57-
JpaAnnotations.JOIN_COLUMNS,
59+
JOIN_COLUMN,
60+
JOIN_COLUMNS,
5861
xmlDocumentContext.getModelBuildingContext()
5962
);
6063
columnsAnn.value( transformJoinColumnList(
@@ -74,7 +77,7 @@ public static JoinColumn[] transformJoinColumnList(
7477

7578
final JoinColumn[] joinColumns = new JoinColumn[jaxbJoinColumns.size()];
7679
for ( int i = 0; i < jaxbJoinColumns.size(); i++ ) {
77-
final JoinColumnJpaAnnotation joinColumn = JpaAnnotations.JOIN_COLUMN.createUsage( xmlDocumentContext.getModelBuildingContext() );
80+
final JoinColumnJpaAnnotation joinColumn = JOIN_COLUMN.createUsage( xmlDocumentContext.getModelBuildingContext() );
7881
joinColumns[i] = joinColumn;
7982
joinColumn.apply( jaxbJoinColumns.get( i ), xmlDocumentContext );
8083
}
@@ -86,40 +89,74 @@ public static void applyJoinColumnsOrFormulas(
8689
MutableMemberDetails memberDetails,
8790
XmlDocumentContext xmlDocumentContext) {
8891
if ( !CollectionHelper.isEmpty( jaxbJoinColumnsOrFormulas ) ) {
89-
memberDetails.removeAnnotationUsage( JpaAnnotations.JOIN_COLUMN );
90-
memberDetails.removeAnnotationUsage( JpaAnnotations.JOIN_COLUMNS );
91-
final JoinColumnsOrFormulasAnnotation joinColumnsOrFormulasUsage = (JoinColumnsOrFormulasAnnotation) memberDetails.replaceAnnotationUsage(
92-
HibernateAnnotations.JOIN_COLUMN_OR_FORMULA,
93-
HibernateAnnotations.JOIN_COLUMNS_OR_FORMULAS,
92+
if ( hasOnlyJoinColumns(jaxbJoinColumnsOrFormulas) ) {
93+
applyPureJoinColumns( jaxbJoinColumnsOrFormulas, memberDetails, xmlDocumentContext );
94+
}
95+
else {
96+
memberDetails.removeAnnotationUsage( JpaAnnotations.JOIN_COLUMN );
97+
memberDetails.removeAnnotationUsage( JpaAnnotations.JOIN_COLUMNS );
98+
final JoinColumnsOrFormulasAnnotation joinColumnsOrFormulasUsage = (JoinColumnsOrFormulasAnnotation) memberDetails.replaceAnnotationUsage(
99+
HibernateAnnotations.JOIN_COLUMN_OR_FORMULA,
100+
HibernateAnnotations.JOIN_COLUMNS_OR_FORMULAS,
101+
xmlDocumentContext.getModelBuildingContext()
102+
);
103+
104+
final JoinColumnOrFormula[] joinColumnOrFormulaList = new JoinColumnOrFormula[jaxbJoinColumnsOrFormulas.size()];
105+
joinColumnsOrFormulasUsage.value( joinColumnOrFormulaList );
106+
107+
for ( int i = 0; i < jaxbJoinColumnsOrFormulas.size(); i++ ) {
108+
final JoinColumnOrFormulaAnnotation joinColumnOrFormulaUsage = HibernateAnnotations.JOIN_COLUMN_OR_FORMULA.createUsage(
109+
xmlDocumentContext.getModelBuildingContext() );
110+
joinColumnOrFormulaList[i] = joinColumnOrFormulaUsage;
111+
112+
final Serializable jaxbJoinColumnOrFormula = jaxbJoinColumnsOrFormulas.get( i );
113+
if ( jaxbJoinColumnOrFormula instanceof JaxbJoinColumnImpl jaxbJoinColumn ) {
114+
final JoinColumnJpaAnnotation joinColumnUsage = JpaAnnotations.JOIN_COLUMN.createUsage(
115+
xmlDocumentContext.getModelBuildingContext() );
116+
joinColumnOrFormulaUsage.column( joinColumnUsage );
117+
joinColumnUsage.apply( jaxbJoinColumn, xmlDocumentContext );
118+
}
119+
else if ( jaxbJoinColumnOrFormula instanceof String jaxbJoinFormula ) {
120+
final JoinFormulaAnnotation joinFormulaUsage = HibernateAnnotations.JOIN_FORMULA.createUsage(
121+
xmlDocumentContext.getModelBuildingContext() );
122+
joinColumnOrFormulaUsage.formula( joinFormulaUsage );
123+
joinFormulaUsage.value( jaxbJoinFormula );
124+
}
125+
else {
126+
throw new MappingException(
127+
"Unexpected join-column-or-formula type : " + jaxbJoinColumnOrFormula );
128+
}
129+
}
130+
}
131+
}
132+
}
133+
134+
private static boolean hasOnlyJoinColumns(List<Serializable> jaxbJoinColumnsOrFormulas) {
135+
return jaxbJoinColumnsOrFormulas.stream().allMatch( element -> element instanceof JaxbJoinColumnImpl );
136+
}
137+
138+
private static void applyPureJoinColumns(
139+
List<Serializable> jaxbJoinColumns,
140+
MutableMemberDetails memberDetails,
141+
XmlDocumentContext xmlDocumentContext) {
142+
memberDetails.removeAnnotationUsage( JOIN_COLUMN );
143+
memberDetails.removeAnnotationUsage( JOIN_COLUMNS );
144+
final JoinColumnsJpaAnnotation joinColumnsUsage = (JoinColumnsJpaAnnotation) memberDetails.replaceAnnotationUsage(
145+
JOIN_COLUMN,
146+
JOIN_COLUMNS,
94147
xmlDocumentContext.getModelBuildingContext()
95148
);
96149

97-
final JoinColumnOrFormula[] joinColumnOrFormulaList = new JoinColumnOrFormula[jaxbJoinColumnsOrFormulas.size()];
98-
joinColumnsOrFormulasUsage.value( joinColumnOrFormulaList );
150+
final JoinColumn[] joinColumn = new JoinColumn[jaxbJoinColumns.size()];
151+
joinColumnsUsage.value( joinColumn );
99152

100-
for ( int i = 0; i < jaxbJoinColumnsOrFormulas.size(); i++ ) {
101-
final JoinColumnOrFormulaAnnotation joinColumnOrFormulaUsage = HibernateAnnotations.JOIN_COLUMN_OR_FORMULA.createUsage(
153+
for ( int i = 0; i < jaxbJoinColumns.size(); i++ ) {
154+
final Serializable jaxbJoinColumnOrFormula = jaxbJoinColumns.get( i );
155+
final JoinColumnJpaAnnotation joinColumnUsage = JOIN_COLUMN.createUsage(
102156
xmlDocumentContext.getModelBuildingContext() );
103-
joinColumnOrFormulaList[i] = joinColumnOrFormulaUsage;
104-
105-
final Serializable jaxbJoinColumnOrFormula = jaxbJoinColumnsOrFormulas.get( i );
106-
if ( jaxbJoinColumnOrFormula instanceof JaxbJoinColumnImpl jaxbJoinColumn ) {
107-
final JoinColumnJpaAnnotation joinColumnUsage = JpaAnnotations.JOIN_COLUMN.createUsage(
108-
xmlDocumentContext.getModelBuildingContext() );
109-
joinColumnOrFormulaUsage.column( joinColumnUsage );
110-
joinColumnUsage.apply( jaxbJoinColumn, xmlDocumentContext );
111-
}
112-
else if ( jaxbJoinColumnOrFormula instanceof String jaxbJoinFormula ) {
113-
final JoinFormulaAnnotation joinFormulaUsage = HibernateAnnotations.JOIN_FORMULA.createUsage(
114-
xmlDocumentContext.getModelBuildingContext() );
115-
joinColumnOrFormulaUsage.formula( joinFormulaUsage );
116-
joinFormulaUsage.value( jaxbJoinFormula );
117-
}
118-
else {
119-
throw new MappingException( "Unexpected join-column-or-formula type : " + jaxbJoinColumnOrFormula );
120-
}
157+
joinColumn[i] = joinColumnUsage;
158+
joinColumnUsage.apply( (JaxbJoinColumnImpl) jaxbJoinColumnOrFormula, xmlDocumentContext );
121159
}
122-
}
123160
}
124161

125162
/**

‎hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlManyToOneTest.java‎

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
import org.hibernate.annotations.Cascade;
88
import org.hibernate.annotations.CascadeType;
9-
import org.hibernate.annotations.JoinColumnOrFormula;
10-
import org.hibernate.annotations.JoinColumnsOrFormulas;
11-
import org.hibernate.annotations.JoinFormula;
129
import org.hibernate.boot.internal.Target;
1310
import org.hibernate.models.spi.MemberDetails;
1411

@@ -57,19 +54,16 @@ public void testNoJoins() {
5754
public void testSingleJoinColumn() {
5855
final MemberDetails memberDetails = getAttributeMember( Entity1.class, "field1", "many-to-one.orm2.xml" );
5956
assertThat( memberDetails.hasDirectAnnotationUsage( ManyToOne.class ) ).isTrue();
60-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumnsOrFormulas.class ) ).isTrue();
6157

62-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumnOrFormula.class ) ).isFalse();
63-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumns.class ) ).isFalse();
6458
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumn.class ) ).isFalse();
65-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinFormula.class ) ).isFalse();
59+
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumns.class ) ).isTrue();
6660

6761
assertThat( memberDetails.hasDirectAnnotationUsage( JoinTable.class ) ).isFalse();
6862
assertThat( memberDetails.hasDirectAnnotationUsage( Id.class ) ).isFalse();
6963
assertThat( memberDetails.hasDirectAnnotationUsage( MapsId.class ) ).isFalse();
7064

71-
final JoinColumnsOrFormulas joinColumnsOrFormulasUsage = memberDetails.getDirectAnnotationUsage( JoinColumnsOrFormulas.class );
72-
final JoinColumn joinColumnUsage = joinColumnsOrFormulasUsage.value()[0].column();
65+
final JoinColumns joinColumnsUsage = memberDetails.getDirectAnnotationUsage( JoinColumns.class );
66+
final JoinColumn joinColumnUsage = joinColumnsUsage.value()[0];
7367
assertThat( joinColumnUsage.name() ).isEqualTo( "col1" );
7468
assertThat( joinColumnUsage.referencedColumnName() ).isEqualTo( "col2" );
7569
assertThat( joinColumnUsage.table() ).isEqualTo( "table1" );
@@ -79,20 +73,18 @@ public void testSingleJoinColumn() {
7973
public void testMultipleJoinColumns() {
8074
final MemberDetails memberDetails = getAttributeMember( Entity1.class, "field1", "many-to-one.orm3.xml" );
8175
assertThat( memberDetails.hasDirectAnnotationUsage( ManyToOne.class ) ).isTrue();
82-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumnsOrFormulas.class ) ).isTrue();
76+
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumns.class ) ).isTrue();
8377

84-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumnOrFormula.class ) ).isFalse();
85-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinFormula.class ) ).isFalse();
8678
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumn.class ) ).isFalse();
8779
assertThat( memberDetails.hasDirectAnnotationUsage( JoinTable.class ) ).isFalse();
8880
assertThat( memberDetails.hasDirectAnnotationUsage( Id.class ) ).isFalse();
8981
assertThat( memberDetails.hasDirectAnnotationUsage( MapsId.class ) ).isFalse();
9082

91-
final JoinColumnsOrFormulas joinColumnsOrFormulasUsage = memberDetails.getDirectAnnotationUsage( JoinColumnsOrFormulas.class );
92-
final JoinColumnOrFormula[] joinColumnOrFormulaUsages = joinColumnsOrFormulasUsage.value();
93-
assertThat( joinColumnOrFormulaUsages ).hasSize( 2 );
83+
final JoinColumns joinColumnsUsage = memberDetails.getDirectAnnotationUsage( JoinColumns.class );
84+
final JoinColumn[] joinColumnUsages = joinColumnsUsage.value();
85+
assertThat( joinColumnUsages ).hasSize( 2 );
9486

95-
final JoinColumn joinColumnUsage0 = joinColumnOrFormulaUsages[0].column();
87+
final JoinColumn joinColumnUsage0 = joinColumnUsages[0];
9688
assertThat( joinColumnUsage0.name() ).isEmpty();
9789
assertThat( joinColumnUsage0.referencedColumnName() ).isEmpty();
9890
assertThat( joinColumnUsage0.table() ).isEmpty();
@@ -102,7 +94,7 @@ public void testMultipleJoinColumns() {
10294
assertThat( joinColumnUsage0.nullable() ).isTrue();
10395
assertThat( joinColumnUsage0.unique() ).isFalse();
10496

105-
final JoinColumn joinColumnUsage1 = joinColumnOrFormulaUsages[1].column();
97+
final JoinColumn joinColumnUsage1 = joinColumnUsages[1];
10698
assertThat( joinColumnUsage1.name() ).isEqualTo( "col1" );
10799
assertThat( joinColumnUsage1.referencedColumnName() ).isEqualTo( "col2" );
108100
assertThat( joinColumnUsage1.table() ).isEqualTo( "table1" );

‎hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlOneToOneTest.java‎

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
import org.hibernate.annotations.Cascade;
88
import org.hibernate.annotations.CascadeType;
9-
import org.hibernate.annotations.JoinColumnOrFormula;
10-
import org.hibernate.annotations.JoinColumnsOrFormulas;
119
import org.hibernate.boot.internal.Target;
1210
import org.hibernate.models.spi.MemberDetails;
1311

@@ -116,17 +114,18 @@ public void testMultiplePrimaryKeyJoinColumn() {
116114
public void testSingleJoinColumn() {
117115
final MemberDetails memberDetails = getAttributeMember( Entity1.class, "field1", "one-to-one.orm4.xml" );
118116
assertThat( memberDetails.hasDirectAnnotationUsage( OneToOne.class ) ).isTrue();
119-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumnsOrFormulas.class ) ).isTrue();
117+
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumn.class ) ).isFalse();
118+
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumns.class ) ).isTrue();
120119

121120
assertThat( memberDetails.hasDirectAnnotationUsage( MapsId.class ) ).isFalse();
122121
assertThat( memberDetails.hasDirectAnnotationUsage( Id.class ) ).isFalse();
123122
assertThat( memberDetails.hasDirectAnnotationUsage( PrimaryKeyJoinColumns.class ) ).isFalse();
124123
assertThat( memberDetails.hasDirectAnnotationUsage( PrimaryKeyJoinColumn.class ) ).isFalse();
125124
assertThat( memberDetails.hasDirectAnnotationUsage( JoinTable.class ) ).isFalse();
126125

127-
final JoinColumnsOrFormulas joinColumnsOrFormulas = memberDetails.getDirectAnnotationUsage( JoinColumnsOrFormulas.class );
128-
assertThat( joinColumnsOrFormulas.value() ).hasSize( 1 );
129-
final JoinColumn joinColumnUsage = joinColumnsOrFormulas.value()[0].column();
126+
final JoinColumns joinColumnsUsage = memberDetails.getDirectAnnotationUsage( JoinColumns.class );
127+
assertThat( joinColumnsUsage.value() ).hasSize( 1 );
128+
final JoinColumn joinColumnUsage = joinColumnsUsage.value()[0];
130129
assertThat( joinColumnUsage.name() ).isEqualTo( "col1" );
131130
assertThat( joinColumnUsage.referencedColumnName() ).isEqualTo( "col2" );
132131
assertThat( joinColumnUsage.table() ).isEqualTo( "table1" );
@@ -136,19 +135,19 @@ public void testSingleJoinColumn() {
136135
public void testMultipleJoinColumns(){
137136
final MemberDetails memberDetails = getAttributeMember( Entity1.class, "field1", "one-to-one.orm5.xml" );
138137
assertThat( memberDetails.hasDirectAnnotationUsage( OneToOne.class ) ).isTrue();
139-
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumnsOrFormulas.class ) ).isTrue();
138+
assertThat( memberDetails.hasDirectAnnotationUsage( JoinColumns.class ) ).isTrue();
140139

141140
assertThat( memberDetails.hasDirectAnnotationUsage( MapsId.class ) ).isFalse();
142141
assertThat( memberDetails.hasDirectAnnotationUsage( Id.class ) ).isFalse();
143142
assertThat( memberDetails.hasDirectAnnotationUsage( PrimaryKeyJoinColumns.class ) ).isFalse();
144143
assertThat( memberDetails.hasDirectAnnotationUsage( PrimaryKeyJoinColumn.class ) ).isFalse();
145144
assertThat( memberDetails.hasDirectAnnotationUsage( JoinTable.class ) ).isFalse();
146145

147-
final JoinColumnsOrFormulas joinColumnsOrFormulasUsage = memberDetails.getDirectAnnotationUsage( JoinColumnsOrFormulas.class );
148-
final JoinColumnOrFormula[] joinColumnOrFormulaUsages = joinColumnsOrFormulasUsage.value();
149-
assertThat( joinColumnOrFormulaUsages ).hasSize( 2 );
146+
final JoinColumns joinColumnsUsage = memberDetails.getDirectAnnotationUsage( JoinColumns.class );
147+
final JoinColumn[] joinColumnUsages = joinColumnsUsage.value();
148+
assertThat( joinColumnUsages ).hasSize( 2 );
150149

151-
final JoinColumn joinColumnUsage0 = joinColumnOrFormulaUsages[0].column();
150+
final JoinColumn joinColumnUsage0 = joinColumnUsages[0];
152151
assertThat( joinColumnUsage0.name() ).isEmpty();
153152
assertThat( joinColumnUsage0.referencedColumnName() ).isEmpty();
154153
assertThat( joinColumnUsage0.table() ).isEmpty();
@@ -158,7 +157,7 @@ public void testMultipleJoinColumns(){
158157
assertThat( joinColumnUsage0.nullable() ).isTrue();
159158
assertThat( joinColumnUsage0.unique() ).isFalse();
160159

161-
final JoinColumn joinColumnUsage1 = joinColumnOrFormulaUsages[1].column();
160+
final JoinColumn joinColumnUsage1 = joinColumnUsages[1];
162161
assertThat( joinColumnUsage1.name() ).isEqualTo( "col1" );
163162
assertThat( joinColumnUsage1.referencedColumnName() ).isEqualTo( "col2" );
164163
assertThat( joinColumnUsage1.table() ).isEqualTo( "table1" );

‎hibernate-core/src/test/java/org/hibernate/orm/test/boot/models/xml/attr/ManyToOneTests.java‎

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import org.hibernate.annotations.CascadeType;
99
import org.hibernate.annotations.Fetch;
1010
import org.hibernate.annotations.FetchMode;
11-
import org.hibernate.annotations.JoinColumnOrFormula;
12-
import org.hibernate.annotations.JoinColumnsOrFormulas;
1311
import org.hibernate.annotations.NotFound;
1412
import org.hibernate.annotations.NotFoundAction;
1513
import org.hibernate.annotations.OnDelete;
@@ -50,20 +48,15 @@ void testSimpleManyToOne(ServiceRegistryScope scope) {
5048
.addXmlMappings( "mappings/models/attr/many-to-one/simple.xml" )
5149
.build();
5250

53-
final ModelsContext ModelsContext = createBuildingContext( managedResources, serviceRegistry );
54-
final ClassDetailsRegistry classDetailsRegistry = ModelsContext.getClassDetailsRegistry();
51+
final ModelsContext modelsContext = createBuildingContext( managedResources, serviceRegistry );
52+
final ClassDetailsRegistry classDetailsRegistry = modelsContext.getClassDetailsRegistry();
5553

5654
final ClassDetails classDetails = classDetailsRegistry.getClassDetails( SimpleEntity.class.getName() );
5755

5856
final FieldDetails parentField = classDetails.findFieldByName( "parent" );
5957
final ManyToOne manyToOneAnn = parentField.getDirectAnnotationUsage( ManyToOne.class );
6058
assertThat( manyToOneAnn ).isNotNull();
61-
final JoinColumnsOrFormulas joinColumnsOrFormulas = parentField.getDirectAnnotationUsage( JoinColumnsOrFormulas.class );
62-
assertThat( joinColumnsOrFormulas.value() ).hasSize( 1 );
63-
final JoinColumnOrFormula joinColumnOrFormula = joinColumnsOrFormulas.value()[0];
64-
assertThat( joinColumnOrFormula.formula() ).isNotNull();
65-
assertThat( joinColumnOrFormula.formula().value() ).isNull();
66-
final JoinColumn joinColumnAnn = joinColumnOrFormula.column();
59+
final JoinColumn joinColumnAnn = parentField.getAnnotationUsage( JoinColumn.class, modelsContext );
6760
assertThat( joinColumnAnn ).isNotNull();
6861
assertThat( joinColumnAnn.name() ).isEqualTo( "parent_fk" );
6962

0 commit comments

Comments
 (0)