clean up collection SecondPass stuff
This commit is contained in:
parent
79642022a6
commit
070f7e5d3a
|
@ -481,11 +481,10 @@ public class AnnotatedColumn {
|
|||
* @throws AnnotationException missing secondary table
|
||||
*/
|
||||
public Table getTable() {
|
||||
if ( table != null ){
|
||||
if ( table != null ) {
|
||||
return table;
|
||||
}
|
||||
|
||||
if ( isSecondary() ) {
|
||||
else if ( isSecondary() ) {
|
||||
return getJoin().getTable();
|
||||
}
|
||||
else {
|
||||
|
@ -1013,9 +1012,15 @@ public class AnnotatedColumn {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"Column{table=%s, mappingColumn=%s, insertable=%s, updatable=%s, unique=%s}",
|
||||
getTable(), mappingColumn.getName(), insertable, updatable, unique
|
||||
);
|
||||
StringBuilder string = new StringBuilder();
|
||||
string.append( getClass().getSimpleName() ).append( "(" );
|
||||
if ( isNotEmpty( logicalColumnName ) ) {
|
||||
string.append( "column='" ).append( logicalColumnName ).append( "'" );
|
||||
}
|
||||
if ( isNotEmpty( formulaString ) ) {
|
||||
string.append( "formula='" ).append( formulaString ).append( "'" );
|
||||
}
|
||||
string.append( "'" );
|
||||
return string.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,13 +101,4 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"DiscriminatorColumn{logicalColumnName'%s', discriminatorTypeName='%s'}",
|
||||
getLogicalColumnName(),
|
||||
discriminatorTypeName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,22 +66,27 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
private String mappedByEntityName;
|
||||
private String mappedByJpaEntityName;
|
||||
private boolean JPA2ElementCollection;
|
||||
private String manyToManyOwnerSideEntityName;
|
||||
|
||||
//TODO: this is a bad way to determine the ImplicitJoinColumnNameSource.Nature
|
||||
|
||||
@Deprecated
|
||||
public void setJPA2ElementCollection(boolean JPA2ElementCollection) {
|
||||
this.JPA2ElementCollection = JPA2ElementCollection;
|
||||
}
|
||||
|
||||
// TODO hacky solution to get the information at property ref resolution
|
||||
//TODO: this is a bad way to get the information at property ref resolution
|
||||
|
||||
@Deprecated
|
||||
public String getManyToManyOwnerSideEntityName() {
|
||||
return manyToManyOwnerSideEntityName;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setManyToManyOwnerSideEntityName(String manyToManyOwnerSideEntityName) {
|
||||
this.manyToManyOwnerSideEntityName = manyToManyOwnerSideEntityName;
|
||||
}
|
||||
|
||||
private String manyToManyOwnerSideEntityName;
|
||||
|
||||
public void setReferencedColumn(String referencedColumn) {
|
||||
this.referencedColumn = referencedColumn;
|
||||
}
|
||||
|
@ -874,9 +879,15 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"JoinColumn{logicalColumnName='%s', referencedColumn='%s', mappedBy='%s'}",
|
||||
getLogicalColumnName(), referencedColumn, mappedBy
|
||||
);
|
||||
StringBuilder string = new StringBuilder();
|
||||
string.append( getClass().getSimpleName() ).append( "(" );
|
||||
if ( isNotEmpty( getLogicalColumnName() ) ) {
|
||||
string.append( "column='" ).append( getLogicalColumnName() ).append( "'" );
|
||||
}
|
||||
if ( isNotEmpty( referencedColumn ) ) {
|
||||
string.append( "referencedColumn='" ).append( referencedColumn ).append( "'" );
|
||||
}
|
||||
string.append( "'" );
|
||||
return string.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,6 +175,7 @@ import static org.hibernate.cfg.InheritanceState.getSuperclassInheritanceState;
|
|||
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY;
|
||||
|
||||
/**
|
||||
|
@ -2405,20 +2406,23 @@ public final class AnnotationBinder {
|
|||
final String propertyName = inferredData.getPropertyName();
|
||||
value.setTypeUsingReflection( propertyHolder.getClassName(), propertyName );
|
||||
|
||||
final String fullPath = qualify( propertyHolder.getPath(), propertyName );
|
||||
|
||||
bindForeignKeyNameAndDefinition(
|
||||
value,
|
||||
property,
|
||||
propertyHolder.getOverriddenForeignKey( StringHelper.qualify( propertyHolder.getPath(), propertyName ) ),
|
||||
propertyHolder.getOverriddenForeignKey( fullPath ),
|
||||
joinColumn,
|
||||
joinColumns,
|
||||
context
|
||||
);
|
||||
|
||||
final FkSecondPass secondPass = new ToOneFkSecondPass(
|
||||
value, columns,
|
||||
value,
|
||||
columns,
|
||||
!optional && unique, //cannot have nullable and unique on certain DBs like Derby
|
||||
propertyHolder.getEntityOwnerClassName(),
|
||||
propertyHolder.getPath() + "." + propertyName,
|
||||
propertyHolder.getPersistentClass(),
|
||||
fullPath,
|
||||
context
|
||||
);
|
||||
if ( inSecondPass ) {
|
||||
|
@ -2427,7 +2431,7 @@ public final class AnnotationBinder {
|
|||
else {
|
||||
context.getMetadataCollector().addSecondPass( secondPass );
|
||||
}
|
||||
AnnotatedColumn.checkPropertyConsistency( columns, propertyHolder.getEntityName() + "." + propertyName );
|
||||
AnnotatedColumn.checkPropertyConsistency( columns, qualify( propertyHolder.getEntityName(), propertyName ) );
|
||||
//PropertyBinder binder = new PropertyBinder();
|
||||
propertyBinder.setName( propertyName );
|
||||
propertyBinder.setValue( value );
|
||||
|
|
|
@ -159,11 +159,12 @@ public class BinderHelper {
|
|||
*/
|
||||
public static void createSyntheticPropertyReference(
|
||||
AnnotatedJoinColumn[] columns,
|
||||
PersistentClass ownerEntity,
|
||||
//associated entity only used for more precise exception
|
||||
// the target entity of the association, to which the columns belong
|
||||
PersistentClass targetEntity,
|
||||
// the entity which declares the association (used for exception message)
|
||||
PersistentClass associatedEntity,
|
||||
Value value,
|
||||
//true when we do the reverse side of a @ManyToMany
|
||||
// true when we do the reverse side of a @ManyToMany
|
||||
boolean inverse,
|
||||
MetadataBuildingContext context) {
|
||||
|
||||
|
@ -176,27 +177,28 @@ public class BinderHelper {
|
|||
// only necessary for owning side of association
|
||||
&& !firstColumn.hasMappedBy()
|
||||
// not necessary for a primary key reference
|
||||
&& checkReferencedColumnsType( columns, ownerEntity, context ) == NON_PK_REFERENCE ) {
|
||||
&& checkReferencedColumnsType( columns, targetEntity, context ) == NON_PK_REFERENCE ) {
|
||||
|
||||
// all the columns have to belong to the same table;
|
||||
// figure out which table has the columns by looking
|
||||
// for a PersistentClass or Join in the hierarchy of
|
||||
// the target entity which has the first column
|
||||
final Object columnOwner = findColumnOwner( ownerEntity, firstColumn.getReferencedColumn(), context );
|
||||
final Object columnOwner = findColumnOwner( targetEntity, firstColumn.getReferencedColumn(), context );
|
||||
for ( AnnotatedJoinColumn col: columns ) {
|
||||
Object owner = findColumnOwner( ownerEntity, col.getReferencedColumn(), context );
|
||||
final Object owner = findColumnOwner( targetEntity, col.getReferencedColumn(), context );
|
||||
if ( owner == null ) {
|
||||
throw new AnnotationException("A '@JoinColumn' for association "
|
||||
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" );
|
||||
+ "' 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 ('"
|
||||
+ col.getReferencedColumn() + "' belongs to a different table to '"
|
||||
+ firstColumn.getReferencedColumn() + "'" );
|
||||
+ " reference columns of different tables mapped by the target entity '"
|
||||
+ targetEntity.getEntityName() + "' ('" + col.getReferencedColumn() +
|
||||
"' belongs to a different table to '" + firstColumn.getReferencedColumn() + "'" );
|
||||
}
|
||||
}
|
||||
// find all properties mapped to each column
|
||||
|
@ -204,10 +206,10 @@ public class BinderHelper {
|
|||
// create a Property along with the new synthetic
|
||||
// Component if necessary (or reuse the existing
|
||||
// Property that matches exactly)
|
||||
final Property property = referencedProperty( ownerEntity, inverse, columns, columnOwner, properties, context );
|
||||
final Property property = referencedProperty( targetEntity, inverse, columns, columnOwner, properties, context );
|
||||
// register the mapping with the InFlightMetadataCollector
|
||||
registerSyntheticProperty(
|
||||
ownerEntity,
|
||||
targetEntity,
|
||||
value,
|
||||
inverse,
|
||||
firstColumn.getPropertyHolder().getPersistentClass(),
|
||||
|
|
|
@ -122,28 +122,27 @@ public class OneToOneSecondPass implements SecondPass {
|
|||
binder.setLazyGroup( lazyGroupAnnotation.value() );
|
||||
}
|
||||
|
||||
Property prop = binder.makeProperty();
|
||||
prop.setOptional( optional );
|
||||
Property property = binder.makeProperty();
|
||||
property.setOptional( optional );
|
||||
if ( isEmptyAnnotationValue( mappedBy ) ) {
|
||||
// we need to check if the columns are in the right order
|
||||
// if not, then we need to create a many to one and formula
|
||||
// but actually, since entities linked by a one to one need
|
||||
// to share the same composite id class, this cannot happen in hibernate
|
||||
// to share the same composite id class, this cannot happen
|
||||
boolean rightOrder = true;
|
||||
|
||||
if ( rightOrder ) {
|
||||
String path = qualify( propertyHolder.getPath(), propertyName );
|
||||
final ToOneFkSecondPass secondPass = new ToOneFkSecondPass(
|
||||
value,
|
||||
joinColumns,
|
||||
!optional, //cannot have nullabe and unique on certain DBs
|
||||
propertyHolder.getEntityOwnerClassName(),
|
||||
path,
|
||||
!optional, //cannot have nullable and unique on certain DBs
|
||||
propertyHolder.getPersistentClass(),
|
||||
qualify( propertyHolder.getPath(), propertyName ),
|
||||
buildingContext
|
||||
);
|
||||
secondPass.doSecondPass( persistentClasses );
|
||||
//no column associated since its a one to one
|
||||
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
|
||||
propertyHolder.addProperty( property, inferredData.getDeclaringClass() );
|
||||
}
|
||||
// else {
|
||||
//this is a many to one with Formula
|
||||
|
@ -169,7 +168,7 @@ public class OneToOneSecondPass implements SecondPass {
|
|||
+ "' which does not exist in the target entity type '" + value.getReferencedEntityName() + "'" );
|
||||
}
|
||||
if ( otherSideProperty.getValue() instanceof OneToOne ) {
|
||||
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
|
||||
propertyHolder.addProperty( property, inferredData.getDeclaringClass() );
|
||||
}
|
||||
else if ( otherSideProperty.getValue() instanceof ManyToOne ) {
|
||||
Join otherSideJoin = null;
|
||||
|
@ -193,7 +192,7 @@ public class OneToOneSecondPass implements SecondPass {
|
|||
manyToOne.setReferencedEntityName( value.getReferencedEntityName() );
|
||||
manyToOne.setUnwrapProxy( value.isUnwrapProxy() );
|
||||
manyToOne.markAsLogicalOneToOne();
|
||||
prop.setValue( manyToOne );
|
||||
property.setValue( manyToOne );
|
||||
for ( Column column: otherSideJoin.getKey().getColumns() ) {
|
||||
Column copy = new Column();
|
||||
copy.setLength( column.getLength() );
|
||||
|
@ -210,10 +209,10 @@ public class OneToOneSecondPass implements SecondPass {
|
|||
copy.setGeneratedAs(column.getGeneratedAs() );
|
||||
manyToOne.addColumn( copy );
|
||||
}
|
||||
mappedByJoin.addProperty( prop );
|
||||
mappedByJoin.addProperty( property );
|
||||
}
|
||||
else {
|
||||
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
|
||||
propertyHolder.addProperty( property, inferredData.getDeclaringClass() );
|
||||
}
|
||||
|
||||
value.setReferencedPropertyName( mappedBy );
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.hibernate.AssertionFailure;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.annotations.TableBinder;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.ManyToOne;
|
||||
|
@ -21,6 +20,7 @@ import org.hibernate.mapping.Property;
|
|||
import org.hibernate.mapping.ToOne;
|
||||
|
||||
import static org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference;
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
|
||||
/**
|
||||
* Enable a proper set of the FK columns in respect with the id column order
|
||||
|
@ -30,6 +30,7 @@ import static org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference;
|
|||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class ToOneFkSecondPass extends FkSecondPass {
|
||||
private final PersistentClass persistentClass;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
private final boolean unique;
|
||||
private final String path;
|
||||
|
@ -39,13 +40,14 @@ public class ToOneFkSecondPass extends FkSecondPass {
|
|||
ToOne value,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
boolean unique,
|
||||
String entityClassName,
|
||||
PersistentClass persistentClass,
|
||||
String path,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
super( value, columns );
|
||||
this.persistentClass = persistentClass;
|
||||
this.buildingContext = buildingContext;
|
||||
this.unique = unique;
|
||||
this.entityClassName = entityClassName;
|
||||
this.entityClassName = persistentClass.getClassName();
|
||||
this.path = entityClassName != null ? path.substring( entityClassName.length() + 1 ) : path;
|
||||
}
|
||||
|
||||
|
@ -56,8 +58,11 @@ public class ToOneFkSecondPass extends FkSecondPass {
|
|||
|
||||
@Override
|
||||
public boolean isInPrimaryKey() {
|
||||
if ( entityClassName == null ) return false;
|
||||
final PersistentClass persistentClass = buildingContext.getMetadataCollector().getEntityBinding( entityClassName );
|
||||
if ( entityClassName == null ) {
|
||||
return false;
|
||||
}
|
||||
final PersistentClass persistentClass = buildingContext.getMetadataCollector()
|
||||
.getEntityBinding( entityClassName );
|
||||
Property property = persistentClass.getIdentifierProperty();
|
||||
if ( path == null ) {
|
||||
return false;
|
||||
|
@ -91,14 +96,21 @@ public class ToOneFkSecondPass extends FkSecondPass {
|
|||
public void doSecondPass(java.util.Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
if ( value instanceof ManyToOne ) {
|
||||
final ManyToOne manyToOne = (ManyToOne) value;
|
||||
final PersistentClass referencedEntity = persistentClasses.get( manyToOne.getReferencedEntityName() );
|
||||
if ( referencedEntity == null ) {
|
||||
throw new AnnotationException( "Association '" + StringHelper.qualify( entityClassName, path )
|
||||
final PersistentClass targetEntity = persistentClasses.get( manyToOne.getReferencedEntityName() );
|
||||
if ( targetEntity == null ) {
|
||||
throw new AnnotationException( "Association '" + qualify( entityClassName, path )
|
||||
+ "' targets an unknown entity named '" + manyToOne.getReferencedEntityName() + "'" );
|
||||
}
|
||||
manyToOne.setPropertyName( path );
|
||||
createSyntheticPropertyReference( columns, referencedEntity, null, manyToOne, false, buildingContext );
|
||||
TableBinder.bindForeignKey( referencedEntity, null, columns, manyToOne, unique, buildingContext );
|
||||
createSyntheticPropertyReference(
|
||||
columns,
|
||||
targetEntity,
|
||||
persistentClass,
|
||||
manyToOne,
|
||||
false,
|
||||
buildingContext
|
||||
);
|
||||
TableBinder.bindForeignKey( targetEntity, persistentClass, columns, manyToOne, unique, buildingContext );
|
||||
// HbmMetadataSourceProcessorImpl does this only when property-ref != null, but IMO, it makes sense event if it is null
|
||||
if ( !manyToOne.isIgnoreNotFound() ) manyToOne.createPropertyRefConstraints( persistentClasses );
|
||||
}
|
||||
|
|
|
@ -190,18 +190,18 @@ public abstract class CollectionBinder {
|
|||
java.util.Collection.class
|
||||
);
|
||||
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
final MetadataBuildingContext buildingContext;
|
||||
private final Supplier<ManagedBean<? extends UserCollectionType>> customTypeBeanResolver;
|
||||
private final boolean isSortedCollection;
|
||||
|
||||
protected Collection collection;
|
||||
protected String propertyName;
|
||||
PropertyHolder propertyHolder;
|
||||
protected PropertyHolder propertyHolder;
|
||||
private int batchSize;
|
||||
private String mappedBy;
|
||||
private XClass collectionElementType;
|
||||
private XClass targetEntity;
|
||||
private AnnotatedJoinColumn[] inverseJoinColumns;
|
||||
protected AnnotatedJoinColumn[] inverseJoinColumns;
|
||||
private String cascadeStrategy;
|
||||
private String cacheConcurrencyStrategy;
|
||||
private String cacheRegionName;
|
||||
|
@ -211,15 +211,16 @@ public abstract class CollectionBinder {
|
|||
protected String mapKeyPropertyName;
|
||||
private boolean insertable = true;
|
||||
private boolean updatable = true;
|
||||
private AnnotatedJoinColumn[] fkJoinColumns;
|
||||
protected AnnotatedJoinColumn[] foreignJoinColumns;
|
||||
private AnnotatedJoinColumn[] joinColumns;
|
||||
private boolean isExplicitAssociationTable;
|
||||
private AnnotatedColumn[] elementColumns;
|
||||
private boolean isEmbedded;
|
||||
private XProperty property;
|
||||
private NotFoundAction notFoundAction;
|
||||
protected boolean isEmbedded;
|
||||
protected XProperty property;
|
||||
protected NotFoundAction notFoundAction;
|
||||
private TableBinder tableBinder;
|
||||
private AnnotatedColumn[] mapKeyColumns;
|
||||
private AnnotatedJoinColumn[] mapKeyManyToManyColumns;
|
||||
protected AnnotatedColumn[] mapKeyColumns;
|
||||
protected AnnotatedJoinColumn[] mapKeyManyToManyColumns;
|
||||
protected Map<String, IdentifierGeneratorDefinition> localGenerators;
|
||||
protected Map<XClass, InheritanceState> inheritanceStatePerClass;
|
||||
private XClass declaringClass;
|
||||
|
@ -713,8 +714,6 @@ public abstract class CollectionBinder {
|
|||
this.joinColumns = joinColumns;
|
||||
}
|
||||
|
||||
private AnnotatedJoinColumn[] joinColumns;
|
||||
|
||||
public void setPropertyHolder(PropertyHolder propertyHolder) {
|
||||
this.propertyHolder = propertyHolder;
|
||||
}
|
||||
|
@ -764,13 +763,13 @@ public abstract class CollectionBinder {
|
|||
return binder;
|
||||
}
|
||||
|
||||
private static CollectionBinder createBinderAutomatically(XProperty property, MetadataBuildingContext buildingContext) {
|
||||
final CollectionClassification classification = determineCollectionClassification( property, buildingContext );
|
||||
final CollectionTypeRegistrationDescriptor typeRegistration = buildingContext.getMetadataCollector()
|
||||
private static CollectionBinder createBinderAutomatically(XProperty property, MetadataBuildingContext context) {
|
||||
final CollectionClassification classification = determineCollectionClassification( property, context );
|
||||
final CollectionTypeRegistrationDescriptor typeRegistration = context.getMetadataCollector()
|
||||
.findCollectionTypeRegistration( classification );
|
||||
return typeRegistration != null
|
||||
? createBinderFromTypeRegistration( property, classification, typeRegistration, buildingContext )
|
||||
: createBinderFromProperty( property, buildingContext );
|
||||
? createBinderFromTypeRegistration( property, classification, typeRegistration, context )
|
||||
: createBinderFromProperty( property, context );
|
||||
}
|
||||
|
||||
private static CollectionBinder createBinderFromTypeRegistration(
|
||||
|
@ -796,16 +795,17 @@ public abstract class CollectionBinder {
|
|||
Class<? extends UserCollectionType> implementation,
|
||||
Map<String,String> parameters,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final StandardServiceRegistry serviceRegistry = buildingContext.getBuildingOptions().getServiceRegistry();
|
||||
final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class );
|
||||
final ManagedBeanRegistry beanRegistry = buildingContext.getBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.getService( ManagedBeanRegistry.class );
|
||||
if ( CollectionHelper.isNotEmpty( parameters ) ) {
|
||||
return beanRegistry.getBean( implementation );
|
||||
}
|
||||
else {
|
||||
// defined parameters...
|
||||
if ( ParameterizedType.class.isAssignableFrom( implementation ) ) {
|
||||
// because there are config parameters and the type is configurable, we need
|
||||
// a separate bean instance which means uniquely naming it
|
||||
// because there are config parameters and the type is configurable,
|
||||
// we need a separate bean instance which means uniquely naming it
|
||||
final ManagedBean<? extends UserCollectionType> typeBean = beanRegistry.getBean( role, implementation );
|
||||
final UserCollectionType type = typeBean.getBeanInstance();
|
||||
final Properties properties = new Properties();
|
||||
|
@ -828,11 +828,9 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static CollectionBinder createBinderFromProperty(
|
||||
XProperty property,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final CollectionClassification classification = determineCollectionClassification( property, buildingContext );
|
||||
return createBinder( property, null, classification, buildingContext );
|
||||
private static CollectionBinder createBinderFromProperty(XProperty property, MetadataBuildingContext context) {
|
||||
final CollectionClassification classification = determineCollectionClassification( property, context );
|
||||
return createBinder( property, null, classification, context );
|
||||
}
|
||||
|
||||
private static CollectionBinder createBinderFromCustomTypeAnnotation(
|
||||
|
@ -853,20 +851,18 @@ public abstract class CollectionBinder {
|
|||
public static ManagedBean<? extends UserCollectionType> resolveCustomType(
|
||||
XProperty property,
|
||||
CollectionType typeAnnotation,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final ManagedBeanRegistry beanRegistry = buildingContext.getBootstrapContext()
|
||||
MetadataBuildingContext context) {
|
||||
final ManagedBeanRegistry beanRegistry = context.getBootstrapContext()
|
||||
.getServiceRegistry()
|
||||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
final Class<? extends UserCollectionType> typeImpl = typeAnnotation.type();
|
||||
if ( typeAnnotation.parameters().length == 0 ) {
|
||||
// no parameters - we can re-use a no-config bean instance
|
||||
// no parameters - we can reuse a no-config bean instance
|
||||
return beanRegistry.getBean( typeImpl );
|
||||
}
|
||||
else {
|
||||
// defined parameters...
|
||||
final String attributeKey = property.getDeclaringClass().getName() + "#" + property.getName();
|
||||
|
||||
if ( ParameterizedType.class.isAssignableFrom( typeImpl ) ) {
|
||||
// because there are config parameters and the type is configurable, we need
|
||||
// a separate bean instance which means uniquely naming it
|
||||
|
@ -883,7 +879,6 @@ public abstract class CollectionBinder {
|
|||
attributeKey,
|
||||
ParameterizedType.class.getName()
|
||||
);
|
||||
|
||||
// but still return the bean - we can again use the no-config bean instance
|
||||
return beanRegistry.getBean( typeImpl );
|
||||
}
|
||||
|
@ -1095,8 +1090,8 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
public void bind() {
|
||||
this.collection = createCollection( propertyHolder.getPersistentClass() );
|
||||
String role = qualify( propertyHolder.getPath(), propertyName );
|
||||
collection = createCollection( propertyHolder.getPersistentClass() );
|
||||
final String role = qualify( propertyHolder.getPath(), propertyName );
|
||||
LOG.debugf( "Collection role: %s", role );
|
||||
collection.setRole( role );
|
||||
collection.setMappedByProperty( mappedBy );
|
||||
|
@ -1151,24 +1146,7 @@ public abstract class CollectionBinder {
|
|||
if ( inheritanceStatePerClass == null) {
|
||||
throw new AssertionFailure( "inheritanceStatePerClass not set" );
|
||||
}
|
||||
metadataCollector.addSecondPass(
|
||||
getSecondPass(
|
||||
fkJoinColumns,
|
||||
joinColumns,
|
||||
inverseJoinColumns,
|
||||
elementColumns,
|
||||
mapKeyColumns,
|
||||
mapKeyManyToManyColumns,
|
||||
isEmbedded,
|
||||
property,
|
||||
getElementType(),
|
||||
notFoundAction,
|
||||
oneToMany,
|
||||
tableBinder,
|
||||
buildingContext
|
||||
),
|
||||
!isMappedBy
|
||||
);
|
||||
metadataCollector.addSecondPass( getSecondPass(), !isMappedBy );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
|
@ -1464,7 +1442,7 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private XClass getElementType() {
|
||||
XClass getElementType() {
|
||||
if ( AnnotationBinder.isDefault( targetEntity, buildingContext ) ) {
|
||||
if ( collectionElementType != null ) {
|
||||
return collectionElementType;
|
||||
|
@ -1479,37 +1457,11 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
public SecondPass getSecondPass(
|
||||
final AnnotatedJoinColumn[] fkJoinColumns,
|
||||
final AnnotatedJoinColumn[] keyColumns,
|
||||
final AnnotatedJoinColumn[] inverseColumns,
|
||||
final AnnotatedColumn[] elementColumns,
|
||||
final AnnotatedColumn[] mapKeyColumns,
|
||||
final AnnotatedJoinColumn[] mapKeyManyToManyColumns,
|
||||
final boolean isEmbedded,
|
||||
final XProperty property,
|
||||
final XClass elementType,
|
||||
final NotFoundAction notFoundAction,
|
||||
final boolean unique,
|
||||
final TableBinder assocTableBinder,
|
||||
final MetadataBuildingContext buildingContext) {
|
||||
SecondPass getSecondPass() {
|
||||
return new CollectionSecondPass( collection ) {
|
||||
@Override
|
||||
public void secondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
bindStarToManySecondPass(
|
||||
persistentClasses,
|
||||
elementType,
|
||||
fkJoinColumns,
|
||||
keyColumns,
|
||||
inverseColumns,
|
||||
elementColumns,
|
||||
isEmbedded,
|
||||
property,
|
||||
unique,
|
||||
assocTableBinder,
|
||||
notFoundAction,
|
||||
buildingContext
|
||||
);
|
||||
bindStarToManySecondPass( persistentClasses );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1517,20 +1469,9 @@ public abstract class CollectionBinder {
|
|||
/**
|
||||
* return true if it's a Fk, false if it's an association table
|
||||
*/
|
||||
protected boolean bindStarToManySecondPass(
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
XClass elementType,
|
||||
AnnotatedJoinColumn[] fkJoinColumns,
|
||||
AnnotatedJoinColumn[] keyColumns,
|
||||
AnnotatedJoinColumn[] inverseColumns,
|
||||
AnnotatedColumn[] elementColumns,
|
||||
boolean isEmbedded,
|
||||
XProperty property,
|
||||
boolean unique,
|
||||
TableBinder associationTableBinder,
|
||||
NotFoundAction notFoundAction,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
PersistentClass persistentClass = persistentClasses.get( elementType.getName() );
|
||||
protected boolean bindStarToManySecondPass(Map<String, PersistentClass> persistentClasses) {
|
||||
final XClass elementType = getElementType();
|
||||
final PersistentClass persistentClass = persistentClasses.get( elementType.getName() );
|
||||
boolean reversePropertyInJoin = false;
|
||||
if ( persistentClass != null && hasMappedBy() ) {
|
||||
try {
|
||||
|
@ -1548,39 +1489,15 @@ public abstract class CollectionBinder {
|
|||
&& oneToMany
|
||||
&& !isExplicitAssociationTable
|
||||
&& ( joinColumns[0].isImplicit() && hasMappedBy() //implicit @JoinColumn
|
||||
|| !fkJoinColumns[0].isImplicit() ) //this is an explicit @JoinColumn
|
||||
|| !foreignJoinColumns[0].isImplicit() ) //this is an explicit @JoinColumn
|
||||
) {
|
||||
//this is a foreign key
|
||||
bindOneToManySecondPass(
|
||||
getCollection(),
|
||||
persistentClasses,
|
||||
fkJoinColumns,
|
||||
elementType,
|
||||
cascadeDeleteEnabled,
|
||||
notFoundAction,
|
||||
buildingContext,
|
||||
inheritanceStatePerClass
|
||||
);
|
||||
bindOneToManySecondPass( persistentClasses );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
//this is an association table
|
||||
bindManyToManySecondPass(
|
||||
this.collection,
|
||||
persistentClasses,
|
||||
keyColumns,
|
||||
inverseColumns,
|
||||
elementColumns,
|
||||
isEmbedded,
|
||||
elementType,
|
||||
notFoundAction,
|
||||
unique,
|
||||
cascadeDeleteEnabled,
|
||||
associationTableBinder,
|
||||
property,
|
||||
propertyHolder,
|
||||
buildingContext
|
||||
);
|
||||
bindManyToManySecondPass( persistentClasses );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1589,42 +1506,34 @@ public abstract class CollectionBinder {
|
|||
return isNotEmpty( mappedBy );
|
||||
}
|
||||
|
||||
protected void bindOneToManySecondPass(
|
||||
Collection collection,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
AnnotatedJoinColumn[] fkJoinColumns,
|
||||
XClass collectionType,
|
||||
boolean cascadeDeleteEnabled,
|
||||
NotFoundAction notFoundAction,
|
||||
MetadataBuildingContext buildingContext,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
protected void bindOneToManySecondPass(Map<String, PersistentClass> persistentClasses) {
|
||||
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Binding a OneToMany: %s.%s through a foreign key", propertyHolder.getEntityName(), propertyName );
|
||||
}
|
||||
if ( buildingContext == null ) {
|
||||
throw new AssertionFailure(
|
||||
"CollectionSecondPass for oneToMany should not be called with null mappings"
|
||||
);
|
||||
if ( property == null ) {
|
||||
throw new AssertionFailure( "null was passed for argument property" );
|
||||
}
|
||||
|
||||
logOneToManySeconPass();
|
||||
|
||||
final org.hibernate.mapping.OneToMany oneToMany =
|
||||
new org.hibernate.mapping.OneToMany( buildingContext, collection.getOwner() );
|
||||
new org.hibernate.mapping.OneToMany( buildingContext, getCollection().getOwner() );
|
||||
collection.setElement( oneToMany );
|
||||
oneToMany.setReferencedEntityName( collectionType.getName() );
|
||||
oneToMany.setReferencedEntityName( getElementType().getName() );
|
||||
oneToMany.setNotFoundAction( notFoundAction );
|
||||
|
||||
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||
|
||||
final String assocClass = oneToMany.getReferencedEntityName();
|
||||
final PersistentClass associatedClass = persistentClasses.get( assocClass );
|
||||
handleJpaOrderBy( collection, associatedClass );
|
||||
final Map<String, Join> joins = buildingContext.getMetadataCollector().getJoins( assocClass );
|
||||
final Map<String, Join> joins = collector.getJoins( assocClass );
|
||||
if ( associatedClass == null ) {
|
||||
throw new MappingException(
|
||||
String.format("Association [%s] for entity [%s] references unmapped class [%s]",
|
||||
propertyName, propertyHolder.getClassName(), assocClass)
|
||||
String.format( "Association [%s] for entity [%s] references unmapped class [%s]",
|
||||
propertyName, propertyHolder.getClassName(), assocClass )
|
||||
);
|
||||
}
|
||||
oneToMany.setAssociatedClass( associatedClass );
|
||||
for ( AnnotatedJoinColumn column : fkJoinColumns ) {
|
||||
for ( AnnotatedJoinColumn column : foreignJoinColumns ) {
|
||||
column.setPersistentClass( associatedClass, joins, inheritanceStatePerClass );
|
||||
column.setJoins( joins );
|
||||
collection.setCollectionTable( column.getTable() );
|
||||
|
@ -1635,23 +1544,16 @@ public abstract class CollectionBinder {
|
|||
bindFilters( false );
|
||||
handleWhere( false );
|
||||
|
||||
bindCollectionSecondPass(
|
||||
collection,
|
||||
null,
|
||||
fkJoinColumns,
|
||||
cascadeDeleteEnabled,
|
||||
property,
|
||||
propertyHolder,
|
||||
buildingContext
|
||||
);
|
||||
PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
|
||||
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled, buildingContext );
|
||||
|
||||
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
|
||||
// for non-inverse one-to-many, with a not-null fk, add a backref!
|
||||
final String entityName = oneToMany.getReferencedEntityName();
|
||||
final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName );
|
||||
final PersistentClass referenced = collector.getEntityBinding( entityName );
|
||||
final Backref backref = new Backref();
|
||||
AnnotatedJoinColumn fkColumn = fkJoinColumns[0];
|
||||
backref.setName( '_' + fkColumn.getPropertyName() + '_' + fkColumn.getLogicalColumnName() + "Backref" );
|
||||
final AnnotatedJoinColumn column = foreignJoinColumns[0];
|
||||
backref.setName( '_' + column.getPropertyName() + '_' + column.getLogicalColumnName() + "Backref" );
|
||||
backref.setUpdateable( false );
|
||||
backref.setSelectable( false );
|
||||
backref.setCollectionRole( collection.getRole() );
|
||||
|
@ -2053,90 +1955,70 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private void bindManyToManySecondPass(
|
||||
Collection collValue,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
AnnotatedJoinColumn[] inverseJoinColumns,
|
||||
AnnotatedColumn[] elementColumns,
|
||||
boolean isEmbedded,
|
||||
XClass elementType,
|
||||
NotFoundAction notFoundAction,
|
||||
boolean unique,
|
||||
boolean cascadeDeleteEnabled,
|
||||
TableBinder associationTableBinder,
|
||||
XProperty property,
|
||||
PropertyHolder parentPropertyHolder,
|
||||
MetadataBuildingContext buildingContext) throws MappingException {
|
||||
private void bindManyToManySecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||
|
||||
if ( property == null ) {
|
||||
throw new IllegalArgumentException( "null was passed for argument property" );
|
||||
throw new AssertionFailure( "null was passed for argument property" );
|
||||
}
|
||||
|
||||
final PersistentClass collectionEntity = persistentClasses.get( elementType.getName() );
|
||||
final XClass elementType = getElementType();
|
||||
final PersistentClass targetEntity = persistentClasses.get( elementType.getName() );
|
||||
final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy );
|
||||
|
||||
boolean isCollectionOfEntities = collectionEntity != null;
|
||||
boolean isManyToAny = property.isAnnotationPresent( ManyToAny.class );
|
||||
final boolean isCollectionOfEntities = targetEntity != null;
|
||||
final boolean isManyToAny = property.isAnnotationPresent( ManyToAny.class );
|
||||
|
||||
logManyToManySecondPass( oneToMany, isCollectionOfEntities, isManyToAny );
|
||||
|
||||
logManyToManySecondPass( collValue, joinColumns, unique, isCollectionOfEntities, isManyToAny );
|
||||
//check for user error
|
||||
detectManyToManyProblems(
|
||||
elementType,
|
||||
property,
|
||||
parentPropertyHolder,
|
||||
propertyHolder,
|
||||
isCollectionOfEntities,
|
||||
isManyToAny
|
||||
);
|
||||
|
||||
if ( hasMappedBy() ) {
|
||||
handleUnownedManyToMany(
|
||||
collValue,
|
||||
collection,
|
||||
joinColumns,
|
||||
elementType,
|
||||
collectionEntity,
|
||||
targetEntity,
|
||||
isCollectionOfEntities
|
||||
);
|
||||
}
|
||||
else {
|
||||
handleOwnedManyToMany(
|
||||
collValue,
|
||||
collection,
|
||||
joinColumns,
|
||||
associationTableBinder,
|
||||
tableBinder,
|
||||
property,
|
||||
buildingContext,
|
||||
collectionEntity,
|
||||
targetEntity,
|
||||
isCollectionOfEntities
|
||||
);
|
||||
}
|
||||
bindFilters( isCollectionOfEntities );
|
||||
handleWhere( isCollectionOfEntities );
|
||||
|
||||
bindCollectionSecondPass(
|
||||
collValue,
|
||||
collectionEntity,
|
||||
joinColumns,
|
||||
cascadeDeleteEnabled,
|
||||
property,
|
||||
propertyHolder,
|
||||
buildingContext
|
||||
);
|
||||
bindCollectionSecondPass( targetEntity, joinColumns, cascadeDeleteEnabled, buildingContext );
|
||||
|
||||
ManyToOne element = null;
|
||||
if ( isCollectionOfEntities ) {
|
||||
element = handleCollectionOfEntities(
|
||||
collValue,
|
||||
final ManyToOne element = handleCollectionOfEntities(
|
||||
collection,
|
||||
elementType,
|
||||
notFoundAction,
|
||||
property,
|
||||
buildingContext,
|
||||
collectionEntity,
|
||||
targetEntity,
|
||||
hqlOrderBy
|
||||
);
|
||||
bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany, buildingContext );
|
||||
}
|
||||
else if ( isManyToAny ) {
|
||||
handleManyToAny(
|
||||
collValue,
|
||||
collection,
|
||||
inverseJoinColumns,
|
||||
cascadeDeleteEnabled,
|
||||
property,
|
||||
|
@ -2145,28 +2027,22 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
else {
|
||||
handleElementCollection(
|
||||
collValue,
|
||||
collection,
|
||||
elementColumns,
|
||||
isEmbedded,
|
||||
elementType,
|
||||
property,
|
||||
parentPropertyHolder,
|
||||
propertyHolder,
|
||||
buildingContext,
|
||||
hqlOrderBy
|
||||
);
|
||||
}
|
||||
|
||||
checkFilterConditions( collValue );
|
||||
|
||||
//FIXME: do optional = false
|
||||
if ( isCollectionOfEntities ) {
|
||||
bindManyToManyInverseForeignKey( collectionEntity, inverseJoinColumns, element, unique, buildingContext );
|
||||
}
|
||||
|
||||
checkFilterConditions( collection );
|
||||
}
|
||||
|
||||
private void handleElementCollection(
|
||||
Collection collValue,
|
||||
Collection collection,
|
||||
AnnotatedColumn[] elementColumns,
|
||||
boolean isEmbedded,
|
||||
XClass elementType,
|
||||
|
@ -2174,16 +2050,15 @@ public abstract class CollectionBinder {
|
|||
PropertyHolder parentPropertyHolder,
|
||||
MetadataBuildingContext buildingContext,
|
||||
String hqlOrderBy) {
|
||||
XClass elementClass;
|
||||
AnnotatedClassType classType;
|
||||
CollectionPropertyHolder holder;
|
||||
final XClass elementClass;
|
||||
final AnnotatedClassType classType;
|
||||
final CollectionPropertyHolder holder;
|
||||
if ( PRIMITIVE_NAMES.contains( elementType.getName() ) ) {
|
||||
classType = AnnotatedClassType.NONE;
|
||||
elementClass = null;
|
||||
|
||||
holder = PropertyHolderBuilder.buildPropertyHolder(
|
||||
collValue,
|
||||
collValue.getRole(),
|
||||
collection,
|
||||
collection.getRole(),
|
||||
null,
|
||||
property,
|
||||
parentPropertyHolder,
|
||||
|
@ -2192,41 +2067,34 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
else {
|
||||
elementClass = elementType;
|
||||
classType = buildingContext.getMetadataCollector().getClassType( elementClass );
|
||||
|
||||
holder = PropertyHolderBuilder.buildPropertyHolder(
|
||||
collValue,
|
||||
collValue.getRole(),
|
||||
collection,
|
||||
collection.getRole(),
|
||||
elementClass,
|
||||
property,
|
||||
parentPropertyHolder,
|
||||
buildingContext
|
||||
);
|
||||
|
||||
// 'parentPropertyHolder' is the PropertyHolder for the owner of the collection
|
||||
// 'holder' is the CollectionPropertyHolder.
|
||||
// 'property' is the collection XProperty
|
||||
parentPropertyHolder.startingProperty(property);
|
||||
|
||||
parentPropertyHolder.startingProperty( property );
|
||||
//force in case of attribute override
|
||||
boolean attributeOverride = property.isAnnotationPresent( AttributeOverride.class )
|
||||
|| property.isAnnotationPresent( AttributeOverrides.class );
|
||||
// todo : force in the case of Convert annotation(s) with embedded paths (beyond key/value prefixes)?
|
||||
if ( isEmbedded || attributeOverride ) {
|
||||
classType = AnnotatedClassType.EMBEDDABLE;
|
||||
}
|
||||
classType = isEmbedded || attributeOverride
|
||||
? AnnotatedClassType.EMBEDDABLE
|
||||
: buildingContext.getMetadataCollector().getClassType(elementClass);
|
||||
}
|
||||
|
||||
final Class<? extends CompositeUserType<?>> compositeUserType = resolveCompositeUserType(
|
||||
property,
|
||||
elementClass,
|
||||
buildingContext
|
||||
);
|
||||
final Class<? extends CompositeUserType<?>> compositeUserType =
|
||||
resolveCompositeUserType( property, elementClass, buildingContext );
|
||||
if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) {
|
||||
holder.prepare(property);
|
||||
|
||||
EntityBinder entityBinder = new EntityBinder();
|
||||
PersistentClass owner = collValue.getOwner();
|
||||
final EntityBinder entityBinder = new EntityBinder();
|
||||
final PersistentClass owner = collection.getOwner();
|
||||
|
||||
final AccessType baseAccessType;
|
||||
final Access accessAnn = property.getAnnotation( Access.class );
|
||||
|
@ -2270,17 +2138,17 @@ public abstract class CollectionBinder {
|
|||
inheritanceStatePerClass
|
||||
);
|
||||
|
||||
collValue.setElement( component );
|
||||
collection.setElement( component );
|
||||
|
||||
if ( isNotEmpty(hqlOrderBy) ) {
|
||||
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment(hqlOrderBy);
|
||||
if ( isNotEmpty( hqlOrderBy ) ) {
|
||||
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
|
||||
if ( orderBy != null ) {
|
||||
collValue.setOrderBy( orderBy );
|
||||
collection.setOrderBy( orderBy );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.prepare(property);
|
||||
holder.prepare( property );
|
||||
|
||||
final BasicValueBinder elementBinder =
|
||||
new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext);
|
||||
|
@ -2300,21 +2168,21 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
//override the table
|
||||
for (AnnotatedColumn column : elementColumns) {
|
||||
column.setTable( collValue.getCollectionTable() );
|
||||
column.setTable( collection.getCollectionTable() );
|
||||
}
|
||||
elementBinder.setColumns(elementColumns);
|
||||
elementBinder.setType(
|
||||
property,
|
||||
elementClass,
|
||||
collValue.getOwnerEntityName(),
|
||||
collection.getOwnerEntityName(),
|
||||
holder.resolveElementAttributeConverterDescriptor( property, elementClass )
|
||||
);
|
||||
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
|
||||
elementBinder.setAccessType( accessType );
|
||||
collValue.setElement( elementBinder.make() );
|
||||
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment(hqlOrderBy);
|
||||
collection.setElement( elementBinder.make() );
|
||||
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
|
||||
if ( orderBy != null ) {
|
||||
collValue.setOrderBy( orderBy );
|
||||
collection.setOrderBy( orderBy );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2543,30 +2411,6 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private void logManyToManySecondPass(
|
||||
Collection collValue,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
boolean unique,
|
||||
boolean isCollectionOfEntities,
|
||||
boolean isManyToAny) {
|
||||
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
|
||||
if ( isCollectionOfEntities && unique) {
|
||||
LOG.debugf("Binding a OneToMany: %s through an association table", path);
|
||||
}
|
||||
else if (isCollectionOfEntities) {
|
||||
LOG.debugf("Binding a ManyToMany: %s", path);
|
||||
}
|
||||
else if (isManyToAny) {
|
||||
LOG.debugf("Binding a ManyToAny: %s", path);
|
||||
}
|
||||
else {
|
||||
LOG.debugf("Binding a collection of element: %s", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(
|
||||
XProperty property,
|
||||
XClass propertyClass,
|
||||
|
@ -2619,47 +2463,57 @@ public abstract class CollectionBinder {
|
|||
return null; // @OrderBy not found.
|
||||
}
|
||||
|
||||
private static void checkFilterConditions(Collection collValue) {
|
||||
private static void checkFilterConditions(Collection collection) {
|
||||
//for now it can't happen, but sometime soon...
|
||||
if ( ( collValue.getFilters().size() != 0 || isNotEmpty( collValue.getWhere() ) ) &&
|
||||
collValue.getFetchMode() == FetchMode.JOIN &&
|
||||
!( collValue.getElement() instanceof SimpleValue ) && //SimpleValue (CollectionOfElements) are always SELECT but it does not matter
|
||||
collValue.getElement().getFetchMode() != FetchMode.JOIN ) {
|
||||
if ( ( collection.getFilters().size() != 0 || isNotEmpty( collection.getWhere() ) )
|
||||
&& collection.getFetchMode() == FetchMode.JOIN
|
||||
&& !( collection.getElement() instanceof SimpleValue ) //SimpleValue (CollectionOfElements) are always SELECT but it does not matter
|
||||
&& collection.getElement().getFetchMode() != FetchMode.JOIN ) {
|
||||
throw new MappingException(
|
||||
"@ManyToMany or @ElementCollection defining filter or where without join fetching "
|
||||
+ "not valid within collection using join fetching[" + collValue.getRole() + "]"
|
||||
+ "not valid within collection using join fetching[" + collection.getRole() + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindCollectionSecondPass(
|
||||
Collection collValue,
|
||||
PersistentClass collectionEntity,
|
||||
PersistentClass targetEntity,
|
||||
AnnotatedJoinColumn[] joinColumns,
|
||||
boolean cascadeDeleteEnabled,
|
||||
XProperty property,
|
||||
PropertyHolder propertyHolder,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
try {
|
||||
createSyntheticPropertyReference(
|
||||
joinColumns,
|
||||
collValue.getOwner(),
|
||||
collectionEntity,
|
||||
collValue,
|
||||
false,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
catch (AnnotationException ex) {
|
||||
throw new AnnotationException( "Unable to map collection "
|
||||
+ collValue.getOwner().getClassName() + "." + property.getName(), ex );
|
||||
}
|
||||
DependantValue key = buildCollectionKey( collValue, joinColumns, cascadeDeleteEnabled,
|
||||
buildingContext.getBuildingOptions().isNoConstraintByDefault(), property, propertyHolder, buildingContext );
|
||||
MetadataBuildingContext context) {
|
||||
|
||||
createSyntheticPropertyReference(
|
||||
joinColumns,
|
||||
collection.getOwner(),
|
||||
collection.getOwner(),
|
||||
collection,
|
||||
false,
|
||||
context
|
||||
);
|
||||
|
||||
final DependantValue key = buildCollectionKey(
|
||||
collection,
|
||||
joinColumns,
|
||||
cascadeDeleteEnabled,
|
||||
context.getBuildingOptions().isNoConstraintByDefault(),
|
||||
property,
|
||||
propertyHolder,
|
||||
context
|
||||
);
|
||||
|
||||
//TODO: this is really warty
|
||||
if ( property.isAnnotationPresent( ElementCollection.class ) && joinColumns.length > 0 ) {
|
||||
joinColumns[0].setJPA2ElementCollection( true );
|
||||
}
|
||||
TableBinder.bindForeignKey( collValue.getOwner(), collectionEntity, joinColumns, key, false, buildingContext );
|
||||
|
||||
TableBinder.bindForeignKey(
|
||||
collection.getOwner(),
|
||||
targetEntity,
|
||||
joinColumns,
|
||||
key,
|
||||
false,
|
||||
context
|
||||
);
|
||||
key.sortProperties();
|
||||
}
|
||||
|
||||
|
@ -2678,36 +2532,48 @@ public abstract class CollectionBinder {
|
|||
* collection element. Otherwise, delegate to the usual algorithm.
|
||||
*/
|
||||
public void bindManyToManyInverseForeignKey(
|
||||
PersistentClass referencedEntity,
|
||||
PersistentClass targetEntity,
|
||||
AnnotatedJoinColumn[] columns,
|
||||
SimpleValue value,
|
||||
boolean unique,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
MetadataBuildingContext context) {
|
||||
if ( hasMappedBy() ) {
|
||||
final Property property = referencedEntity.getRecursiveProperty( mappedBy );
|
||||
final List<Selectable> mappedByColumns = mappedByColumns( referencedEntity, property );
|
||||
final Property property = targetEntity.getRecursiveProperty( mappedBy );
|
||||
final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property );
|
||||
for ( Selectable selectable: mappedByColumns ) {
|
||||
columns[0].linkValueUsingAColumnCopy( (Column) selectable, value );
|
||||
}
|
||||
final String referencedPropertyName = buildingContext.getMetadataCollector()
|
||||
.getPropertyReferencedAssociation( referencedEntity.getEntityName(), mappedBy );
|
||||
final String referencedPropertyName = context.getMetadataCollector()
|
||||
.getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy );
|
||||
if ( referencedPropertyName != null ) {
|
||||
//TODO always a many to one?
|
||||
( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName );
|
||||
buildingContext.getMetadataCollector().addUniquePropertyReference(
|
||||
referencedEntity.getEntityName(),
|
||||
referencedPropertyName
|
||||
);
|
||||
context.getMetadataCollector()
|
||||
.addUniquePropertyReference( targetEntity.getEntityName(), referencedPropertyName );
|
||||
}
|
||||
( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null );
|
||||
value.createForeignKey();
|
||||
}
|
||||
else {
|
||||
createSyntheticPropertyReference( columns, referencedEntity, null, value, true, buildingContext );
|
||||
createSyntheticPropertyReference(
|
||||
columns,
|
||||
targetEntity,
|
||||
collection.getOwner(),
|
||||
value,
|
||||
true,
|
||||
context
|
||||
);
|
||||
if ( notFoundAction == NotFoundAction.IGNORE ) {
|
||||
value.disableForeignKey();
|
||||
}
|
||||
TableBinder.bindForeignKey( referencedEntity, null, columns, value, unique, buildingContext );
|
||||
TableBinder.bindForeignKey(
|
||||
targetEntity,
|
||||
collection.getOwner(),
|
||||
columns,
|
||||
value,
|
||||
unique,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2732,7 +2598,7 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
public void setFkJoinColumns(AnnotatedJoinColumn[] annotatedJoinColumns) {
|
||||
this.fkJoinColumns = annotatedJoinColumns;
|
||||
this.foreignJoinColumns = annotatedJoinColumns;
|
||||
}
|
||||
|
||||
public void setExplicitAssociationTable(boolean explicitAssocTable) {
|
||||
|
@ -2770,4 +2636,31 @@ public abstract class CollectionBinder {
|
|||
public void setLocalGenerators(Map<String, IdentifierGeneratorDefinition> localGenerators) {
|
||||
this.localGenerators = localGenerators;
|
||||
}
|
||||
|
||||
private void logOneToManySeconPass() {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Binding a OneToMany: %s through a foreign key", safeCollectionRole() );
|
||||
}
|
||||
}
|
||||
|
||||
private void logManyToManySecondPass(
|
||||
boolean isOneToMany,
|
||||
boolean isCollectionOfEntities,
|
||||
boolean isManyToAny) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
if ( isCollectionOfEntities && isOneToMany ) {
|
||||
LOG.debugf( "Binding a OneToMany: %s through an association table", safeCollectionRole() );
|
||||
}
|
||||
else if ( isCollectionOfEntities ) {
|
||||
LOG.debugf( "Binding a ManyToMany: %s", safeCollectionRole() );
|
||||
}
|
||||
else if ( isManyToAny ) {
|
||||
LOG.debugf( "Binding a ManyToAny: %s", safeCollectionRole() );
|
||||
}
|
||||
else {
|
||||
LOG.debugf( "Binding a collection of element: %s", safeCollectionRole() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1800,12 +1800,12 @@ public class EntityBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private void bindJoinToPersistentClass(Join join, AnnotatedJoinColumn[] annotatedJoinColumns, MetadataBuildingContext buildingContext) {
|
||||
DependantValue key = new DependantValue( buildingContext, join.getTable(), persistentClass.getIdentifier() );
|
||||
private void bindJoinToPersistentClass(Join join, AnnotatedJoinColumn[] joinColumns, MetadataBuildingContext context) {
|
||||
DependantValue key = new DependantValue( context, join.getTable(), persistentClass.getIdentifier() );
|
||||
join.setKey( key );
|
||||
setForeignKeyNameIfDefined( join );
|
||||
key.setCascadeDeleteEnabled( false );
|
||||
TableBinder.bindForeignKey( persistentClass, null, annotatedJoinColumns, key, false, buildingContext );
|
||||
TableBinder.bindForeignKey( persistentClass, null, joinColumns, key, false, context );
|
||||
key.sortProperties();
|
||||
join.createPrimaryKey();
|
||||
join.createForeignKey();
|
||||
|
|
|
@ -52,33 +52,8 @@ public class IdBagBinder extends BagBinder {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean bindStarToManySecondPass(
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
XClass collType,
|
||||
AnnotatedJoinColumn[] fkJoinColumns,
|
||||
AnnotatedJoinColumn[] keyColumns,
|
||||
AnnotatedJoinColumn[] inverseColumns,
|
||||
AnnotatedColumn[] elementColumns,
|
||||
boolean isEmbedded,
|
||||
XProperty property,
|
||||
boolean unique,
|
||||
TableBinder associationTableBinder,
|
||||
NotFoundAction notFoundAction,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
boolean result = super.bindStarToManySecondPass(
|
||||
persistentClasses,
|
||||
collType,
|
||||
fkJoinColumns,
|
||||
keyColumns,
|
||||
inverseColumns,
|
||||
elementColumns,
|
||||
isEmbedded,
|
||||
property,
|
||||
unique,
|
||||
associationTableBinder,
|
||||
notFoundAction,
|
||||
getBuildingContext()
|
||||
);
|
||||
protected boolean bindStarToManySecondPass(Map<String, PersistentClass> persistentClasses) {
|
||||
boolean result = super.bindStarToManySecondPass( persistentClasses );
|
||||
|
||||
final CollectionId collectionIdAnn = property.getAnnotation( CollectionId.class );
|
||||
if ( collectionIdAnn == null ) {
|
||||
|
@ -120,7 +95,7 @@ public class IdBagBinder extends BagBinder {
|
|||
|
||||
valueBinder.setType(
|
||||
property,
|
||||
collType,
|
||||
getElementType(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
|
|
@ -63,39 +63,13 @@ public class ListBinder extends CollectionBinder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SecondPass getSecondPass(
|
||||
final AnnotatedJoinColumn[] fkJoinColumns,
|
||||
final AnnotatedJoinColumn[] keyColumns,
|
||||
final AnnotatedJoinColumn[] inverseColumns,
|
||||
final AnnotatedColumn[] elementColumns,
|
||||
AnnotatedColumn[] mapKeyColumns,
|
||||
final AnnotatedJoinColumn[] mapKeyManyToManyColumns,
|
||||
final boolean isEmbedded,
|
||||
final XProperty property,
|
||||
final XClass elementType,
|
||||
final NotFoundAction notFoundAction,
|
||||
final boolean unique,
|
||||
final TableBinder assocTableBinder,
|
||||
final MetadataBuildingContext buildingContext) {
|
||||
public SecondPass getSecondPass() {
|
||||
return new CollectionSecondPass( ListBinder.this.collection ) {
|
||||
@Override
|
||||
public void secondPass(Map<String, PersistentClass> persistentClasses)
|
||||
throws MappingException {
|
||||
bindStarToManySecondPass(
|
||||
persistentClasses,
|
||||
elementType,
|
||||
fkJoinColumns,
|
||||
keyColumns,
|
||||
inverseColumns,
|
||||
elementColumns,
|
||||
isEmbedded,
|
||||
property,
|
||||
unique,
|
||||
assocTableBinder,
|
||||
notFoundAction,
|
||||
buildingContext
|
||||
);
|
||||
bindIndex( property, elementType, buildingContext );
|
||||
bindStarToManySecondPass( persistentClasses );
|
||||
bindIndex( property, getElementType(), buildingContext );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.AssertionFailure;
|
|||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.MapKeyCompositeType;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
|
@ -89,31 +88,21 @@ public class MapBinder extends CollectionBinder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SecondPass getSecondPass(
|
||||
final AnnotatedJoinColumn[] fkJoinColumns,
|
||||
final AnnotatedJoinColumn[] keyColumns,
|
||||
final AnnotatedJoinColumn[] inverseColumns,
|
||||
final AnnotatedColumn[] elementColumns,
|
||||
final AnnotatedColumn[] mapKeyColumns,
|
||||
final AnnotatedJoinColumn[] mapKeyManyToManyColumns,
|
||||
final boolean isEmbedded,
|
||||
final XProperty property,
|
||||
final XClass collType,
|
||||
final NotFoundAction notFoundAction,
|
||||
final boolean unique,
|
||||
final TableBinder assocTableBinder,
|
||||
final MetadataBuildingContext buildingContext) {
|
||||
SecondPass getSecondPass() {
|
||||
return new CollectionSecondPass( MapBinder.this.collection ) {
|
||||
public void secondPass(Map<String, PersistentClass> persistentClasses)
|
||||
throws MappingException {
|
||||
bindStarToManySecondPass(
|
||||
persistentClasses, collType, fkJoinColumns, keyColumns, inverseColumns, elementColumns,
|
||||
isEmbedded, property, unique, assocTableBinder, notFoundAction, buildingContext
|
||||
);
|
||||
bindStarToManySecondPass( persistentClasses );
|
||||
bindKeyFromAssociationTable(
|
||||
collType, persistentClasses, mapKeyPropertyName, property, isEmbedded, buildingContext,
|
||||
mapKeyColumns, mapKeyManyToManyColumns,
|
||||
inverseColumns != null ? inverseColumns[0].getPropertyName() : null
|
||||
getElementType(),
|
||||
persistentClasses,
|
||||
mapKeyPropertyName,
|
||||
property,
|
||||
isEmbedded,
|
||||
buildingContext,
|
||||
mapKeyColumns,
|
||||
mapKeyManyToManyColumns,
|
||||
inverseJoinColumns != null ? inverseJoinColumns[0].getPropertyName() : null
|
||||
);
|
||||
makeOneToManyMapKeyColumnNullableIfNotInProperty( property );
|
||||
}
|
||||
|
|
|
@ -543,7 +543,7 @@ public class TableBinder {
|
|||
associatedClass = destinationEntity;
|
||||
}
|
||||
else {
|
||||
PropertyHolder holder = columns[0].getPropertyHolder();
|
||||
final PropertyHolder holder = columns[0].getPropertyHolder();
|
||||
associatedClass = holder == null ? null : holder.getPersistentClass();
|
||||
}
|
||||
|
||||
|
@ -594,6 +594,7 @@ public class TableBinder {
|
|||
PersistentClass associatedClass) {
|
||||
//implicit case, we hope PK and FK columns are in the same order
|
||||
if ( columns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
|
||||
// TODO: what about secondary tables?? associatedClass is null?
|
||||
throw new AnnotationException(
|
||||
"An association that targets entity '" + referencedEntity.getEntityName()
|
||||
+ "' from entity '" + associatedClass.getEntityName()
|
||||
|
|
|
@ -120,53 +120,57 @@ public enum CollectionClassification {
|
|||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( value instanceof CollectionClassification ) {
|
||||
return ( (CollectionClassification) value );
|
||||
else if ( value instanceof CollectionClassification ) {
|
||||
return (CollectionClassification) value;
|
||||
}
|
||||
|
||||
if ( value instanceof String ) {
|
||||
else if ( value instanceof String ) {
|
||||
final String string = (String) value;
|
||||
for ( CollectionClassification collectionClassification : values() ) {
|
||||
if ( collectionClassification.name().equalsIgnoreCase( string ) ) {
|
||||
return collectionClassification;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if ( value instanceof Class ) {
|
||||
return interpretClass( (Class<?>) value );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static CollectionClassification interpretClass(Class<?> configuredClass) {
|
||||
if ( java.util.List.class.isAssignableFrom(configuredClass) ) {
|
||||
return LIST;
|
||||
}
|
||||
if ( SortedSet.class.isAssignableFrom(configuredClass) ) {
|
||||
return SORTED_SET;
|
||||
}
|
||||
if ( java.util.Set.class.isAssignableFrom(configuredClass) ) {
|
||||
return SET;
|
||||
}
|
||||
if ( SortedMap.class.isAssignableFrom(configuredClass) ) {
|
||||
return SORTED_MAP;
|
||||
}
|
||||
if ( java.util.Map.class.isAssignableFrom(configuredClass) ) {
|
||||
return MAP;
|
||||
}
|
||||
if ( java.util.Collection.class.isAssignableFrom(configuredClass) ) {
|
||||
return BAG;
|
||||
}
|
||||
|
||||
if ( value instanceof Class ) {
|
||||
final Class<?> configuredClass = (Class<?>) value;
|
||||
if ( java.util.List.class.isAssignableFrom( configuredClass ) ) {
|
||||
return LIST;
|
||||
}
|
||||
if ( SortedSet.class.isAssignableFrom( configuredClass ) ) {
|
||||
return SORTED_SET;
|
||||
}
|
||||
if ( java.util.Set.class.isAssignableFrom( configuredClass ) ) {
|
||||
return SET;
|
||||
}
|
||||
if ( SortedMap.class.isAssignableFrom( configuredClass ) ) {
|
||||
return SORTED_MAP;
|
||||
}
|
||||
if ( java.util.Map.class.isAssignableFrom( configuredClass ) ) {
|
||||
return MAP;
|
||||
}
|
||||
if ( java.util.Collection.class.isAssignableFrom( configuredClass ) ) {
|
||||
return BAG;
|
||||
}
|
||||
|
||||
BootLogging.BOOT_LOGGER.debugf(
|
||||
"Unexpected Class specified for CollectionClassification resolution (`%s`) - " +
|
||||
"should be one of `%s`, `%s`, `%s`, `%s`, `%s` or `%s` (or subclass of)",
|
||||
configuredClass.getName(),
|
||||
java.util.List.class.getName(),
|
||||
SortedSet.class.getName(),
|
||||
java.util.Set.class.getName(),
|
||||
SortedMap.class.isAssignableFrom( configuredClass ),
|
||||
java.util.Map.class.isAssignableFrom( configuredClass ),
|
||||
java.util.Collection.class.getName()
|
||||
);
|
||||
}
|
||||
BootLogging.BOOT_LOGGER.debugf(
|
||||
"Unexpected Class specified for CollectionClassification resolution (`%s`) - " +
|
||||
"should be one of `%s`, `%s`, `%s`, `%s`, `%s` or `%s` (or subclass of)",
|
||||
configuredClass.getName(),
|
||||
java.util.List.class.getName(),
|
||||
SortedSet.class.getName(),
|
||||
java.util.Set.class.getName(),
|
||||
SortedMap.class.isAssignableFrom(configuredClass),
|
||||
java.util.Map.class.isAssignableFrom(configuredClass),
|
||||
java.util.Collection.class.getName()
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.cfg.annotations;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.AnnotatedJoinColumn;
|
||||
import org.hibernate.cfg.InheritanceState;
|
||||
import org.hibernate.cfg.PropertyHolder;
|
||||
import org.hibernate.cfg.annotations.CollectionBinder;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test for HHH-10106
|
||||
*
|
||||
* @author Vyacheslav Rarata
|
||||
*/
|
||||
public class CollectionBinderTest extends BaseUnitTestCase {
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-10106")
|
||||
public void testAssociatedClassException() throws SQLException {
|
||||
final Collection collection = mock(Collection.class);
|
||||
final XClass collectionType = mock(XClass.class);
|
||||
final MetadataBuildingContext buildingContext = mock(MetadataBuildingContext.class);
|
||||
final InFlightMetadataCollector inFly = mock(InFlightMetadataCollector.class);
|
||||
final PersistentClass persistentClass = mock(PersistentClass.class);
|
||||
final Table table = mock(Table.class);
|
||||
|
||||
when(buildingContext.getMetadataCollector()).thenReturn(inFly);
|
||||
when(collection.getOwner()).thenReturn(persistentClass);
|
||||
when(collectionType.getName()).thenReturn("List");
|
||||
when(persistentClass.getTable()).thenReturn(table);
|
||||
when(table.getName()).thenReturn("Hibernate");
|
||||
|
||||
String expectMessage = "Association [abc] for entity [CollectionBinderTest] references unmapped class [List]";
|
||||
try {
|
||||
new CollectionBinder( null, false, buildingContext ) {
|
||||
|
||||
{
|
||||
final PropertyHolder propertyHolder = Mockito.mock(PropertyHolder.class);
|
||||
when(propertyHolder.getClassName()).thenReturn( CollectionBinderTest.class.getSimpleName() );
|
||||
this.propertyName = "abc";
|
||||
setPropertyHolder( propertyHolder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindOneToManySecondPass(
|
||||
Collection collection,
|
||||
Map<String, PersistentClass> persistentClasses,
|
||||
AnnotatedJoinColumn[] fkJoinColumns,
|
||||
XClass collectionType,
|
||||
boolean cascadeDeleteEnabled,
|
||||
NotFoundAction notFoundAction,
|
||||
MetadataBuildingContext buildingContext,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass) {
|
||||
super.bindOneToManySecondPass(
|
||||
collection,
|
||||
persistentClasses,
|
||||
fkJoinColumns,
|
||||
collectionType,
|
||||
cascadeDeleteEnabled,
|
||||
notFoundAction,
|
||||
buildingContext,
|
||||
inheritanceStatePerClass
|
||||
);
|
||||
}
|
||||
}.bindOneToManySecondPass( collection, new HashMap(), null, collectionType, false, null, buildingContext, null);
|
||||
} catch (MappingException e) {
|
||||
assertEquals(expectMessage, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue