HHH-7037 Adding 'AttributeBinding locateAttributeBinding(List<Value> values)' to AttributeBindingContainer in order to locate a attribute binding by its relational values

This commit is contained in:
Hardy Ferentschik 2012-05-18 18:38:15 +02:00
parent 2cd5752ffe
commit 5a0f6628c9
5 changed files with 208 additions and 143 deletions

View File

@ -349,53 +349,22 @@ public class Binder {
attributeSource.getForeignKeyTargetColumnResolutionDelegate();
final ForeignKeyContributingSource.JoinColumnResolutionContext resolutionContext;
if ( resolutionDelegate != null ) {
resolutionContext = new ForeignKeyContributingSource.JoinColumnResolutionContext() {
@Override
public List< Value > resolveRelationalValuesForAttribute( String attributeName ) {
final AttributeBinding referencedAttributeBinding =
referencedEntityBinding.locateAttributeBinding( attributeName );
if ( !referencedAttributeBinding.getAttribute().isSingular() ) {
throw bindingContext().makeMappingException(
String.format(
"Many-to-one attribute [%s] named plural attribute as property-ref [%s]",
attributeSource.getName(),
attributeName ) );
}
List< Value > values = new ArrayList< Value >();
SingularAttributeBinding referencedAttributeBindingAsSingular =
( SingularAttributeBinding ) referencedAttributeBinding;
for ( RelationalValueBinding valueBinding : referencedAttributeBindingAsSingular.getRelationalValueBindings() ) {
values.add( valueBinding.getValue() );
}
return values;
}
@Override
public Column resolveColumn(
String logicalColumnName,
String logicalTableName,
String logicalSchemaName,
String logicalCatalogName ) {
return metadata.getDatabase().getSchema( logicalSchemaName, logicalCatalogName ).locateTable(
Identifier.toIdentifier( logicalTableName ) ).locateColumn( logicalColumnName );
}
};
resolutionContext = new JoinColumnResolutionContext(referencedEntityBinding, attributeSource);
} else {
resolutionContext = null;
}
ForeignKey foreignKey =
createOrLocateForeignKey(
attributeSource.getExplicitForeignKeyName(),
table,
referencedEntityBinding.getPrimaryTable() );
ForeignKey foreignKey = createOrLocateForeignKey(
attributeSource.getExplicitForeignKeyName(),
table,
referencedEntityBinding.getPrimaryTable()
);
final AttributeBinding referencedAttributeBinding =
determineReferencedAttributeBinding(
resolutionDelegate,
attributeBindingContainer,
referencedEntityBinding,
foreignKey );
final AttributeBinding referencedAttributeBinding = determineReferencedAttributeBinding(
resolutionDelegate,
resolutionContext,
referencedEntityBinding
);
if ( !referencedAttributeBinding.getAttribute().isSingular() ) {
throw bindingContext().makeMappingException(
String.format(
@ -1155,36 +1124,18 @@ public class Binder {
private AttributeBinding determineReferencedAttributeBinding(
ForeignKeyContributingSource.JoinColumnResolutionDelegate resolutionDelegate,
AttributeBindingContainer sourceAttributeBindingContainer,
EntityBinding referencedEntityBinding,
ForeignKey foreignKey ) {
ForeignKeyContributingSource.JoinColumnResolutionContext resolutionContext,
EntityBinding referencedEntityBinding) {
if ( resolutionDelegate == null ) {
return referencedEntityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding();
}
final String explicitName = resolutionDelegate.getReferencedAttributeName();
final String referencedAttributeName =
explicitName != null ? explicitName : determineReferencedAttributeName(
sourceAttributeBindingContainer,
referencedEntityBinding,
foreignKey );
return referencedEntityBinding.locateAttributeBinding( referencedAttributeName );
}
private String determineReferencedAttributeName(
AttributeBindingContainer sourceAttributeBindingContainer,
EntityBinding referencedEntityBinding,
ForeignKey foreignKey ) {
// todo : implement this.
// this needs to attempt to resolve the target columns from ForeignKey to an attribute on
// referencedEntityBinding that uses those columns. the original annotation-binder
// logic for this resides in org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference
//
// this is "needed" in order to pass the property name on to
// org.hibernate.type.ManyToOneType. Maybe there is just a better way to handle whatever
// org.hibernate.type.ManyToOneType needs this for.
return null;
String explicitName = resolutionDelegate.getReferencedAttributeName();
if(explicitName != null) {
return referencedEntityBinding.locateAttributeBinding( explicitName );
} else {
return referencedEntityBinding.locateAttributeBinding(resolutionDelegate.getJoinColumns( resolutionContext ) );
}
}
private void bindPrimaryTable( final EntityBinding entityBinding, final EntitySource entitySource ) {
@ -1613,7 +1564,7 @@ public class Binder {
String foreignKeyName,
TableSpecification sourceTable,
TableSpecification targetTable ) {
ForeignKey foreignKey = null;
ForeignKey foreignKey;
if ( foreignKeyName == null ) {
// todo: for now lets assume we have to create it, but eventually we should look through the
// candidate foreign keys referencing targetTable also...
@ -1823,7 +1774,9 @@ public class Binder {
return metadata.getTypeResolver().getTypeFactory().map(
mapBinding.getAttribute().getRole(),
mapBinding.getReferencedPropertyName(),
mapBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() == PluralAttributeElementNature.COMPOSITE );
mapBinding.getPluralAttributeElementBinding()
.getPluralAttributeElementNature() == PluralAttributeElementNature.COMPOSITE
);
}
}
@ -1834,7 +1787,9 @@ public class Binder {
return metadata.getTypeResolver().getTypeFactory().set(
setBinding.getAttribute().getRole(),
setBinding.getReferencedPropertyName(),
setBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() == PluralAttributeElementNature.COMPOSITE );
setBinding.getPluralAttributeElementBinding()
.getPluralAttributeElementNature() == PluralAttributeElementNature.COMPOSITE
);
}
}
@ -1906,4 +1861,56 @@ public class Binder {
String defaultName();
}
public class JoinColumnResolutionContext implements ForeignKeyContributingSource.JoinColumnResolutionContext {
private final EntityBinding referencedEntityBinding;
private final ToOneAttributeSource attributeSource;
public JoinColumnResolutionContext(EntityBinding referencedEntityBinding, ToOneAttributeSource attributeSource) {
this.referencedEntityBinding = referencedEntityBinding;
this.attributeSource = attributeSource;
}
@Override
public List< Value > resolveRelationalValuesForAttribute( String attributeName ) {
final AttributeBinding referencedAttributeBinding =
referencedEntityBinding.locateAttributeBinding( attributeName );
if ( !referencedAttributeBinding.getAttribute().isSingular() ) {
throw bindingContext().makeMappingException(
String.format(
"Many-to-one attribute [%s] named plural attribute as property-ref [%s]",
attributeSource.getName(),
attributeName ) );
}
List< Value > values = new ArrayList< Value >();
SingularAttributeBinding referencedAttributeBindingAsSingular =
( SingularAttributeBinding ) referencedAttributeBinding;
for ( RelationalValueBinding valueBinding : referencedAttributeBindingAsSingular.getRelationalValueBindings() ) {
values.add( valueBinding.getValue() );
}
return values;
}
@Override
public Column resolveColumn(
String logicalColumnName,
String logicalTableName,
String logicalSchemaName,
String logicalCatalogName ) {
Identifier tableIdentifier = Identifier.toIdentifier(logicalTableName);
if(tableIdentifier == null) {
tableIdentifier = referencedEntityBinding.getPrimaryTable().getLogicalName();
}
Schema schema = metadata.getDatabase().getSchema( logicalSchemaName, logicalCatalogName );
Table table = schema.locateTable(tableIdentifier );
if(bindingContexts.peek().isGloballyQuotedIdentifiers() && !StringHelper.isQuoted(logicalColumnName)) {
logicalColumnName = StringHelper.quote( logicalColumnName );
}
return table.locateColumn( logicalColumnName );
}
}
}

View File

@ -37,6 +37,7 @@ import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHe
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
import org.hibernate.metamodel.spi.source.SingularAttributeNature;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
@ -89,47 +90,10 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
"Encountered multiple JoinColumns mixing primary-target-columns and alternate-target-columns"
);
}
return new JoinColumnResolutionDelegate() {
private final String logicalJoinTableName = resolveLogicalJoinTableName();
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
final List<Value> values = new ArrayList<Value>();
for ( Column column : associationAttribute.getColumnValues() ) {
values.add(
context.resolveColumn(
column.getReferencedColumnName(),
logicalJoinTableName,
null,
null
)
);
}
return values;
}
@Override
public String getReferencedAttributeName() {
return null;
}
};
return new AnnotationJoinColumnResolutionDelegate();
}
}
private String resolveLogicalJoinTableName() {
final AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation(
associationAttribute.annotations(),
JPADotNames.JOIN_TABLE
);
if ( joinTableAnnotation != null ) {
return JandexHelper.getValue( joinTableAnnotation, "table", String.class );
}
// todo : this ties into the discussion about naming strategies. This would be part of a logical naming strategy...
return null;
}
@Override
public String getExplicitForeignKeyName() {
return null;
@ -147,9 +111,10 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
@Override
public FetchTiming getFetchTiming() {
if(associationAttribute.isLazy()) {
if ( associationAttribute.isLazy() ) {
return FetchTiming.DELAYED;
} else {
}
else {
return FetchTiming.IMMEDIATE;
}
}
@ -158,6 +123,50 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
public FetchStyle getFetchStyle() {
return associationAttribute.getFetchStyle();
}
public class AnnotationJoinColumnResolutionDelegate
implements ForeignKeyContributingSource.JoinColumnResolutionDelegate {
private final String logicalJoinTableName;
public AnnotationJoinColumnResolutionDelegate() {
logicalJoinTableName = resolveLogicalJoinTableName();
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
final List<Value> values = new ArrayList<Value>();
for ( Column column : associationAttribute.getColumnValues() ) {
org.hibernate.metamodel.spi.relational.Column resolvedColumn = context.resolveColumn(
column.getReferencedColumnName(),
logicalJoinTableName,
null,
null
);
values.add( resolvedColumn );
}
return values;
}
@Override
public String getReferencedAttributeName() {
// in annotations we are not referencing attribute but column names via @JoinColumn(s)
return null;
}
private String resolveLogicalJoinTableName() {
final AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation(
associationAttribute.annotations(),
JPADotNames.JOIN_TABLE
);
if ( joinTableAnnotation != null ) {
return JandexHelper.getValue( joinTableAnnotation, "table", String.class );
}
// todo : this ties into the discussion about naming strategies. This would be part of a logical naming strategy...
return null;
}
}
}

View File

@ -29,6 +29,7 @@ import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.spi.domain.AttributeContainer;
import org.hibernate.metamodel.spi.domain.PluralAttribute;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
/**
@ -64,10 +65,19 @@ public interface AttributeBindingContainer {
*
* @param name The name of the attribute, local to this container.
*
* @return The attribute binding.
* @return The attribute binding or {@code null} if none could be found.
*/
public AttributeBinding locateAttributeBinding(String name);
/**
* Locate a specific attribute binding, by its values.
*
* @param values The list of values
*
* @return The attribute binding or {@code null} if none could be found.
*/
public AttributeBinding locateAttributeBinding(List<Value> values);
/**
* Factory method for basic attribute bindings.
*

View File

@ -185,6 +185,20 @@ public class CompositeAttributeBinding
return attributeBindingMap.get( name );
}
@Override
public AttributeBinding locateAttributeBinding(List<org.hibernate.metamodel.spi.relational.Value> values) {
for(AttributeBinding attributeBinding : attributeBindingMap.values()) {
if(!(attributeBinding instanceof BasicAttributeBinding)) {
continue;
}
BasicAttributeBinding basicAttributeBinding = (BasicAttributeBinding) attributeBinding;
if(basicAttributeBinding.getRelationalValueBindings().equals( values )) {
return attributeBinding;
}
}
return null;
}
@Override
public Iterable<AttributeBinding> attributeBindings() {
return attributeBindingMap.values();

View File

@ -65,7 +65,7 @@ public class EntityBinding implements AttributeBindingContainer {
private Entity entity;
private TableSpecification primaryTable;
private String primaryTableName;
private String primaryTableName;
private Map<String, SecondaryTable> secondaryTables = new HashMap<String, SecondaryTable>();
private Value<Class<?>> proxyInterfaceType;
@ -103,7 +103,7 @@ public class EntityBinding implements AttributeBindingContainer {
private Set<String> synchronizedTableNames = new HashSet<String>();
private Map<String, AttributeBinding> attributeBindingMap = new HashMap<String, AttributeBinding>();
private List<JpaCallbackSource> jpaCallbackClasses = new ArrayList<JpaCallbackSource>();
private List<JpaCallbackSource> jpaCallbackClasses = new ArrayList<JpaCallbackSource>();
/**
* Used to instantiate the EntityBinding for an entity that is the root of an inheritance hierarchy
@ -140,9 +140,9 @@ public class EntityBinding implements AttributeBindingContainer {
}
public boolean isPolymorphic() {
return superEntityBinding != null ||
return superEntityBinding != null ||
hierarchyDetails.getEntityDiscriminator() != null ||
! subEntityBindings.isEmpty();
!subEntityBindings.isEmpty();
}
public boolean hasSubEntityBindings() {
@ -180,7 +180,7 @@ public class EntityBinding implements AttributeBindingContainer {
subclassIterables.add( subSubEntityBindings );
}
}
if ( ! subEntityBindings.isEmpty() ) {
if ( !subEntityBindings.isEmpty() ) {
subclassIterables.add( subEntityBindings );
}
return new JoinedIterable<EntityBinding>( subclassIterables );
@ -193,7 +193,7 @@ public class EntityBinding implements AttributeBindingContainer {
* Note that the returned value specifically excludes this entity binding.
*
* @return sub-entity bindings ordered as a depth-first,
* pre-order traversal
* pre-order traversal
*/
public Iterable<EntityBinding> getPreOrderSubEntityBindingClosure() {
return getPreOrderSubEntityBindingClosure( false );
@ -205,7 +205,9 @@ public class EntityBinding implements AttributeBindingContainer {
iterables.add( java.util.Collections.singletonList( this ) );
}
for ( EntityBinding subEntityBinding : subEntityBindings ) {
Iterable<EntityBinding> subSubEntityBindingClosure = subEntityBinding.getPreOrderSubEntityBindingClosure( true );
Iterable<EntityBinding> subSubEntityBindingClosure = subEntityBinding.getPreOrderSubEntityBindingClosure(
true
);
if ( subSubEntityBindingClosure.iterator().hasNext() ) {
iterables.add( subSubEntityBindingClosure );
}
@ -229,10 +231,10 @@ public class EntityBinding implements AttributeBindingContainer {
this.primaryTable = primaryTable;
}
public TableSpecification locateTable(String tableName) {
if ( tableName == null || tableName.equals( getPrimaryTableName() ) ) {
return primaryTable;
}
public TableSpecification locateTable(String tableName) {
if ( tableName == null || tableName.equals( getPrimaryTableName() ) ) {
return primaryTable;
}
SecondaryTable secondaryTable = secondaryTables.get( tableName );
if ( secondaryTable == null ) {
throw new AssertionFailure(
@ -244,14 +246,15 @@ public class EntityBinding implements AttributeBindingContainer {
);
}
return secondaryTable.getSecondaryTableReference();
}
public String getPrimaryTableName() {
return primaryTableName;
}
}
public void setPrimaryTableName(String primaryTableName) {
this.primaryTableName = primaryTableName;
}
public String getPrimaryTableName() {
return primaryTableName;
}
public void setPrimaryTableName(String primaryTableName) {
this.primaryTableName = primaryTableName;
}
public void addSecondaryTable(SecondaryTable secondaryTable) {
secondaryTables.put( secondaryTable.getSecondaryTableReference().getLogicalName().getName(), secondaryTable );
@ -528,7 +531,7 @@ public class EntityBinding implements AttributeBindingContainer {
SingularAttribute syntheticAttribute,
List<SingularAttributeBinding> subAttributeBindings,
MetaAttributeContext metaAttributeContext) {
if ( ! syntheticAttribute.isSynthetic() ) {
if ( !syntheticAttribute.isSynthetic() ) {
throw new AssertionFailure(
"Illegal attempt to create synthetic attribute binding from non-synthetic attribute reference"
);
@ -600,7 +603,7 @@ public class EntityBinding implements AttributeBindingContainer {
boolean includedInOptimisticLocking,
boolean lazy,
MetaAttributeContext metaAttributeContext,
int base ) {
int base) {
Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.LIST );
final ListBinding binding = new ListBinding(
this,
@ -611,7 +614,8 @@ public class EntityBinding implements AttributeBindingContainer {
includedInOptimisticLocking,
lazy,
metaAttributeContext,
base );
base
);
registerAttributeBinding( attribute.getName(), binding );
return binding;
}
@ -624,7 +628,7 @@ public class EntityBinding implements AttributeBindingContainer {
String propertyAccessorName,
boolean includedInOptimisticLocking,
boolean lazy,
MetaAttributeContext metaAttributeContext ) {
MetaAttributeContext metaAttributeContext) {
Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.MAP );
final MapBinding binding = new MapBinding(
this,
@ -634,7 +638,8 @@ public class EntityBinding implements AttributeBindingContainer {
propertyAccessorName,
includedInOptimisticLocking,
lazy,
metaAttributeContext );
metaAttributeContext
);
registerAttributeBinding( attribute.getName(), binding );
return binding;
}
@ -647,7 +652,7 @@ public class EntityBinding implements AttributeBindingContainer {
String propertyAccessorName,
boolean includedInOptimisticLocking,
boolean lazy,
MetaAttributeContext metaAttributeContext ) {
MetaAttributeContext metaAttributeContext) {
Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.SET );
final SetBinding binding = new SetBinding(
this,
@ -668,6 +673,26 @@ public class EntityBinding implements AttributeBindingContainer {
return attributeBindingMap.get( name );
}
@Override
public AttributeBinding locateAttributeBinding(List<org.hibernate.metamodel.spi.relational.Value> values) {
for(AttributeBinding attributeBinding : attributeBindingMap.values()) {
if(!(attributeBinding instanceof BasicAttributeBinding)) {
continue;
}
BasicAttributeBinding basicAttributeBinding = (BasicAttributeBinding) attributeBinding;
List<org.hibernate.metamodel.spi.relational.Value> attributeValues = new ArrayList<org.hibernate.metamodel.spi.relational.Value>( );
for(RelationalValueBinding relationalBinding : basicAttributeBinding.getRelationalValueBindings()) {
attributeValues.add( relationalBinding.getValue() );
}
if(attributeValues.equals( values )) {
return attributeBinding;
}
}
return null;
}
@Override
public Iterable<AttributeBinding> attributeBindings() {
return attributeBindingMap.values();
@ -711,8 +736,8 @@ public class EntityBinding implements AttributeBindingContainer {
/**
* @return the attribute bindings for this EntityBinding and all of its
* sub-EntityBinding, starting from the root of the hierarchy; includes
* the identifier and attribute bindings defined as part of a join.
* sub-EntityBinding, starting from the root of the hierarchy; includes
* the identifier and attribute bindings defined as part of a join.
*/
public Iterable<AttributeBinding> getSubEntityAttributeBindingClosure() {
List<Iterable<AttributeBinding>> iterables = new ArrayList<Iterable<AttributeBinding>>();
@ -725,11 +750,11 @@ public class EntityBinding implements AttributeBindingContainer {
return new JoinedIterable<AttributeBinding>( iterables );
}
public void setJpaCallbackClasses( List<JpaCallbackSource> jpaCallbackClasses ) {
this.jpaCallbackClasses = jpaCallbackClasses;
public void setJpaCallbackClasses(List<JpaCallbackSource> jpaCallbackClasses) {
this.jpaCallbackClasses = jpaCallbackClasses;
}
public Iterable<JpaCallbackSource> getJpaCallbackClasses() {
return jpaCallbackClasses;
}
public Iterable<JpaCallbackSource> getJpaCallbackClasses() {
return jpaCallbackClasses;
}
}