avoid passing property-level information via the first AnnotatedJoinColumn
This commit is contained in:
parent
d9392d6601
commit
8b3030aa8b
|
@ -46,31 +46,31 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn {
|
|||
|
||||
public static AnnotatedDiscriminatorColumn buildDiscriminatorColumn(
|
||||
DiscriminatorType type,
|
||||
DiscriminatorColumn discAnn,
|
||||
DiscriminatorFormula discFormulaAnn,
|
||||
DiscriminatorColumn discriminatorColumn,
|
||||
DiscriminatorFormula discriminatorFormula,
|
||||
MetadataBuildingContext context) {
|
||||
final AnnotatedDiscriminatorColumn discriminatorColumn = new AnnotatedDiscriminatorColumn();
|
||||
discriminatorColumn.setBuildingContext( context );
|
||||
if ( discFormulaAnn != null ) {
|
||||
discriminatorColumn.setImplicit( false );
|
||||
discriminatorColumn.setFormula( discFormulaAnn.value() );
|
||||
final AnnotatedDiscriminatorColumn column = new AnnotatedDiscriminatorColumn();
|
||||
column.setBuildingContext( context );
|
||||
if ( discriminatorFormula != null ) {
|
||||
column.setImplicit( false );
|
||||
column.setFormula( discriminatorFormula.value() );
|
||||
}
|
||||
else if ( discAnn != null ) {
|
||||
discriminatorColumn.setImplicit( false );
|
||||
if ( !isEmptyAnnotationValue( discAnn.columnDefinition() ) ) {
|
||||
discriminatorColumn.setSqlType( discAnn.columnDefinition() );
|
||||
else if ( discriminatorColumn != null ) {
|
||||
column.setImplicit( false );
|
||||
if ( !isEmptyAnnotationValue( discriminatorColumn.columnDefinition() ) ) {
|
||||
column.setSqlType( discriminatorColumn.columnDefinition() );
|
||||
}
|
||||
if ( !isEmptyAnnotationValue( discAnn.name() ) ) {
|
||||
discriminatorColumn.setLogicalColumnName( discAnn.name() );
|
||||
if ( !isEmptyAnnotationValue( discriminatorColumn.name() ) ) {
|
||||
column.setLogicalColumnName( discriminatorColumn.name() );
|
||||
}
|
||||
discriminatorColumn.setNullable( false );
|
||||
column.setNullable( false );
|
||||
}
|
||||
else {
|
||||
discriminatorColumn.setImplicit( true );
|
||||
column.setImplicit( true );
|
||||
}
|
||||
setDiscriminatorType( type, discAnn, discriminatorColumn );
|
||||
discriminatorColumn.bind();
|
||||
return discriminatorColumn;
|
||||
setDiscriminatorType( type, discriminatorColumn, column );
|
||||
column.bind();
|
||||
return column;
|
||||
}
|
||||
|
||||
private static void setDiscriminatorType(
|
||||
|
|
|
@ -505,7 +505,7 @@ public final class AnnotationBinder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Bind a class having JSR175 annotations. Subclasses <b>have to</b> be bound after its parent class.
|
||||
* Bind an annotated class. A subclass must be bound <em>after</em> its superclass.
|
||||
*
|
||||
* @param clazzToProcess entity to bind as {@code XClass} instance
|
||||
* @param inheritanceStatePerClass Metadata about the inheritance relationships for all mapped classes
|
||||
|
@ -1048,10 +1048,9 @@ public final class AnnotationBinder {
|
|||
|| element.isAnnotationPresent(EmbeddedId.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process annotation of a particular property
|
||||
/**
|
||||
* Process annotation of a particular property or field.
|
||||
*/
|
||||
|
||||
public static void processElementAnnotations(
|
||||
PropertyHolder propertyHolder,
|
||||
Nullability nullability,
|
||||
|
|
|
@ -164,6 +164,7 @@ public class BinderHelper {
|
|||
// the entity which declares the association (used for exception message)
|
||||
PersistentClass associatedEntity,
|
||||
Value value,
|
||||
String propertyName,
|
||||
// true when we do the reverse side of a @ManyToMany
|
||||
boolean inverse,
|
||||
MetadataBuildingContext context) {
|
||||
|
@ -174,8 +175,6 @@ public class BinderHelper {
|
|||
// Property instance
|
||||
final AnnotatedJoinColumn firstColumn = columns[0];
|
||||
if ( !firstColumn.isImplicit()
|
||||
// only necessary for owning side of association
|
||||
&& !firstColumn.hasMappedBy()
|
||||
// not necessary for a primary key reference
|
||||
&& checkReferencedColumnsType( columns, targetEntity, context ) == NON_PK_REFERENCE ) {
|
||||
|
||||
|
@ -184,29 +183,21 @@ public class BinderHelper {
|
|||
// for a PersistentClass or Join in the hierarchy of
|
||||
// the target entity which has the first column
|
||||
final Object columnOwner = findColumnOwner( targetEntity, firstColumn.getReferencedColumn(), context );
|
||||
for ( AnnotatedJoinColumn col: columns ) {
|
||||
final Object owner = findColumnOwner( targetEntity, col.getReferencedColumn(), context );
|
||||
if ( owner == null ) {
|
||||
throw new AnnotationException( "A '@JoinColumn' for association "
|
||||
+ associationMessage( associatedEntity, columns[0] )
|
||||
+ " references a column named '" + col.getReferencedColumn()
|
||||
+ "' which is not mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "'" );
|
||||
}
|
||||
if ( owner != columnOwner ) {
|
||||
throw new AnnotationException( "The '@JoinColumn's for association "
|
||||
+ associationMessage( associatedEntity, columns[0] )
|
||||
+ " reference columns of different tables mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "' ('" + col.getReferencedColumn() +
|
||||
"' belongs to a different table to '" + firstColumn.getReferencedColumn() + "'" );
|
||||
}
|
||||
}
|
||||
checkColumnInSameTable( columns, targetEntity, associatedEntity, context, columnOwner );
|
||||
// find all properties mapped to each column
|
||||
final List<Property> properties = findPropertiesByColumns( columnOwner, columns, associatedEntity, context );
|
||||
// create a Property along with the new synthetic
|
||||
// Component if necessary (or reuse the existing
|
||||
// Property that matches exactly)
|
||||
final Property property = referencedProperty( targetEntity, inverse, columns, columnOwner, properties, context );
|
||||
final Property property = referencedProperty(
|
||||
targetEntity,
|
||||
associatedEntity,
|
||||
propertyName,
|
||||
inverse,
|
||||
columnOwner,
|
||||
properties,
|
||||
context
|
||||
);
|
||||
// register the mapping with the InFlightMetadataCollector
|
||||
registerSyntheticProperty(
|
||||
targetEntity,
|
||||
|
@ -220,6 +211,41 @@ public class BinderHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All the referenced columns must belong to the same table, that is
|
||||
* {@link #findColumnOwner(PersistentClass, String, MetadataBuildingContext)}
|
||||
* must return the same value for all of them.
|
||||
*/
|
||||
private static void checkColumnInSameTable(
|
||||
AnnotatedJoinColumn[] columns,
|
||||
PersistentClass targetEntity,
|
||||
PersistentClass associatedEntity,
|
||||
MetadataBuildingContext context,
|
||||
Object columnOwner) {
|
||||
final AnnotatedJoinColumn firstColumn = columns[0];
|
||||
for ( AnnotatedJoinColumn column: columns) {
|
||||
if ( column.hasMappedBy() ) {
|
||||
// we should only get called for owning side of association
|
||||
throw new AssertionFailure("no need to create synthetic properties for unowned collections");
|
||||
}
|
||||
final Object owner = findColumnOwner( targetEntity, column.getReferencedColumn(), context );
|
||||
if ( owner == null ) {
|
||||
throw new AnnotationException( "A '@JoinColumn' for association "
|
||||
+ associationMessage(associatedEntity, firstColumn)
|
||||
+ " references a column named '" + column.getReferencedColumn()
|
||||
+ "' which is not mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "'" );
|
||||
}
|
||||
if ( owner != columnOwner) {
|
||||
throw new AnnotationException( "The '@JoinColumn's for association "
|
||||
+ associationMessage(associatedEntity, firstColumn)
|
||||
+ " reference columns of different tables mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "' ('" + column.getReferencedColumn() +
|
||||
"' belongs to a different table to '" + firstColumn.getReferencedColumn() + "'" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the referenced columns correspond to exactly one property
|
||||
* of the primary table of the exact target entity subclass,
|
||||
|
@ -232,8 +258,9 @@ public class BinderHelper {
|
|||
*/
|
||||
private static Property referencedProperty(
|
||||
PersistentClass ownerEntity,
|
||||
PersistentClass associatedEntity,
|
||||
String propertyName,
|
||||
boolean inverse,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
Object columnOwner,
|
||||
List<Property> properties,
|
||||
MetadataBuildingContext context) {
|
||||
|
@ -253,9 +280,7 @@ public class BinderHelper {
|
|||
// mapped to the referenced columns. We need to shallow
|
||||
// clone those properties to mark them as non-insertable
|
||||
// and non-updatable
|
||||
final AnnotatedJoinColumn firstColumn = columns[0];
|
||||
final PersistentClass associatedClass = firstColumn.getPropertyHolder().getPersistentClass();
|
||||
final String syntheticPropertyName = syntheticPropertyName( firstColumn.getPropertyName(), inverse, associatedClass );
|
||||
final String syntheticPropertyName = syntheticPropertyName( propertyName, inverse, associatedEntity );
|
||||
return makeSyntheticComponentProperty( ownerEntity, columnOwner, context, syntheticPropertyName, properties );
|
||||
}
|
||||
}
|
||||
|
@ -826,7 +851,7 @@ public class BinderHelper {
|
|||
|
||||
final GeneratedValue generatedValueAnn = idXProperty.getAnnotation( GeneratedValue.class );
|
||||
if ( generatedValueAnn == null ) {
|
||||
// this should really never happen, but its easy to protect against it...
|
||||
// this should really never happen, but it's easy to protect against it...
|
||||
return new IdentifierGeneratorDefinition( "assigned", "assigned" );
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ public class ToOneFkSecondPass extends FkSecondPass {
|
|||
targetEntity,
|
||||
persistentClass,
|
||||
manyToOne,
|
||||
path,
|
||||
false,
|
||||
buildingContext
|
||||
);
|
||||
|
|
|
@ -94,7 +94,6 @@ import org.hibernate.annotations.common.reflection.XProperty;
|
|||
import org.hibernate.boot.BootLogging;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector.CollectionTypeRegistrationDescriptor;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
|
@ -245,6 +244,9 @@ public abstract class CollectionBinder {
|
|||
this.buildingContext = buildingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first pass at binding a collection.
|
||||
*/
|
||||
public static void bindCollection(
|
||||
PropertyHolder propertyHolder,
|
||||
Nullability nullability,
|
||||
|
@ -1506,8 +1508,10 @@ public abstract class CollectionBinder {
|
|||
return isNotEmpty( mappedBy );
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a {@link OneToMany} association.
|
||||
*/
|
||||
protected void bindOneToManySecondPass(Map<String, PersistentClass> persistentClasses) {
|
||||
|
||||
if ( property == null ) {
|
||||
throw new AssertionFailure( "null was passed for argument property" );
|
||||
}
|
||||
|
@ -1544,7 +1548,7 @@ public abstract class CollectionBinder {
|
|||
bindFilters( false );
|
||||
handleWhere( false );
|
||||
|
||||
PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
|
||||
final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
|
||||
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled, buildingContext );
|
||||
|
||||
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
|
||||
|
@ -1955,14 +1959,16 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a {@link ManyToMany} association or {@link ElementCollection}.
|
||||
*/
|
||||
private void bindManyToManySecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
|
||||
if ( property == null ) {
|
||||
throw new AssertionFailure( "null was passed for argument property" );
|
||||
}
|
||||
|
||||
final XClass elementType = getElementType();
|
||||
final PersistentClass targetEntity = persistentClasses.get( elementType.getName() );
|
||||
final PersistentClass targetEntity = persistentClasses.get( elementType.getName() ); //null if this is an @ElementCollection
|
||||
final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy );
|
||||
|
||||
final boolean isCollectionOfEntities = targetEntity != null;
|
||||
|
@ -2482,14 +2488,17 @@ public abstract class CollectionBinder {
|
|||
boolean cascadeDeleteEnabled,
|
||||
MetadataBuildingContext context) {
|
||||
|
||||
if ( !hasMappedBy() ) {
|
||||
createSyntheticPropertyReference(
|
||||
joinColumns,
|
||||
collection.getOwner(),
|
||||
collection.getOwner(),
|
||||
collection,
|
||||
propertyName,
|
||||
false,
|
||||
context
|
||||
);
|
||||
}
|
||||
|
||||
final DependantValue key = buildCollectionKey(
|
||||
collection,
|
||||
|
@ -2527,9 +2536,11 @@ public abstract class CollectionBinder {
|
|||
|
||||
|
||||
/**
|
||||
* Bind the inverse foreign key of a {@link ManyToMany}.
|
||||
* If we are in a mappedBy case, read the columns from the associated
|
||||
* collection element. Otherwise, delegate to the usual algorithm.
|
||||
* Bind the inverse foreign key of a {@link ManyToMany}, that is, the columns
|
||||
* specified by {@code @JoinTable(inverseJoinColumns=...)}, which are the
|
||||
* columns that reference the target entity of the many-to-many association.
|
||||
* If we are in a {@code mappedBy} case, read the columns from the associated
|
||||
* collection element in the target entity.
|
||||
*/
|
||||
public void bindManyToManyInverseForeignKey(
|
||||
PersistentClass targetEntity,
|
||||
|
@ -2560,6 +2571,7 @@ public abstract class CollectionBinder {
|
|||
targetEntity,
|
||||
collection.getOwner(),
|
||||
value,
|
||||
propertyName,
|
||||
true,
|
||||
context
|
||||
);
|
||||
|
|
|
@ -197,6 +197,9 @@ public class EntityBinder {
|
|||
private boolean cacheLazyProperty;
|
||||
private String naturalIdCacheRegion;
|
||||
|
||||
/**
|
||||
* Bind an entity class. This can be done in a single pass.
|
||||
*/
|
||||
public static void bindEntityClass(
|
||||
XClass clazzToProcess,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
|
@ -1555,7 +1558,6 @@ public class EntityBinder {
|
|||
return new LocalCacheAnnotationStub( region, determineCacheConcurrencyStrategy( context ) );
|
||||
}
|
||||
|
||||
@SuppressWarnings("ClassExplicitlyAnnotation")
|
||||
private static class LocalCacheAnnotationStub implements Cache {
|
||||
private final String region;
|
||||
private final CacheConcurrencyStrategy usage;
|
||||
|
|
|
@ -93,10 +93,8 @@ public class PropertyBinder {
|
|||
this.entityBinder = entityBinder;
|
||||
}
|
||||
|
||||
/*
|
||||
* property can be null
|
||||
* prefer propertyName to property.getName() since some are overloaded
|
||||
*/
|
||||
// property can be null
|
||||
// prefer propertyName to property.getName() since some are overloaded
|
||||
private XProperty property;
|
||||
private XClass returnedClass;
|
||||
private boolean isId;
|
||||
|
@ -234,7 +232,7 @@ public class PropertyBinder {
|
|||
}
|
||||
|
||||
private Property bind(Property prop) {
|
||||
if (isId) {
|
||||
if ( isId ) {
|
||||
final RootClass rootClass = ( RootClass ) holder.getPersistentClass();
|
||||
//if an xToMany, it has to be wrapped today.
|
||||
//FIXME this poses a problem as the PK is the class instead of the associated class which is not really compliant with the spec
|
||||
|
|
Loading…
Reference in New Issue