HHH-15111 MappingException is thrown for @JoinColumn with referencedColumnName on a @SecondaryTable
This commit is contained in:
parent
cd78676608
commit
1d67993173
|
@ -69,6 +69,7 @@ import org.hibernate.cfg.PropertyData;
|
|||
import org.hibernate.cfg.QuerySecondPass;
|
||||
import org.hibernate.cfg.RecoverableException;
|
||||
import org.hibernate.cfg.SecondPass;
|
||||
import org.hibernate.cfg.SecondaryTableFromAnnotationSecondPass;
|
||||
import org.hibernate.cfg.SecondaryTableSecondPass;
|
||||
import org.hibernate.cfg.SetBasicValueTypeSecondPass;
|
||||
import org.hibernate.cfg.UniqueConstraintHolder;
|
||||
|
@ -1591,6 +1592,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
private ArrayList<FkSecondPass> fkSecondPassList;
|
||||
private ArrayList<CreateKeySecondPass> createKeySecondPasList;
|
||||
private ArrayList<SecondaryTableSecondPass> secondaryTableSecondPassList;
|
||||
private ArrayList<SecondaryTableFromAnnotationSecondPass> secondaryTableFromAnnotationSecondPassesList;
|
||||
private ArrayList<QuerySecondPass> querySecondPassList;
|
||||
private ArrayList<ImplicitColumnNamingSecondPass> implicitColumnNamingSecondPassList;
|
||||
|
||||
|
@ -1618,6 +1620,12 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
else if ( secondPass instanceof SecondaryTableSecondPass ) {
|
||||
addSecondaryTableSecondPass( (SecondaryTableSecondPass) secondPass, onTopOfTheQueue );
|
||||
}
|
||||
else if ( secondPass instanceof SecondaryTableFromAnnotationSecondPass ) {
|
||||
addSecondaryTableFromAnnotationSecondPass(
|
||||
(SecondaryTableFromAnnotationSecondPass) secondPass,
|
||||
onTopOfTheQueue
|
||||
);
|
||||
}
|
||||
else if ( secondPass instanceof QuerySecondPass ) {
|
||||
addQuerySecondPass( (QuerySecondPass) secondPass, onTopOfTheQueue );
|
||||
}
|
||||
|
@ -1677,6 +1685,13 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
addSecondPass( secondPass, secondaryTableSecondPassList, onTopOfTheQueue );
|
||||
}
|
||||
|
||||
private void addSecondaryTableFromAnnotationSecondPass(SecondaryTableFromAnnotationSecondPass secondPass, boolean onTopOfTheQueue){
|
||||
if ( secondaryTableFromAnnotationSecondPassesList == null ) {
|
||||
secondaryTableFromAnnotationSecondPassesList = new ArrayList<>();
|
||||
}
|
||||
addSecondPass( secondPass, secondaryTableFromAnnotationSecondPassesList, onTopOfTheQueue );
|
||||
}
|
||||
|
||||
private void addQuerySecondPass(QuerySecondPass secondPass, boolean onTopOfTheQueue) {
|
||||
if ( querySecondPassList == null ) {
|
||||
querySecondPassList = new ArrayList<>();
|
||||
|
@ -1765,6 +1780,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
|
||||
private void processFkSecondPassesInOrder() {
|
||||
if ( fkSecondPassList == null || fkSecondPassList.isEmpty() ) {
|
||||
processSecondPasses( secondaryTableFromAnnotationSecondPassesList );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1798,6 +1814,8 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
sp.doSecondPass( getEntityBindingMap() );
|
||||
}
|
||||
|
||||
processSecondPasses( secondaryTableFromAnnotationSecondPassesList );
|
||||
|
||||
processEndOfQueue( endOfQueueFkSecondPasses );
|
||||
|
||||
fkSecondPassList.clear();
|
||||
|
|
|
@ -705,6 +705,8 @@ public final class AnnotationBinder {
|
|||
context.getMetadataCollector().addEntityBinding( persistentClass );
|
||||
|
||||
//Process secondary tables and complementary definitions (ie o.h.a.Table)
|
||||
context.getMetadataCollector()
|
||||
.addSecondPass( new SecondaryTableFromAnnotationSecondPass( entityBinder, propertyHolder, clazzToProcess ) );
|
||||
context.getMetadataCollector()
|
||||
.addSecondPass( new SecondaryTableSecondPass( entityBinder, propertyHolder, clazzToProcess ) );
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package org.hibernate.cfg;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
|
||||
import org.hibernate.cfg.annotations.EntityBinder;
|
||||
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) {
|
||||
this.entityBinder = entityBinder;
|
||||
this.propertyHolder = propertyHolder;
|
||||
this.annotatedClass = annotatedClass;
|
||||
}
|
||||
|
||||
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
entityBinder.finalSecondaryTableFromAnnotationBinding( propertyHolder );
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.Cacheable;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
|
@ -125,6 +127,9 @@ public class EntityBinder {
|
|||
// atm we use both from here; HBM binding solely uses InFlightMetadataCollector.EntityTableXref
|
||||
private final java.util.Map<String, Join> secondaryTables = new HashMap<>();
|
||||
private final java.util.Map<String, Object> secondaryTableJoins = new HashMap<>();
|
||||
private final java.util.Map<String, Join> secondaryTablesFromAnnotation = new HashMap<>();
|
||||
private final java.util.Map<String, Object> secondaryTableFromAnnotationJoins = new HashMap<>();
|
||||
|
||||
private final List<Filter> filters = new ArrayList<>();
|
||||
private boolean ignoreIdAnnotations;
|
||||
private AccessType propertyAccessType = AccessType.DEFAULT;
|
||||
|
@ -813,13 +818,28 @@ public class EntityBinder {
|
|||
* Those operations has to be done after the id definition of the persistence class.
|
||||
* ie after the properties parsing
|
||||
*/
|
||||
Iterator<Join> joins = secondaryTables.values().iterator();
|
||||
Iterator<Object> joinColumns = secondaryTableJoins.values().iterator();
|
||||
|
||||
while ( joins.hasNext() ) {
|
||||
Object uncastedColumn = joinColumns.next();
|
||||
Join join = joins.next();
|
||||
createPrimaryColumnsToSecondaryTable( uncastedColumn, propertyHolder, join );
|
||||
for ( Map.Entry<String, Join> entrySet : secondaryTables.entrySet() ) {
|
||||
if ( !secondaryTablesFromAnnotation.containsKey( entrySet.getKey() ) ) {
|
||||
Object uncastedColumn = joinColumns.next();
|
||||
createPrimaryColumnsToSecondaryTable( uncastedColumn, propertyHolder, entrySet.getValue() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finalSecondaryTableFromAnnotationBinding(PropertyHolder propertyHolder) {
|
||||
/*
|
||||
* Those operations have to be done before the end of the FK second pass processing in order
|
||||
* to find the join columns belonging to secondary tables
|
||||
*/
|
||||
Iterator<Object> joinColumns = secondaryTableFromAnnotationJoins.values().iterator();
|
||||
|
||||
for ( Map.Entry<String, Join> entrySet : secondaryTables.entrySet() ) {
|
||||
if ( secondaryTablesFromAnnotation.containsKey( entrySet.getKey() ) ) {
|
||||
Object uncastedColumn = joinColumns.next();
|
||||
createPrimaryColumnsToSecondaryTable( uncastedColumn, propertyHolder, entrySet.getValue() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1106,8 +1126,15 @@ public class EntityBinder {
|
|||
createPrimaryColumnsToSecondaryTable( joinColumns, propertyHolder, join );
|
||||
}
|
||||
else {
|
||||
secondaryTables.put( table.getQuotedName(), join );
|
||||
secondaryTableJoins.put( table.getQuotedName(), joinColumns );
|
||||
final String quotedName = table.getQuotedName();
|
||||
if ( secondaryTable != null ) {
|
||||
secondaryTablesFromAnnotation.put( quotedName, join );
|
||||
secondaryTableFromAnnotationJoins.put( quotedName, joinColumns );
|
||||
}
|
||||
else {
|
||||
secondaryTableJoins.put( quotedName, joinColumns );
|
||||
}
|
||||
secondaryTables.put( quotedName, join );
|
||||
}
|
||||
|
||||
return join;
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package org.hibernate.orm.test.annotations.joincolumn;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.DiscriminatorColumn;
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Inheritance;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.SecondaryTable;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
JoinColumnWithSecondaryTableTest.Being.class,
|
||||
JoinColumnWithSecondaryTableTest.Animal.class,
|
||||
JoinColumnWithSecondaryTableTest.Cat.class,
|
||||
JoinColumnWithSecondaryTableTest.Toy.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@TestForIssue( jiraKey = "HHH-15111")
|
||||
public class JoinColumnWithSecondaryTableTest {
|
||||
|
||||
@Test
|
||||
public void testIt(SessionFactoryScope scope){
|
||||
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "being")
|
||||
@Inheritance
|
||||
@DiscriminatorColumn(name = "type")
|
||||
public static abstract class Being {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@SecondaryTable(name = "animal")
|
||||
public static abstract class Animal extends Being {
|
||||
@Column(name = "uuid", table = "animal")
|
||||
private String uuid;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@SecondaryTable(name = "cat")
|
||||
@DiscriminatorValue(value = "CAT")
|
||||
public static class Cat extends Animal {
|
||||
@Column(name = "name", table = "cat")
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Toy {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "animal_uuid", referencedColumnName = "uuid")
|
||||
private Cat cat;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue