HHH-8360 HHH-7843 : one-to-one and mappedBy associations

HHH-8360 HHH-7843 : one-to-one and mappedBy associations
This commit is contained in:
Gail Badner 2013-07-17 16:34:30 -07:00
parent c9738beaf4
commit 00fed4c443
87 changed files with 2893 additions and 1340 deletions

View File

@ -123,6 +123,7 @@ public class ForeignKeyHelper {
final AttributeBinding referencedAttributeBinding = explicitName != null
? referencedEntityBinding.locateAttributeBindingByPath( explicitName, true )
: referencedEntityBinding.locateAttributeBinding(
resolutionDelegate.getReferencedTable( resolutionContext ),
resolutionDelegate.getJoinColumns( resolutionContext ),
true
);

View File

@ -299,21 +299,28 @@ class HibernateTypeHelper {
void bindJdbcDataType(
final Type resolvedHibernateType,
final List<RelationalValueBinding> relationalValueBindings) {
if ( relationalValueBindings.size() <= 1 ) {
if ( resolvedHibernateType == null ) {
throw new IllegalArgumentException( "resolvedHibernateType must be non-null." );
}
if ( relationalValueBindings == null || relationalValueBindings.isEmpty() ) {
throw new IllegalArgumentException( "relationalValueBindings must be non-null." );
}
if ( relationalValueBindings.size() == 1 ) {
bindJdbcDataType( resolvedHibernateType, relationalValueBindings.get( 0 ).getValue() );
return;
}
final Type resolvedRelationalType =
resolvedHibernateType.isEntityType()
? EntityType.class.cast( resolvedHibernateType ).getIdentifierOrUniqueKeyType( metadata() )
: resolvedHibernateType;
if ( !CompositeType.class.isInstance( resolvedRelationalType ) ) {
throw bindingContext
.makeMappingException( "Column number mismatch" ); // todo refine the exception message
}
Type[] subTypes = CompositeType.class.cast( resolvedRelationalType ).getSubtypes();
for ( int i = 0; i < subTypes.length; i++ ) {
bindJdbcDataType( subTypes[i], relationalValueBindings.get( i ).getValue() );
else {
final Type resolvedRelationalType =
resolvedHibernateType.isEntityType()
? EntityType.class.cast( resolvedHibernateType ).getIdentifierOrUniqueKeyType( metadata() )
: resolvedHibernateType;
if ( !CompositeType.class.isInstance( resolvedRelationalType ) ) {
throw bindingContext
.makeMappingException( "Column number mismatch" ); // todo refine the exception message
}
Type[] subTypes = CompositeType.class.cast( resolvedRelationalType ).getSubtypes();
for ( int i = 0; i < subTypes.length; i++ ) {
bindJdbcDataType( subTypes[i], relationalValueBindings.get( i ).getValue() );
}
}
}

View File

@ -39,10 +39,11 @@ public class ManyToManyCollectionTableNamingStrategyHelper extends TableNamingSt
private final String propertyName;
public ManyToManyCollectionTableNamingStrategyHelper(
final AbstractPluralAttributeBinding pluralAttributeBinding,
final String attributePath,
final boolean isInverse,
final EntityBinding entityBinding,
final EntityBinding associatedEntityBinding) {
super( pluralAttributeBinding.getContainer().seekEntityBinding() );
super( entityBinding );
if ( isInverse ) {
ownerEntityBinding = associatedEntityBinding;
inverseEntityBinding = entityBinding;
@ -59,7 +60,7 @@ public class ManyToManyCollectionTableNamingStrategyHelper extends TableNamingSt
Table.class.isInstance( inverseEntityBinding.getPrimaryTable() )
? ( (Table) inverseEntityBinding.getPrimaryTable() ).getPhysicalName().getText()
: null;
propertyName = Binder.createAttributePath( pluralAttributeBinding );
propertyName = attributePath;
}
@Override

View File

@ -37,6 +37,7 @@ import org.hibernate.metamodel.spi.domain.Attribute;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.ColumnSource;
import org.hibernate.metamodel.spi.source.DerivedValueSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
@ -51,11 +52,21 @@ public class RelationalValueBindingHelper {
private final TableHelper tableHelper;
private final NaturalIdUniqueKeyHelper uniqueKeyHelper;
RelationalValueBindingHelper(LocalBindingContext bindingContext) {
public RelationalValueBindingHelper(LocalBindingContext bindingContext) {
this.tableHelper = new TableHelper( bindingContext );
this.uniqueKeyHelper = new NaturalIdUniqueKeyHelper();
}
public boolean hasDerivedValue(List<RelationalValueBinding> relationalValueBindings) {
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
if (relationalValueBinding.isDerived() ) {
return true;
}
}
return false;
}
public List<RelationalValueBinding> createRelationalValueBindings(
final AttributeBindingContainer attributeBindingContainer,
final RelationalValueSourceContainer valueSourceContainer,
@ -168,4 +179,19 @@ public class RelationalValueBindingHelper {
}
return valueBindings;
}
public List<RelationalValueBinding> bindInverseRelationalValueBindings(
TableSpecification table,
List<? extends Value> values) {
final List<RelationalValueBinding> relationalValueBindings =
new ArrayList<RelationalValueBinding>( values.size() );
for ( Value value : values ) {
final RelationalValueBinding relationalValueBinding =
value.getValueType() == Value.ValueType.COLUMN ?
new RelationalValueBinding( table, (Column) value, false, false ) :
new RelationalValueBinding( table, (DerivedValue) value );
relationalValueBindings.add( relationalValueBinding );
}
return relationalValueBindings;
}
}

View File

@ -24,6 +24,7 @@
package org.hibernate.metamodel.internal;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -35,7 +36,6 @@ import org.jboss.logging.Logger;
import org.hibernate.AssertionFailure;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.source.AggregatedCompositeIdentifierSource;
import org.hibernate.metamodel.spi.source.AttributeSource;
@ -50,7 +50,6 @@ import org.hibernate.metamodel.spi.source.RootEntitySource;
import org.hibernate.metamodel.spi.source.SimpleIdentifierSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSourceNatureResolver;
/**
* @author Gail Badner
@ -67,10 +66,6 @@ public class SourceIndex {
private final Map<AttributeSourceKey, AttributeSourceKey> mappedByAttributeKeysByOwnerAttributeKeys =
new HashMap<AttributeSourceKey, AttributeSourceKey>();
public void indexRootEntitySource(final RootEntitySource entitySource) {
indexEntitySource( entitySource, entitySource );
}
public void indexEntitySource(final RootEntitySource rootEntitySource, final EntitySource entitySource) {
String entityName = entitySource.getEntityName();
EntitySourceIndex entitySourceIndex = new EntitySourceIndex( this, rootEntitySource, entitySource );
@ -79,15 +74,18 @@ public class SourceIndex {
indexAttributes( entitySourceIndex );
}
public void resolveAssociationSources(EntityBinding entityBinding) {
entitySourceIndexByEntityName.get( entityBinding.getEntityName() ).resolveAssociationSources( entityBinding );
public void resolveAssociationSources(EntityHierarchyHelper.LocalBindingContextExecutionContext bindingContextContext) {
entitySourceIndexByEntityName
.get( bindingContextContext.getEntityBinding().getEntityName() )
.resolveAttributeSources( bindingContextContext );
}
public Map<AttributeSourceKey, SingularAttributeSource> getSingularAttributeSources(
String entityName,
boolean isMappedBy,
SingularAttributeSource.Nature nature) {
final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName );
return entitySourceIndex.getSingularAttributeSources( nature );
return entitySourceIndex.getSingularAttributeSources( isMappedBy, nature );
}
public Map<AttributeSourceKey, PluralAttributeSource> getPluralAttributeSources(
@ -278,11 +276,15 @@ public class SourceIndex {
private final SourceIndex sourceIndex;
private final RootEntitySource rootEntitySource;
private final EntitySource entitySource;
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> identifierAttributeSourcesByNature =
new HashMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>();
// TODO: split out inverse and non-inverse SingularAttributeSource maps.
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> singularAttributeSourcesByNature =
new HashMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>();
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>
identifierAttributeSourcesByNature = new EnumMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>( SingularAttributeSource.Nature.class );
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>
nonMappedBySingularAttributeSourcesByNature = new EnumMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>( SingularAttributeSource.Nature.class );
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>
mappedBySingularAttributeSourcesByNature = new EnumMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>( SingularAttributeSource.Nature.class );
private final Map<AttributeSourceKey, SingularAttributeSource> unresolvedSingularAttributeSourcesByKey =
new HashMap<AttributeSourceKey, SingularAttributeSource>();
// TODO: the following should not need to be LinkedHashMap, but it appears that some unit tests
// depend on the ordering
// TODO: rework nonInversePluralAttributeSourcesByKey and inversePluralAttributeSourcesByKey
@ -291,10 +293,6 @@ public class SourceIndex {
private final Map<AttributeSourceKey, PluralAttributeSource> inversePluralAttributeSourcesByKey =
new LinkedHashMap<AttributeSourceKey, PluralAttributeSource>();
private EntitySourceIndex(final SourceIndex sourceIndex, final RootEntitySource rootEntitySource) {
this( sourceIndex, rootEntitySource, rootEntitySource );
}
private EntitySourceIndex(
final SourceIndex sourceIndex,
final RootEntitySource rootEntitySource,
@ -310,12 +308,21 @@ public class SourceIndex {
boolean isInIdentifier) {
final AttributeSourceKey attributeSourceKey =
new AttributeSourceKey( entitySource.getEntityName(), pathBase, attributeSource.getName() );
if ( attributeSource.getNature() == null ) {
unresolvedSingularAttributeSourcesByKey.put( attributeSourceKey, attributeSource );
return;
}
final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> map;
if ( isInIdentifier ) {
map = identifierAttributeSourcesByNature;
}
else if ( ToOneAttributeSource.class.isInstance( attributeSource ) &&
ToOneAttributeSource.class.cast( attributeSource ).isMappedBy() ) {
map = mappedBySingularAttributeSourcesByNature;
}
else {
map = singularAttributeSourcesByNature;
map = nonMappedBySingularAttributeSourcesByNature;
}
indexSingularAttributeSource(
attributeSourceKey,
@ -344,10 +351,14 @@ public class SourceIndex {
}
private Map<AttributeSourceKey, SingularAttributeSource> getSingularAttributeSources(
boolean isMappedBy,
SingularAttributeSource.Nature nature) {
final Map<AttributeSourceKey, SingularAttributeSource> entries;
if ( singularAttributeSourcesByNature.containsKey( nature ) ) {
entries = Collections.unmodifiableMap( singularAttributeSourcesByNature.get( nature ) );
if ( isMappedBy && mappedBySingularAttributeSourcesByNature.containsKey( nature ) ) {
entries = Collections.unmodifiableMap( mappedBySingularAttributeSourcesByNature.get( nature ) );
}
else if ( !isMappedBy && nonMappedBySingularAttributeSourcesByNature.containsKey( nature ) ) {
entries = Collections.unmodifiableMap( nonMappedBySingularAttributeSourcesByNature.get( nature ) );
}
else {
entries = Collections.emptyMap();
@ -383,119 +394,80 @@ public class SourceIndex {
return Collections.unmodifiableMap( map );
}
private void resolveAssociationSources(final EntityBinding entityBinding) {
// Cycle through non-inverse plural attributes.
for ( Map.Entry<AttributeSourceKey,PluralAttributeSource> entry : inversePluralAttributeSourcesByKey.entrySet() ) {
final AttributeSourceKey pluralAttributeSourceKey = entry.getKey();
final PluralAttributeSource pluralAttributeSource = entry.getValue();
private void resolveAttributeSources(EntityHierarchyHelper.LocalBindingContextExecutionContext bindingContextContext) {
final AttributeSourceResolutionContext sourceResolutionContext =
new AttributeSourceResolutionContextImpl( bindingContextContext );
// Resolve plural attributes.
for ( PluralAttributeSource pluralAttributeSource : inversePluralAttributeSourcesByKey.values() ) {
if ( pluralAttributeSource.getMappedBy() != null ) {
// This plural attribute is mappedBy the opposite side of the association,
// so it needs to be resolved.
// TODO: this should really just resolve PluralAttributeElementSource.Nature
pluralAttributeSource.resolvePluralAttributeElementSource(
new AttributeSourceResolutionContext() {
@Override
public IdentifierSource resolveIdentifierSource(String entityName) {
return sourceIndex.entitySourceIndex( entityName ).rootEntitySource.getIdentifierSource();
}
@Override
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) {
AttributeSourceKey ownerAttributeSourceKey = new AttributeSourceKey( referencedEntityName, mappedBy );
AttributeSource ownerAttributeSource = sourceIndex.attributeSource( referencedEntityName, mappedBy );
// TODO: is this needed? if so, make more obvious and rename method.
// If it's not needed, then resolvePluralAttributeElementSource() and
// and resolvePluralAttributeIndexSource() can use the same
// AttributeSourceResolutionContext.
sourceIndex.addMappedByAssociationByOwnerAssociation(
ownerAttributeSourceKey,
pluralAttributeSourceKey
);
return ownerAttributeSource;
}
}
);
pluralAttributeSource.resolvePluralAttributeElementSource( sourceResolutionContext );
}
if ( IndexedPluralAttributeSource.class.isInstance( pluralAttributeSource ) ) {
IndexedPluralAttributeSource indexedPluralAttributeSource =
(IndexedPluralAttributeSource) pluralAttributeSource;
indexedPluralAttributeSource.resolvePluralAttributeIndexSource(
new AttributeSourceResolutionContext() {
@Override
public IdentifierSource resolveIdentifierSource(String entityName) {
return sourceIndex.entitySourceIndex( entityName ).rootEntitySource.getIdentifierSource();
}
@Override
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) {;
return sourceIndex.attributeSource( referencedEntityName, mappedBy );
}
}
);
indexedPluralAttributeSource.resolvePluralAttributeIndexSource( sourceResolutionContext );
}
}
for ( Map.Entry<AttributeSourceKey,PluralAttributeSource> entry : nonInversePluralAttributeSourcesByKey.entrySet() ) {
final AttributeSourceKey pluralAttributeSourceKey = entry.getKey();
final PluralAttributeSource pluralAttributeSource = entry.getValue();
for ( PluralAttributeSource pluralAttributeSource : nonInversePluralAttributeSourcesByKey.values() ) {
if ( IndexedPluralAttributeSource.class.isInstance( pluralAttributeSource ) ) {
IndexedPluralAttributeSource indexedPluralAttributeSource =
(IndexedPluralAttributeSource) pluralAttributeSource;
indexedPluralAttributeSource.resolvePluralAttributeIndexSource(
new AttributeSourceResolutionContext() {
@Override
public IdentifierSource resolveIdentifierSource(String entityName) {
return sourceIndex.entitySourceIndex( entityName ).rootEntitySource.getIdentifierSource();
}
@Override
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) {;
return sourceIndex.attributeSource( referencedEntityName, mappedBy );
}
}
);
indexedPluralAttributeSource.resolvePluralAttributeIndexSource( sourceResolutionContext );
}
}
final Map<AttributeSourceKey,SingularAttributeSource> unresolvedSingularAttributeSourceMap =
singularAttributeSourcesByNature.get( null );
if ( unresolvedSingularAttributeSourceMap != null ) {
// cycle through unresolved SingularAttributeSource.
// TODO: rework so approach is similar to one-to-many/many-to-many resolution.
for ( Iterator<Map.Entry<AttributeSourceKey,SingularAttributeSource>> it = unresolvedSingularAttributeSourceMap.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<AttributeSourceKey,SingularAttributeSource> entry = it.next();
final AttributeSourceKey attributeSourceKey = entry.getKey();
final SingularAttributeSource attributeSource = entry.getValue();
if ( !ToOneAttributeSource.class.isInstance( attributeSource ) ) {
throw new AssertionFailure(
String.format( "Only a ToOneAttributeSource is expected to have a null nature; attribute: %s ", attributeSourceKey )
);
}
ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) attributeSource;
toOneAttributeSource.resolveToOneAttributeSourceNature(
new ToOneAttributeSourceNatureResolver.ToOneAttributeSourceNatureResolutionContext() {
@Override
public boolean areIdentifierColumnsDefined() {
return false;
}
@Override
public List<Column> getIdentifierColumns() {
// TODO: should this return columns from EntityIdentifier???
// (broken for joined-subclass)
return entityBinding.getPrimaryTable().getPrimaryKey().getColumns();
}
}
// cycle through unresolved SingularAttributeSource.
// TODO: rework so approach is similar to one-to-many/many-to-many resolution.
for ( Iterator<Map.Entry<AttributeSourceKey,SingularAttributeSource>> it = unresolvedSingularAttributeSourcesByKey.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<AttributeSourceKey,SingularAttributeSource> entry = it.next();
final AttributeSourceKey attributeSourceKey = entry.getKey();
final SingularAttributeSource attributeSource = entry.getValue();
if ( !ToOneAttributeSource.class.isInstance( attributeSource ) ) {
throw new AssertionFailure(
String.format( "Only a ToOneAttributeSource is expected to have a null nature; attribute: %s ", attributeSourceKey )
);
if ( toOneAttributeSource.getNature() == null ) {
throw new AssertionFailure(
String.format( "Null nature should have been resolved: %s ", attributeSourceKey )
);
}
it.remove();
indexSingularAttributeSource( attributeSourceKey,attributeSource, singularAttributeSourcesByNature );
}
ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) attributeSource;
toOneAttributeSource.resolveToOneAttributeSource( sourceResolutionContext );
if ( toOneAttributeSource.getNature() == null ) {
throw new AssertionFailure(
String.format( "Null nature should have been resolved: %s ", attributeSourceKey )
);
}
indexSingularAttributeSource(
attributeSourceKey,
attributeSource,
toOneAttributeSource.isMappedBy() ?
mappedBySingularAttributeSourcesByNature :
nonMappedBySingularAttributeSourcesByNature
);
}
}
class AttributeSourceResolutionContextImpl implements AttributeSourceResolutionContext {
private final EntityHierarchyHelper.LocalBindingContextExecutionContext bindingContextContext;
public AttributeSourceResolutionContextImpl(
EntityHierarchyHelper.LocalBindingContextExecutionContext bindingContextContext) {
this.bindingContextContext = bindingContextContext;
}
@Override
public IdentifierSource resolveIdentifierSource(String entityName) {
return bindingContextContext.getRootEntitySource().getIdentifierSource();
}
@Override
public AttributeSource resolveAttributeSource(String entityName, String attributeName) {
return sourceIndex.attributeSource( entityName, attributeName );
}
@Override
public List<Column> resolveIdentifierColumns() {
return bindingContextContext.getEntityBinding().getPrimaryTable().getPrimaryKey().getColumns();
}
}
}

View File

@ -28,6 +28,7 @@ import org.jboss.logging.Logger;
import org.hibernate.TruthValue;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.Schema;
@ -38,9 +39,11 @@ import org.hibernate.metamodel.spi.source.ColumnSource;
import org.hibernate.metamodel.spi.source.InLineViewSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.MappingDefaults;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.SizeSource;
import org.hibernate.metamodel.spi.source.TableSource;
import org.hibernate.metamodel.spi.source.TableSpecificationSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
/**
* @author Gail Badner

View File

@ -0,0 +1,113 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.resolver;
import java.util.List;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
/**
+ * @author Gail Badner
+ */
public interface AssociationRelationalBindingResolver {
SingularAttributeBinding resolveOneToOneReferencedAttributeBinding(
final ToOneAttributeSource attributeSource,
final EntityBinding referencedEntityBinding);
List<RelationalValueBinding> resolveOneToOneRelationalValueBindings(
final ToOneAttributeSource attributeSource,
final AttributeBindingContainer attributeBindingContainer,
final SingularAttributeBinding referencedAttributeBinding);
ForeignKey resolveOneToOneForeignKey(
ToOneAttributeSource attributeSource,
TableSpecification sourceTable,
List<Column> sourceColumns,
EntityBinding referencedEntityBinding);
SingularAttributeBinding resolveManyToOneReferencedAttributeBinding(
final AttributeBindingContainer attributeBindingContainer,
final ToOneAttributeSource attributeSource,
final EntityBinding referencedEntityBinding);
// TODO: referencedAttributeBinding and referencedEntityBinding are both included due to a bug that can
// cause entityBinding != entityBinding.hierarchyDetails.getEntityIdentifier().getAttributeBinding().getContainer()
List<RelationalValueBinding> resolveManyToOneRelationalValueBindings(
final ToOneAttributeSource attributeSource,
final AttributeBindingContainer attributeBindingContainer,
final SingularAttributeBinding referencedAttributeBinding,
final EntityBinding referencedEntityBinding);
ForeignKey resolveManyToOneForeignKey(
ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
List<RelationalValueBinding> relationalValueBindings,
EntityBinding referencedEntityBinding);
List<RelationalValueBinding> resolveManyToManyElementRelationalValueBindings(
final EntityBinding entityBinding,
final ManyToManyPluralAttributeElementSource elementSource,
final TableSpecification collectionTable,
final EntityBinding referencedEntityBinding);
ForeignKey resolveManyToManyElementForeignKey(
final EntityBinding entityBinding,
final ManyToManyPluralAttributeElementSource elementSource,
final TableSpecification collectionTable,
final List<RelationalValueBinding> relationalValueBindings,
final EntityBinding referencedEntityBinding);
TableSpecification resolveManyToManyCollectionTable(
PluralAttributeSource pluralAttributeSource,
String attributePath,
EntityBinding entityBinding,
EntityBinding referencedEntityBinding);
List<RelationalValueBinding> resolvePluralAttributeKeyRelationalValueBindings(
final PluralAttributeSource attributeSource,
final EntityBinding entityBinding,
final TableSpecification collectionTable,
final EntityBinding referencedEntityBinding);
ForeignKey resolvePluralAttributeKeyForeignKey(
final PluralAttributeSource attributeSource,
final EntityBinding entityBinding,
final TableSpecification collectionTable,
final List<RelationalValueBinding> relationalValueBindings,
final EntityBinding referencedEntityBinding);
SingularAttributeBinding resolvePluralAttributeKeyReferencedBinding(
final AttributeBindingContainer attributeBindingContainer,
final PluralAttributeSource attributeSource);
}

View File

@ -0,0 +1,350 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.resolver;
import java.util.Collections;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.metamodel.internal.ForeignKeyHelper;
import org.hibernate.metamodel.internal.RelationalValueBindingHelper;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.ManyToManyPluralAttributeElementBinding;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.binding.SecondaryTable;
import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.source.AssociationSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.type.ForeignKeyDirection;
/**
+ * @author Gail Badner
+ */
public class MappedByAssociationRelationalBindingResolverImpl implements AssociationRelationalBindingResolver {
private final LocalBindingContext bindingContext;
private final ForeignKeyHelper foreignKeyHelper;
private final RelationalValueBindingHelper relationalValueBindingHelper;
public MappedByAssociationRelationalBindingResolverImpl(LocalBindingContext bindingContext) {
this.bindingContext = bindingContext;
this.foreignKeyHelper = new ForeignKeyHelper( bindingContext );
this.relationalValueBindingHelper = new RelationalValueBindingHelper( bindingContext );
}
@Override
public SingularAttributeBinding resolveOneToOneReferencedAttributeBinding(
ToOneAttributeSource attributeSource,
EntityBinding referencedEntityBinding) {
return (SingularAttributeBinding) referencedEntityBinding.locateAttributeBindingByPath(
getMappedByAssociationSource( attributeSource ).getMappedBy(),
true
);
}
@Override
public List<RelationalValueBinding> resolveOneToOneRelationalValueBindings(
final ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
SingularAttributeBinding referencedAttributeBinding) {
return Collections.emptyList();
}
@Override
public ForeignKey resolveOneToOneForeignKey(
ToOneAttributeSource attributeSource,
TableSpecification sourceTable,
List<Column> sourceColumns,
EntityBinding referencedEntityBinding) {
// TODO: get rid of this duplication!!!
if ( attributeSource.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
throw new AssertionFailure( "Cannot create a foreign key for one-to-one with foreign key direction going to the parent." );
}
final List<Column> targetColumns = foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
attributeSource
);
final TableSpecification targetTable = foreignKeyHelper.determineForeignKeyTargetTable(
referencedEntityBinding,
attributeSource
);
return foreignKeyHelper.locateOrCreateForeignKey(
attributeSource.getExplicitForeignKeyName(),
sourceTable,
sourceColumns,
targetTable,
targetColumns
);
}
@Override
public SingularAttributeBinding resolveManyToOneReferencedAttributeBinding(
AttributeBindingContainer attributeBindingContainer,
ToOneAttributeSource attributeSource,
EntityBinding referencedEntityBinding) {
// This is a mappedBy many-to-one. This should only happen when the owning many-to-one uses a join table.
// TODO: confirm the above is true.
final SecondaryTable ownerSecondaryTable = getOwnerSecondaryTable(
getMappedByAssociationSource( attributeSource ),
referencedEntityBinding
);
return referencedEntityBinding.locateAttributeBinding(
ownerSecondaryTable.getForeignKeyReference().getTargetTable(),
ownerSecondaryTable.getForeignKeyReference().getTargetColumns(),
true
);
}
@Override
public List<RelationalValueBinding> resolveManyToOneRelationalValueBindings(
ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
SingularAttributeBinding referencedAttributeBinding,
EntityBinding referencedEntityBinding) {
// A many-to-one can only have mappedBy specified if there is a join table.
// TODO: confirm this is true.
// The relational value bindings for the attribute being processed
// will contain the columns that make up the FK join tables on the
// owner's secondary table.
final SecondaryTable ownerSecondaryTable = getOwnerSecondaryTable(
getMappedByAssociationSource( attributeSource ),
referencedEntityBinding
);
return relationalValueBindingHelper.bindInverseRelationalValueBindings(
ownerSecondaryTable.getForeignKeyReference().getSourceTable(),
ownerSecondaryTable.getForeignKeyReference().getSourceColumns()
);
}
@Override
public ForeignKey resolveManyToOneForeignKey(
ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
List<RelationalValueBinding> relationalValueBindings,
EntityBinding referencedEntityBinding) {
// A many-to-one can only have mappedBy specified if there is a join table.
// TODO: confirm this is true.
final SecondaryTable ownerSecondaryTable = getOwnerSecondaryTable(
getMappedByAssociationSource( attributeSource ),
referencedEntityBinding
);
return ownerSecondaryTable.getForeignKeyReference();
}
@Override
public List<RelationalValueBinding> resolveManyToManyElementRelationalValueBindings(
final EntityBinding entityBinding,
final ManyToManyPluralAttributeElementSource elementSource,
final TableSpecification collectionTable,
final EntityBinding referencedEntityBinding) {
{
final AttributeBinding ownerAttributeBinding = getOwnerAttributeBinding(
getMappedByAssociationSource( elementSource )
);
final List<RelationalValueBinding> relationalValueBindings;
if ( ownerAttributeBinding.getAttribute().isSingular() ) {
// the owner is a many-to-one on a join table; the target will be the FK target
// for the secondary table.
final SecondaryTable ownerSecondaryTable =
referencedEntityBinding.getSecondaryTables().get( collectionTable.getLogicalName() );
relationalValueBindings = relationalValueBindingHelper.bindInverseRelationalValueBindings(
collectionTable,
ownerSecondaryTable.getForeignKeyReference().getSourceColumns()
);
}
else {
final PluralAttributeBinding ownerPluralAttributeBinding = (PluralAttributeBinding) ownerAttributeBinding;
relationalValueBindings = relationalValueBindingHelper.bindInverseRelationalValueBindings(
collectionTable,
ownerPluralAttributeBinding.getPluralAttributeKeyBinding().getValues()
);
}
return relationalValueBindings;
}
}
@Override
public ForeignKey resolveManyToManyElementForeignKey(
final EntityBinding entityBinding,
final ManyToManyPluralAttributeElementSource elementSource,
final TableSpecification collectionTable,
final List<RelationalValueBinding> relationalValueBindings,
final EntityBinding referencedEntityBinding) {
final AttributeBinding ownerAttributeBinding = getOwnerAttributeBinding(
getMappedByAssociationSource( elementSource )
);
if ( ownerAttributeBinding.getAttribute().isSingular() ) {
// the owner is a many-to-one on a join table; the target will be the FK target
// for the secondary table.
final SecondaryTable ownerSecondaryTable =
referencedEntityBinding.getSecondaryTables().get( collectionTable.getLogicalName() );
return ownerSecondaryTable.getForeignKeyReference();
}
else {
final PluralAttributeBinding ownerPluralAttributeBinding = (PluralAttributeBinding) ownerAttributeBinding;
return ownerPluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey();
}
}
@Override
public TableSpecification resolveManyToManyCollectionTable(
PluralAttributeSource pluralAttributeSource,
String attributePath,
EntityBinding entityBinding,
EntityBinding referencedEntityBinding) {
final AttributeBinding ownerAttributeBinding = getOwnerAttributeBinding(
getMappedByAssociationSource( (AssociationSource) pluralAttributeSource.getElementSource() )
);
return ownerAttributeBinding.getAttribute().isSingular() ?
( (SingularAssociationAttributeBinding) ownerAttributeBinding ).getTable() :
( (PluralAttributeBinding) ownerAttributeBinding ).getPluralAttributeKeyBinding().getCollectionTable();
}
@Override
public List<RelationalValueBinding> resolvePluralAttributeKeyRelationalValueBindings(
PluralAttributeSource attributeSource,
EntityBinding entityBinding,
TableSpecification collectionTable,
EntityBinding referencedEntityBinding) {
final AttributeBinding ownerAttributeBinding = getOwnerAttributeBinding(
getMappedByAssociationSource( (AssociationSource) attributeSource.getElementSource() )
);
if ( ownerAttributeBinding.getAttribute().isSingular() ) {
return ( (ManyToOneAttributeBinding) ownerAttributeBinding ).getRelationalValueBindings();
}
else {
final PluralAttributeBinding pluralOwnerAttributeBinding = (PluralAttributeBinding) ownerAttributeBinding;
final ManyToManyPluralAttributeElementBinding ownerElementBinding =
(ManyToManyPluralAttributeElementBinding) pluralOwnerAttributeBinding.getPluralAttributeElementBinding();
return ownerElementBinding.getRelationalValueBindings();
}
}
@Override
public ForeignKey resolvePluralAttributeKeyForeignKey(
PluralAttributeSource attributeSource,
EntityBinding entityBinding,
TableSpecification collectionTable,
List<RelationalValueBinding> sourceRelationalValueBindings,
EntityBinding referencedEntityBinding) {
final AttributeBinding ownerAttributeBinding = getOwnerAttributeBinding(
getMappedByAssociationSource( (AssociationSource) attributeSource.getElementSource() )
);
final ForeignKey foreignKey;
if ( ownerAttributeBinding.getAttribute().isSingular() ) {
foreignKey = ( (ManyToOneAttributeBinding) ownerAttributeBinding ).getForeignKey();
}
else {
final PluralAttributeBinding pluralOwnerAttributeBinding = (PluralAttributeBinding) ownerAttributeBinding;
final ManyToManyPluralAttributeElementBinding ownerElementBinding =
(ManyToManyPluralAttributeElementBinding) pluralOwnerAttributeBinding.getPluralAttributeElementBinding();
foreignKey = ownerElementBinding.getForeignKey();
}
foreignKey.setDeleteRule( attributeSource.getKeySource().getOnDeleteAction() );
return foreignKey;
}
@Override
public SingularAttributeBinding resolvePluralAttributeKeyReferencedBinding(
AttributeBindingContainer attributeBindingContainer,
PluralAttributeSource attributeSource) {
final AttributeBinding ownerAttributeBinding = getOwnerAttributeBinding(
getMappedByAssociationSource( (AssociationSource) attributeSource.getElementSource() )
);
final SingularAttributeBinding referencedAttributeBinding;
if ( ownerAttributeBinding.getAttribute().isSingular() ) {
referencedAttributeBinding =
( (SingularAssociationAttributeBinding) ownerAttributeBinding ).getReferencedAttributeBinding();
}
else {
final PluralAttributeBinding ownerPluralAttributeBinding = (PluralAttributeBinding) ownerAttributeBinding;
final ManyToManyPluralAttributeElementBinding ownerElementBinding =
(ManyToManyPluralAttributeElementBinding) ownerPluralAttributeBinding
.getPluralAttributeElementBinding();
referencedAttributeBinding = attributeBindingContainer.seekEntityBinding().locateAttributeBinding(
ownerElementBinding.getForeignKey().getTargetTable(),
ownerElementBinding.getForeignKey().getTargetColumns(),
true
);
if ( referencedAttributeBinding == null ) {
throw new NotYetImplementedException( "Referenced columns not used by an attribute binding is not supported yet." );
}
}
return referencedAttributeBinding;
}
private MappedByAssociationSource getMappedByAssociationSource(AssociationSource associationSource) {
if ( !associationSource.isMappedBy() || !MappedByAssociationSource.class.isInstance( associationSource ) ) {
throw new AssertionFailure( "Expected a MappedByAssociationSource." );
}
return (MappedByAssociationSource) associationSource;
}
private AttributeBinding getOwnerAttributeBinding(MappedByAssociationSource associationSource) {
final EntityBinding referencedEntityBinding = bindingContext.getMetadataImplementor().getEntityBinding(
associationSource.getReferencedEntityName()
);
final AttributeBinding ownerAttributeBinding = referencedEntityBinding.locateAttributeBindingByPath(
associationSource.getMappedBy(),
true
);
if ( ownerAttributeBinding == null ) {
throw bindingContext.makeMappingException(
String.format(
"Attribute not found: [%s.%s]",
referencedEntityBinding.getEntityName(),
associationSource.getMappedBy()
)
);
}
return ownerAttributeBinding;
}
private SecondaryTable getOwnerSecondaryTable(
MappedByAssociationSource attributeSource,
EntityBinding referencedEntityBinding) {
SingularAssociationAttributeBinding ownerAttributeBinding =
(SingularAssociationAttributeBinding) referencedEntityBinding.locateAttributeBinding(
attributeSource.getMappedBy()
);
TableSpecification table = ownerAttributeBinding.getTable();
if ( referencedEntityBinding.getPrimaryTable().equals( table ) ) {
throw new AssertionFailure( "many-to-one has mappedby specified but it does not use a join table." );
}
return referencedEntityBinding.getSecondaryTables().get( table.getLogicalName() );
}
}

View File

@ -0,0 +1,420 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.resolver;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.metamodel.internal.Binder;
import org.hibernate.metamodel.internal.ForeignKeyHelper;
import org.hibernate.metamodel.internal.ManyToManyCollectionTableNamingStrategyHelper;
import org.hibernate.metamodel.internal.RelationalValueBindingHelper;
import org.hibernate.metamodel.internal.TableHelper;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.AssociationSource;
import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.PluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.PluralAttributeKeySource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.RelationalValueSourceContainer;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.TableSpecificationSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.type.ForeignKeyDirection;
/**
+ * @author Gail Badner
+ */
public class StandardAssociationRelationalBindingResolverImpl implements AssociationRelationalBindingResolver {
private final RelationalValueBindingHelper relationalValueBindingHelper;
private final ForeignKeyHelper foreignKeyHelper;
private final TableHelper tableHelper;
public StandardAssociationRelationalBindingResolverImpl(LocalBindingContext bindingContext) {
this.relationalValueBindingHelper = new RelationalValueBindingHelper( bindingContext );
this.foreignKeyHelper = new ForeignKeyHelper( bindingContext );
this.tableHelper = new TableHelper( bindingContext );
}
@Override
public SingularAttributeBinding resolveOneToOneReferencedAttributeBinding(
ToOneAttributeSource attributeSource,
EntityBinding referencedEntityBinding) {
return resolveReferencedAttributeBinding( attributeSource, referencedEntityBinding );
}
@Override
public List<RelationalValueBinding> resolveOneToOneRelationalValueBindings(
final ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
SingularAttributeBinding referencedAttributeBinding) {
if ( ! attributeSource.relationalValueSources().isEmpty() ) {
final TableSpecification defaultTable =
locateDefaultTableSpecificationForAttribute(
attributeBindingContainer,
attributeSource
);
return resolveRelationalValueBindings(
attributeSource,
attributeBindingContainer.seekEntityBinding(),
defaultTable,
false,
attributeSource.getDefaultNamingStrategies(
attributeBindingContainer.seekEntityBinding().getEntity().getName(),
defaultTable.getLogicalName().getText(),
referencedAttributeBinding
)
);
}
else {
return Collections.emptyList();
}
}
private TableSpecification locateDefaultTableSpecificationForAttribute(
final AttributeBindingContainer attributeBindingContainer,
final SingularAttributeSource attributeSource) {
return attributeSource.getContainingTableName() == null ?
attributeBindingContainer.getPrimaryTable() :
attributeBindingContainer.seekEntityBinding().locateTable( attributeSource.getContainingTableName() );
}
@Override
public ForeignKey resolveOneToOneForeignKey(
ToOneAttributeSource attributeSource,
TableSpecification sourceTable,
List<Column> sourceColumns,
EntityBinding referencedEntityBinding) {
if ( attributeSource.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) {
throw new AssertionFailure( "Cannot create a foreign key for one-to-one with foreign key direction going to the parent." );
}
final TableSpecification targetTable = foreignKeyHelper.determineForeignKeyTargetTable(
referencedEntityBinding,
attributeSource
);
final List<Column> targetColumns = foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
attributeSource
);
return foreignKeyHelper.locateOrCreateForeignKey(
attributeSource.getExplicitForeignKeyName(),
sourceTable,
sourceColumns,
targetTable,
targetColumns
);
}
@Override
public SingularAttributeBinding resolveManyToOneReferencedAttributeBinding(
AttributeBindingContainer attributeBindingContainer,
ToOneAttributeSource attributeSource,
EntityBinding referencedEntityBinding) {
return resolveReferencedAttributeBinding( attributeSource, referencedEntityBinding );
}
@Override
public List<RelationalValueBinding> resolveManyToOneRelationalValueBindings(
ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
SingularAttributeBinding referencedAttributeBinding,
EntityBinding referencedEntityBinding) {
final TableSpecification defaultTable =
locateDefaultTableSpecificationForAttribute(
attributeBindingContainer,
attributeSource
);
return resolveRelationalValueBindings(
attributeSource,
attributeBindingContainer.seekEntityBinding(),
defaultTable,
false,
attributeSource.getDefaultNamingStrategies(
attributeBindingContainer.seekEntityBinding().getEntity().getName(),
defaultTable.getLogicalName().getText(),
referencedAttributeBinding
)
);
}
@Override
public ForeignKey resolveManyToOneForeignKey(
ToOneAttributeSource attributeSource,
AttributeBindingContainer attributeBindingContainer,
List<RelationalValueBinding> relationalValueBindings,
EntityBinding referencedEntityBinding) {
final List<Column> targetColumns = foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
attributeSource
);
return locateOrCreateForeignKey(
attributeSource,
referencedEntityBinding,
relationalValueBindings.get( 0 ).getTable(),
relationalValueBindings,
targetColumns
);
}
@Override
public List<RelationalValueBinding> resolveManyToManyElementRelationalValueBindings(
final EntityBinding entityBinding,
final ManyToManyPluralAttributeElementSource elementSource,
final TableSpecification collectionTable,
final EntityBinding referencedEntityBinding) {
final List<Column> targetColumns =
foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
elementSource
);
final List<Binder.DefaultNamingStrategy> namingStrategies = new ArrayList<Binder.DefaultNamingStrategy>( targetColumns.size() );
for ( final Column targetColumn : targetColumns ) {
namingStrategies.add(
new Binder.DefaultNamingStrategy() {
@Override
public String defaultName(NamingStrategy namingStrategy) {
return namingStrategy.foreignKeyColumnName(
elementSource.getAttributeSource().getName(),
referencedEntityBinding.getEntityName(),
referencedEntityBinding.getPrimaryTableName(),
targetColumn.getColumnName().getText()
);
}
}
);
}
return resolveRelationalValueBindings(
elementSource,
entityBinding,
collectionTable,
true,
namingStrategies
);
}
@Override
public ForeignKey resolveManyToManyElementForeignKey(
final EntityBinding entityBinding,
final ManyToManyPluralAttributeElementSource elementSource,
final TableSpecification collectionTable,
final List<RelationalValueBinding> relationalValueBindings,
final EntityBinding referencedEntityBinding) {
final List<Column> targetColumns =
foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
elementSource
);
return locateOrCreateForeignKey(
elementSource,
referencedEntityBinding,
collectionTable,
relationalValueBindings,
targetColumns
);
}
@Override
public TableSpecification resolveManyToManyCollectionTable(
PluralAttributeSource pluralAttributeSource,
String attributePath,
EntityBinding entityBinding,
EntityBinding referencedEntityBinding) {
final TableSpecificationSource collectionTableSource = pluralAttributeSource.getCollectionTableSpecificationSource();
return tableHelper.createTable(
collectionTableSource,
new ManyToManyCollectionTableNamingStrategyHelper(
attributePath,
pluralAttributeSource.isInverse(),
entityBinding,
referencedEntityBinding
)
);
}
@Override
public List<RelationalValueBinding> resolvePluralAttributeKeyRelationalValueBindings(
final PluralAttributeSource attributeSource,
final EntityBinding entityBinding,
final TableSpecification collectionTable,
final EntityBinding referencedEntityBinding) {
final PluralAttributeKeySource keySource = attributeSource.getKeySource();
final List<Column>targetColumns = foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
keySource
);
final List<Binder.DefaultNamingStrategy> namingStrategies = new ArrayList<Binder.DefaultNamingStrategy>( targetColumns.size() );
final String ownedAttributeName;
if ( attributeSource.getElementSource().getNature().isAssociation() ) {
final AssociationSource associationSource = (AssociationSource) attributeSource.getElementSource();
if ( associationSource.getOwnedAssociationSources().size() > 1 ) {
throw new NotYetImplementedException( "Cannot determine default naming strategy when an association owns more than 1 other association." );
}
if ( associationSource.getOwnedAssociationSources().isEmpty() ) {
ownedAttributeName = null;
}
else {
final AssociationSource ownedAssociationSource = associationSource.getOwnedAssociationSources().iterator().next();
ownedAttributeName = ownedAssociationSource.getAttributeSource().getName();
}
}
else {
ownedAttributeName = null;
}
for ( final Column targetColumn : targetColumns ) {
namingStrategies.add(
new Binder.DefaultNamingStrategy() {
@Override
public String defaultName(NamingStrategy namingStrategy) {
return namingStrategy.foreignKeyColumnName(
ownedAttributeName,
entityBinding.getEntityName(),
entityBinding.getPrimaryTableName(),
targetColumn.getColumnName().getText()
);
}
}
);
}
return resolveRelationalValueBindings(
keySource,
entityBinding,
collectionTable,
attributeSource.getElementSource().getNature() != PluralAttributeElementSource.Nature.ONE_TO_MANY,
namingStrategies
);
}
@Override
public ForeignKey resolvePluralAttributeKeyForeignKey(
final PluralAttributeSource attributeSource,
final EntityBinding entityBinding,
final TableSpecification collectionTable,
final List<RelationalValueBinding> sourceRelationalValueBindings,
final EntityBinding referencedEntityBinding) {
final PluralAttributeKeySource keySource = attributeSource.getKeySource();
List<Column> targetColumns =
foreignKeyHelper.determineForeignKeyTargetColumns(
referencedEntityBinding,
keySource
);
ForeignKey foreignKey = locateOrCreateForeignKey(
keySource,
referencedEntityBinding,
collectionTable,
sourceRelationalValueBindings,
targetColumns
);
foreignKey.setDeleteRule( keySource.getOnDeleteAction() );
return foreignKey;
}
@Override
public SingularAttributeBinding resolvePluralAttributeKeyReferencedBinding(
AttributeBindingContainer attributeBindingContainer,
PluralAttributeSource attributeSource) {
return foreignKeyHelper.determineReferencedAttributeBinding(
attributeSource.getKeySource(),
attributeBindingContainer.seekEntityBinding()
);
}
private SingularAttributeBinding resolveReferencedAttributeBinding(
ToOneAttributeSource attributeSource,
EntityBinding referencedEntityBinding) {
return foreignKeyHelper.determineReferencedAttributeBinding( attributeSource, referencedEntityBinding );
}
public List<RelationalValueBinding> resolveRelationalValueBindings(
final RelationalValueSourceContainer relationalValueSourceContainer,
EntityBinding entityBinding,
TableSpecification defaultTable,
boolean forceNonNullable,
List<Binder.DefaultNamingStrategy> defaultNamingStrategies) {
return relationalValueBindingHelper.createRelationalValueBindings(
entityBinding,
relationalValueSourceContainer,
defaultTable,
defaultNamingStrategies,
forceNonNullable
);
}
private ForeignKey locateOrCreateForeignKey(
final ForeignKeyContributingSource foreignKeyContributingSource,
final EntityBinding referencedEntityBinding,
final TableSpecification sourceTable,
final List<RelationalValueBinding> sourceRelationalValueBindings,
final List<Column> targetColumns) {
final TableSpecification targetTable = foreignKeyHelper.determineForeignKeyTargetTable(
referencedEntityBinding,
foreignKeyContributingSource
);
return foreignKeyHelper.locateOrCreateForeignKey(
foreignKeyContributingSource.getExplicitForeignKeyName(),
sourceTable,
extractColumnsFromRelationalValueBindings( sourceRelationalValueBindings ),
targetTable,
targetColumns
);
}
// TODO: try to get rid of this...
private static List<Column> extractColumnsFromRelationalValueBindings(
final List<RelationalValueBinding> valueBindings) {
List<Column> columns = new ArrayList<Column>( valueBindings.size() );
for ( RelationalValueBinding relationalValueBinding : valueBindings ) {
final Value value = relationalValueBinding.getValue();
// todo : currently formulas are not supported here... :(
if ( !Column.class.isInstance( value ) ) {
throw new NotYetImplementedException(
"Derived values are not supported when creating a foreign key that targets columns."
);
}
columns.add( (Column) value );
}
return columns;
}
}

View File

@ -0,0 +1,86 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.source.annotations;
import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.spi.source.FilterSource;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
/**
+ * @author Gail Badner
+ */
public abstract class AbstractManyToManyPluralAttributeElementSourceImpl
extends AbstractPluralAssociationElementSourceImpl
implements ManyToManyPluralAttributeElementSource {
public AbstractManyToManyPluralAttributeElementSourceImpl(
PluralAttributeSourceImpl pluralAttributeSource,
final String relativePath) {
super( pluralAttributeSource, relativePath );
}
@Override
public boolean isUnique() {
return pluralAssociationAttribute().getNature() == MappedAttribute.Nature.ONE_TO_MANY;
}
@Override
public String getReferencedEntityAttributeName() {
// HBM only
return null;
}
@Override
public FilterSource[] getFilterSources() {
return new FilterSource[0]; //todo
}
@Override
public String getWhere() {
return pluralAssociationAttribute().getWhereClause();
}
@Override
public FetchTiming getFetchTiming() {
return FetchTiming.IMMEDIATE;
}
@Override
public Nature getNature() {
return Nature.MANY_TO_MANY;
}
@Override
public boolean isOrdered() {
return StringHelper.isNotEmpty( pluralAssociationAttribute().getOrderBy() );
}
@Override
public String getOrder() {
return pluralAssociationAttribute().getOrderBy();
}
}

View File

@ -0,0 +1,95 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.source.annotations;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHelper;
import org.hibernate.metamodel.spi.source.AssociationPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
/**
+ * @author Gail Badner
+ */
public abstract class AbstractPluralAssociationElementSourceImpl
extends AbstractPluralAttributeElementSourceImpl implements AssociationPluralAttributeElementSource {
private final PluralAttributeSourceImpl pluralAttributeSource;
private final Set<MappedByAssociationSource> ownedAssociationSources = new HashSet<MappedByAssociationSource>( );
public AbstractPluralAssociationElementSourceImpl(
final PluralAttributeSourceImpl pluralAttributeSource,
final String relativePath) {
super( pluralAttributeSource.pluralAssociationAttribute(), relativePath );
this.pluralAttributeSource = pluralAttributeSource;
}
@Override
public String getReferencedEntityName() {
return pluralAssociationAttribute().getReferencedEntityType();
}
@Override
public boolean isNotFoundAnException() {
return !pluralAssociationAttribute().isIgnoreNotFound();
}
public AttributeSource getAttributeSource() {
return pluralAttributeSource;
}
@Override
public Set<MappedByAssociationSource> getOwnedAssociationSources() {
return ownedAssociationSources;
}
@Override
public void addMappedByAssociationSource(MappedByAssociationSource attributeSource) {
if ( attributeSource == null ) {
throw new IllegalArgumentException( "attributeSource must be non-null." );
}
ownedAssociationSources.add( attributeSource );
}
@Override
public boolean isMappedBy() {
return false;
}
@Override
public Iterable<CascadeStyle> getCascadeStyles() {
return EnumConversionHelper.cascadeTypeToCascadeStyleSet(
pluralAssociationAttribute().getCascadeTypes(),
pluralAssociationAttribute().getHibernateCascadeTypes(),
pluralAssociationAttribute().getContext()
);
}
protected PluralAssociationAttribute pluralAssociationAttribute() {
return pluralAttributeSource.pluralAssociationAttribute();
}
}

View File

@ -33,12 +33,12 @@ import org.hibernate.metamodel.spi.source.PluralAttributeSource;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public abstract class AbstractPluralAttributeElementSource implements AnnotationAttributeSource {
public abstract class AbstractPluralAttributeElementSourceImpl implements AnnotationAttributeSource {
private final String path;
protected AttributeOverride attributeOverride;
protected AssociationOverride associationOverride;
public AbstractPluralAttributeElementSource(
public AbstractPluralAttributeElementSourceImpl(
final PluralAssociationAttribute associationAttribute,
final String relativePath) {
if ( associationAttribute.getPluralAttributeNature() == PluralAttributeSource.Nature.MAP ) {

View File

@ -0,0 +1,129 @@
package org.hibernate.metamodel.internal.source.annotations;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.SingularAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHelper;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.type.ForeignKeyDirection;
public abstract class AbstractToOneAttributeSourceImpl extends SingularAttributeSourceImpl implements ToOneAttributeSource{
private final SingularAssociationAttribute associationAttribute;
private final Set<CascadeStyle> cascadeStyles;
private final Set<MappedByAssociationSource> ownedAssociationSources = new HashSet<MappedByAssociationSource>();
private SingularAttributeSource.Nature nature;
public AbstractToOneAttributeSourceImpl(SingularAssociationAttribute associationAttribute, String relativePath) {
super( associationAttribute, relativePath );
this.associationAttribute = associationAttribute;
this.cascadeStyles = EnumConversionHelper.cascadeTypeToCascadeStyleSet(
associationAttribute.getCascadeTypes(),
associationAttribute.getHibernateCascadeTypes(),
associationAttribute.getContext()
);
}
@Override
public SingularAttributeSource.Nature getNature() {
return nature;
}
protected SingularAssociationAttribute associationAttribute() {
return associationAttribute;
}
protected void setNature(SingularAttributeSource.Nature nature) {
if ( this.nature != null ) {
throw new IllegalStateException( "nature is already initialized." );
}
this.nature = nature;
}
@Override
public AttributeSource getAttributeSource() {
return this;
}
@Override
public String getReferencedEntityName() {
return associationAttribute.getReferencedEntityType();
}
@Override
public boolean isUnique() {
return MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute.getNature() );
}
@Override
public boolean isNotFoundAnException() {
return !associationAttribute.isIgnoreNotFound();
}
@Override
public Set<MappedByAssociationSource> getOwnedAssociationSources() {
return ownedAssociationSources;
}
@Override
public void addMappedByAssociationSource(MappedByAssociationSource attributeSource) {
if ( attributeSource == null ) {
throw new IllegalArgumentException( "attributeSource must be non-null." );
}
ownedAssociationSources.add( attributeSource );
}
@Override
public boolean isMappedBy() {
return false;
}
@Override
public Iterable<CascadeStyle> getCascadeStyles() {
return cascadeStyles;
}
@Override
public FetchTiming getFetchTiming() {
return associationAttribute.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE;
}
@Override
public FetchStyle getFetchStyle() {
if ( associationAttribute.getFetchStyle() != null ) {
return associationAttribute.getFetchStyle();
}
else {
return associationAttribute.isLazy() ? FetchStyle.SELECT : FetchStyle.JOIN;
}
}
@Override
public boolean isUnWrapProxy() {
return associationAttribute.isUnWrapProxy();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "ToOneAttributeSourceImpl" );
sb.append( "{associationAttribute=" ).append( associationAttribute );
sb.append( ", cascadeStyles=" ).append( cascadeStyles );
sb.append( '}' );
return sb.toString();
}
@Override
public ForeignKeyDirection getForeignKeyDirection() {
return nature == Nature.ONE_TO_ONE && !associationAttribute.isOptional() ?
ForeignKeyDirection.FROM_PARENT :
ForeignKeyDirection.TO_PARENT;
}
}

View File

@ -13,7 +13,8 @@ import org.hibernate.metamodel.spi.source.RelationalValueSource;
/**
* @author Hardy Ferentschik
*/
public class BasicPluralAttributeElementSourceImpl extends AbstractPluralAttributeElementSource implements BasicPluralAttributeElementSource {
public class BasicPluralAttributeElementSourceImpl
extends AbstractPluralAttributeElementSourceImpl implements BasicPluralAttributeElementSource {
private final PluralAssociationAttribute associationAttribute;
private final ConfiguredClass entityClass;
private final Nature nature;

View File

@ -24,7 +24,6 @@
package org.hibernate.metamodel.internal.source.annotations;
import org.hibernate.TruthValue;
import org.hibernate.metamodel.internal.source.annotations.attribute.AttributeOverride;
import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
@ -37,20 +36,26 @@ import org.hibernate.metamodel.spi.source.SizeSource;
*/
public class ColumnSourceImpl implements ColumnSource {
private final Column columnValues;
private final String defaultTableName;
private final String readFragement;
private final String writeFragement;
private final String checkCondition;
public ColumnSourceImpl(Column columnValues) {
this( null, columnValues );
this( null, columnValues, null );
}
public ColumnSourceImpl(MappedAttribute attribute, Column columnValues) {
this( attribute, columnValues, null );
}
public ColumnSourceImpl(MappedAttribute attribute, Column columnValues, String defaultTableName) {
boolean isBasicAttribute = attribute != null && attribute.getNature() == MappedAttribute.Nature.BASIC;
this.readFragement = attribute != null && isBasicAttribute ? ( (BasicAttribute) attribute ).getCustomReadFragment() : null;
this.writeFragement = attribute != null && isBasicAttribute ? ( (BasicAttribute) attribute ).getCustomWriteFragment() : null;
this.checkCondition = attribute != null ? attribute.getCheckCondition() : null;
this.columnValues = columnValues;
this.defaultTableName = defaultTableName;
}
@Override
@ -128,12 +133,16 @@ public class ColumnSourceImpl implements ColumnSource {
@Override
public String getContainingTableName() {
if ( columnValues == null ) {
return null;
return defaultTableName;
}
else if ( columnValues.getTable() == null ) {
return defaultTableName;
}
else {
return columnValues.getTable();
}
return columnValues.getTable();
}
// these come from attribute ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override

View File

@ -174,12 +174,13 @@ public class ComponentAttributeSourceImpl implements ComponentAttributeSource, A
@Override
public String getContainingTableName() {
// none, it is defined on the sub-attributes
return null;
}
@Override
public List<RelationalValueSource> relationalValueSources() {
// none, they are defined on the simple sub-attributes
// none, they are defined on the sub-attributes
return null;
}

View File

@ -35,6 +35,9 @@ import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.PrimaryKeyJoinColumn;
import org.hibernate.metamodel.internal.source.annotations.entity.EntityClass;
import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotNames;
@ -58,6 +61,7 @@ import org.jboss.jandex.ClassInfo;
/**
* @author Hardy Ferentschik
* @author Gail Badner
*/
public class EntitySourceImpl implements EntitySource {
private final EntityClass entityClass;
@ -397,7 +401,7 @@ public class EntitySourceImpl implements EntitySource {
JPADotNames.SECONDARY_TABLE
);
if ( secondaryTable != null ) {
secondaryTableSources.add( createSecondaryTableSource( secondaryTable ) );
secondaryTableSources.add( createSecondaryTableSource( secondaryTable, true ) );
}
}
@ -414,7 +418,20 @@ public class EntitySourceImpl implements EntitySource {
AnnotationInstance[].class
);
for ( AnnotationInstance secondaryTable : tableAnnotations ) {
secondaryTableSources.add( createSecondaryTableSource( secondaryTable ) );
secondaryTableSources.add( createSecondaryTableSource( secondaryTable, true ) );
}
}
}
for(AssociationAttribute associationAttribute: entityClass.getAssociationAttributes().values()){
if( ( associationAttribute.getNature() == MappedAttribute.Nature.MANY_TO_ONE ||
associationAttribute.getNature() == MappedAttribute.Nature.ONE_TO_ONE ) ) {
AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation(
associationAttribute.annotations(),
JPADotNames.JOIN_TABLE
);
if ( joinTableAnnotation != null ) {
secondaryTableSources.add( createSecondaryTableSource( joinTableAnnotation, false ) );
}
}
}
@ -515,24 +532,35 @@ public class EntitySourceImpl implements EntitySource {
}
}
private SecondaryTableSource createSecondaryTableSource(AnnotationInstance tableAnnotation) {
final List<PrimaryKeyJoinColumn> keys = collectionSecondaryTableKeys( tableAnnotation );
private SecondaryTableSource createSecondaryTableSource(
AnnotationInstance tableAnnotation,
boolean isPrimaryKeyJoinColumn) {
final List<? extends Column> keys = collectSecondaryTableKeys( tableAnnotation, isPrimaryKeyJoinColumn );
return new SecondaryTableSourceImpl( new TableSourceImpl( tableAnnotation ), keys );
}
private List<PrimaryKeyJoinColumn> collectionSecondaryTableKeys(final AnnotationInstance tableAnnotation) {
private List<? extends Column> collectSecondaryTableKeys(
final AnnotationInstance tableAnnotation,
final boolean isPrimaryKeyJoinColumn) {
final AnnotationInstance[] joinColumnAnnotations = JandexHelper.getValue(
tableAnnotation,
"pkJoinColumns",
isPrimaryKeyJoinColumn ? "pkJoinColumns" : "joinColumns",
AnnotationInstance[].class
);
if ( joinColumnAnnotations == null ) {
return Collections.emptyList();
}
final List<PrimaryKeyJoinColumn> keys = new ArrayList<PrimaryKeyJoinColumn>();
final List<Column> keys = new ArrayList<Column>();
for ( final AnnotationInstance joinColumnAnnotation : joinColumnAnnotations ) {
keys.add( new PrimaryKeyJoinColumn( joinColumnAnnotation ) );
final Column joinColumn;
if ( isPrimaryKeyJoinColumn ) {
joinColumn = new PrimaryKeyJoinColumn( joinColumnAnnotation );
}
else {
joinColumn = new Column( joinColumnAnnotation );
}
keys.add( joinColumn );
}
return keys;
}

View File

@ -94,7 +94,7 @@ public class JoinedSubclassEntitySourceImpl extends SubclassEntitySourceImpl imp
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
List<Value> columns = new ArrayList<Value>();
for ( String name : targetColumnNames ) {
// the nulls represent table, schema and catalog name which are ignored anyway...

View File

@ -1,28 +1,15 @@
package org.hibernate.metamodel.internal.source.annotations;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHelper;
import org.hibernate.metamodel.spi.source.ManyToAnyPluralAttributeElementSource;
/**
* @author Hardy Ferentschik
*/
public class ManyToAnyPluralAttributeElementSourceImpl extends AbstractPluralAttributeElementSource implements ManyToAnyPluralAttributeElementSource {
private final PluralAssociationAttribute attribute;
public class ManyToAnyPluralAttributeElementSourceImpl
extends AbstractPluralAssociationElementSourceImpl implements ManyToAnyPluralAttributeElementSource {
public ManyToAnyPluralAttributeElementSourceImpl(PluralAssociationAttribute attribute, String relativePath) {
super(attribute, relativePath);
this.attribute = attribute;
}
@Override
public Iterable<CascadeStyle> getCascadeStyles() {
return EnumConversionHelper.cascadeTypeToCascadeStyleSet(
attribute.getCascadeTypes(),
attribute.getHibernateCascadeTypes(),
attribute.getContext() );
public ManyToAnyPluralAttributeElementSourceImpl(PluralAttributeSourceImpl pluralAttributeSource, String relativePath) {
super( pluralAttributeSource, relativePath );
}
@Override

View File

@ -0,0 +1,57 @@
package org.hibernate.metamodel.internal.source.annotations;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
/**
* @author Gail Badner
*/
public class ManyToManyMappedByPluralAttributeElementSourceImpl
extends AbstractManyToManyPluralAttributeElementSourceImpl implements MappedByAssociationSource {
public ManyToManyMappedByPluralAttributeElementSourceImpl(
PluralAttributeSourceImpl pluralAttributeSource,
final String relativePath) {
super( pluralAttributeSource, relativePath );
if ( pluralAssociationAttribute().getMappedBy() == null ) {
throw new AssertionFailure( "pluralAssociationAttribute().getMappedBy() must be non-null." );
}
}
@Override
public String getExplicitForeignKeyName() {
throw new UnsupportedOperationException( "Not supported for attributes with mappedBy specified." ); }
@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
throw new UnsupportedOperationException( "Not supported for attributes with mappedBy specified." ); }
@Override
public boolean areValuesIncludedInInsertByDefault() {
throw new UnsupportedOperationException( "Not supported for attributes with mappedBy specified." ); }
@Override
public boolean areValuesIncludedInUpdateByDefault() {
throw new UnsupportedOperationException( "Not supported for attributes with mappedBy specified." ); }
@Override
public boolean areValuesNullableByDefault() {
throw new UnsupportedOperationException( "Not supported for attributes with mappedBy specified." ); }
@Override
public boolean isMappedBy() {
return true;
}
@Override
public String getMappedBy() {
return pluralAssociationAttribute().getMappedBy();
}
@Override
public List<RelationalValueSource> relationalValueSources() {
throw new UnsupportedOperationException( "Not supported for attributes with mappedBy specified." ); }
}

View File

@ -24,88 +24,42 @@
package org.hibernate.metamodel.internal.source.annotations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.jboss.jandex.AnnotationInstance;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.AssertionFailure;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHelper;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.FilterSource;
import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
/**
* @author Hardy Ferentschik
* @author Brett Meyer
* @author Gail Badner
*/
public class ManyToManyPluralAttributeElementSourceImpl extends AbstractPluralAttributeElementSource implements ManyToManyPluralAttributeElementSource {
public class ManyToManyPluralAttributeElementSourceImpl
extends AbstractManyToManyPluralAttributeElementSourceImpl
implements ManyToManyPluralAttributeElementSource {
private final AttributeSource ownerAttributeSource;
private final PluralAssociationAttribute associationAttribute;
private final List<RelationalValueSource> relationalValueSources
= new ArrayList<RelationalValueSource>();
private final Collection<String> referencedColumnNames
= new HashSet<String>();
private final Iterable<CascadeStyle> cascadeStyles;
private final boolean isUnique;
public ManyToManyPluralAttributeElementSourceImpl(
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute,
boolean isUnique,
PluralAttributeSourceImpl pluralAttributeSource,
String relativePath) {
super(associationAttribute, relativePath);
this.ownerAttributeSource = ownerAttributeSource;
this.associationAttribute = associationAttribute;
this.isUnique = isUnique;
for ( Column column : associationAttribute.getInverseJoinColumnValues() ) {
relationalValueSources.add( new ColumnSourceImpl( column ) );
if ( column.getReferencedColumnName() != null ) {
referencedColumnNames.add( column.getReferencedColumnName() );
}
super( pluralAttributeSource, relativePath );
if ( pluralAttributeSource.getMappedBy() != null ) {
throw new AssertionFailure( "pluralAttributeSource.getMappedBy() must be null." );
}
for ( Column column : pluralAttributeSource.pluralAssociationAttribute().getInverseJoinColumnValues() ) {
relationalValueSources.add( new ColumnSourceImpl( column ) );
}
cascadeStyles = EnumConversionHelper.cascadeTypeToCascadeStyleSet(
associationAttribute.getCascadeTypes(),
associationAttribute.getHibernateCascadeTypes(),
associationAttribute.getContext() );
}
@Override
public String getReferencedEntityName() {
return associationAttribute.getReferencedEntityType();
}
@Override
public FilterSource[] getFilterSources() {
return new FilterSource[0]; //todo
}
@Override
public String getReferencedEntityAttributeName() {
// HBM only
return null;
}
@Override
public Collection<String> getReferencedColumnNames() {
return referencedColumnNames;
}
@Override
@ -113,62 +67,23 @@ public class ManyToManyPluralAttributeElementSourceImpl extends AbstractPluralAt
return relationalValueSources;
}
@Override
public Iterable<CascadeStyle> getCascadeStyles() {
return cascadeStyles;
}
@Override
public boolean isNotFoundAnException() {
return !associationAttribute.isIgnoreNotFound();
}
@Override
public String getExplicitForeignKeyName() {
if ( associationAttribute.getMappedBy() != null ) {
throw new NotYetImplementedException( "foreign key name on mappedBy side not implemented yet." );
}
else {
return associationAttribute.getInverseForeignKeyName();
}
return pluralAssociationAttribute().getInverseForeignKeyName();
}
@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
if ( associationAttribute.getMappedBy() != null ) {
if ( ownerAttributeSource instanceof PluralAttributeSource ) {
PluralAttributeSource ownerPluralAttributeSource = (PluralAttributeSource) ownerAttributeSource;
return ownerPluralAttributeSource.getKeySource().getForeignKeyTargetColumnResolutionDelegate();
}
else {
ToOneAttributeSource ownerSingularAttributeSource = (ToOneAttributeSource) ownerAttributeSource;
return ownerSingularAttributeSource.getForeignKeyTargetColumnResolutionDelegate();
boolean hasReferencedColumn = false;
for ( Column joinColumn : pluralAssociationAttribute().getInverseJoinColumnValues() ) {
if ( joinColumn.getReferencedColumnName() != null ) {
hasReferencedColumn = true;
break;
}
}
return associationAttribute.getJoinColumnValues().isEmpty() ?
null :
new AnnotationJoinColumnResolutionDelegate();
}
@Override
public boolean isUnique() {
return isUnique;
}
@Override
public String getWhere() {
return associationAttribute.getWhereClause();
}
@Override
public FetchTiming getFetchTiming() {
return FetchTiming.IMMEDIATE;
}
@Override
public Nature getNature() {
return Nature.MANY_TO_MANY;
return hasReferencedColumn ?
new AnnotationJoinColumnResolutionDelegate() :
null;
}
@Override
@ -186,16 +101,6 @@ public class ManyToManyPluralAttributeElementSourceImpl extends AbstractPluralAt
return false;
}
@Override
public boolean isOrdered() {
return StringHelper.isNotEmpty( associationAttribute.getOrderBy() );
}
@Override
public String getOrder() {
return associationAttribute.getOrderBy();
}
// TODO: This needs reworked.
public class AnnotationJoinColumnResolutionDelegate
implements ForeignKeyContributingSource.JoinColumnResolutionDelegate {
@ -206,12 +111,9 @@ public class ManyToManyPluralAttributeElementSourceImpl extends AbstractPluralAt
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
final List<Value> values = new ArrayList<Value>();
for ( Column column : associationAttribute.getInverseJoinColumnValues() ) {
if ( column.getReferencedColumnName() == null ) {
return context.resolveRelationalValuesForAttribute( null );
}
for ( Column column : pluralAssociationAttribute().getInverseJoinColumnValues() ) {
org.hibernate.metamodel.spi.relational.Column resolvedColumn = context.resolveColumn(
column.getReferencedColumnName(),
null,
@ -236,7 +138,7 @@ public class ManyToManyPluralAttributeElementSourceImpl extends AbstractPluralAt
private String resolveLogicalJoinTableName() {
final AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation(
associationAttribute.annotations(),
pluralAssociationAttribute().annotations(),
JPADotNames.JOIN_TABLE
);

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.source.annotations;
import org.hibernate.AssertionFailure;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
/**
* @author Gail Badner
*/
public class OneToManyMappedByPluralAttributeElementSourceImpl
extends OneToManyPluralAttributeElementSourceImpl implements MappedByAssociationSource {
public OneToManyMappedByPluralAttributeElementSourceImpl(
PluralAttributeSourceImpl pluralAttributeSource,
String relativePath) {
super( pluralAttributeSource, relativePath );
if ( pluralAttributeSource.pluralAssociationAttribute().getMappedBy() == null ) {
throw new AssertionFailure( "pluralAssociationAttribute().getMappedBy() must be non-null." );
}
}
@Override
public boolean isMappedBy() {
return true;
}
@Override
public String getMappedBy() {
return pluralAssociationAttribute().getMappedBy();
}
}

View File

@ -23,71 +23,24 @@
*/
package org.hibernate.metamodel.internal.source.annotations;
import org.hibernate.AssertionFailure;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHelper;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.OneToManyPluralAttributeElementSource;
/**
* @author Hardy Ferentschik
*/
public class OneToManyPluralAttributeElementSourceImpl extends AbstractPluralAttributeElementSource implements OneToManyPluralAttributeElementSource {
private final AttributeSource ownerAttributeSource;
private final PluralAssociationAttribute associationAttribute;
public class OneToManyPluralAttributeElementSourceImpl
extends AbstractPluralAssociationElementSourceImpl implements OneToManyPluralAttributeElementSource {
public OneToManyPluralAttributeElementSourceImpl(
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute,
PluralAttributeSourceImpl pluralAttributeSource,
String relativePath) {
super(associationAttribute, relativePath);
this.ownerAttributeSource = ownerAttributeSource;
this.associationAttribute = associationAttribute;
}
@Override
public String getReferencedEntityName() {
return associationAttribute.getReferencedEntityType();
}
@Override
public boolean isNotFoundAnException() {
return !associationAttribute.isIgnoreNotFound();
}
@Override
public Iterable<CascadeStyle> getCascadeStyles() {
return EnumConversionHelper.cascadeTypeToCascadeStyleSet(
associationAttribute.getCascadeTypes(),
associationAttribute.getHibernateCascadeTypes(),
associationAttribute.getContext() );
super( pluralAttributeSource, relativePath );
}
@Override
public Nature getNature() {
switch ( associationAttribute.getNature() ) {
case MANY_TO_MANY: {
return Nature.MANY_TO_MANY;
}
case MANY_TO_ANY: {
return Nature.MANY_TO_ANY;
}
case ONE_TO_MANY: {
return Nature.ONE_TO_MANY;
}
case ELEMENT_COLLECTION_BASIC: {
return Nature.BASIC;
}
case ELEMENT_COLLECTION_EMBEDDABLE: {
return Nature.AGGREGATE;
}
default: {
throw new AssertionFailure( "Unexpected attribute nature: " + associationAttribute.getNature() );
}
}
return Nature.ONE_TO_MANY;
}
}

View File

@ -77,7 +77,9 @@ public class PluralAttributeKeySourceImpl implements PluralAttributeKeySource {
@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
if ( attribute.getMappedBy() != null ) {
throw new IllegalStateException( "Cannot determine foreign key information because association is not the owner." );
}
for ( Column joinColumn : attribute.getJoinColumnValues() ) {
if ( StringHelper.isNotEmpty( joinColumn.getReferencedColumnName() ) ) {
return new JoinColumnResolutionDelegateImpl( attribute );
@ -107,7 +109,7 @@ public class PluralAttributeKeySourceImpl implements PluralAttributeKeySource {
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
List<Column> joinColumnValues = attribute.getJoinColumnValues();
if ( joinColumnValues.isEmpty() ) {
return null;

View File

@ -30,7 +30,7 @@ import java.util.Map;
import org.jboss.jandex.AnnotationInstance;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.AssertionFailure;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.StringHelper;
@ -43,10 +43,12 @@ import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotName
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.binding.Caching;
import org.hibernate.metamodel.spi.binding.CustomSQL;
import org.hibernate.metamodel.spi.source.AssociationSource;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.AttributeSourceResolutionContext;
import org.hibernate.metamodel.spi.source.HibernateTypeSource;
import org.hibernate.metamodel.spi.source.FilterSource;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.MetaAttributeSource;
import org.hibernate.metamodel.spi.source.Orderable;
import org.hibernate.metamodel.spi.source.PluralAttributeElementSource;
@ -86,7 +88,7 @@ public class PluralAttributeSourceImpl implements AnnotationAttributeSource, Plu
if ( associationAttribute.getMappedBy() == null ) {
this.ownerAttributeSource = this;
this.elementSource = determineElementSource( this, associationAttribute, entityClass, attributePath );
this.elementSource = determineElementSource( this, this, entityClass, attributePath );
}
this.filterSources = determineFilterSources(associationAttribute);
}
@ -160,12 +162,6 @@ public class PluralAttributeSourceImpl implements AnnotationAttributeSource, Plu
return associationAttribute.getBatchSize();
}
public static boolean usesJoinTable(AttributeSource ownerAttributeSource) {
return ownerAttributeSource.isSingular() ?
( (ToOneAttributeSource) ownerAttributeSource ).getContainingTableName() != null :
( (PluralAttributeSource) ownerAttributeSource ).usesJoinTable();
}
@Override
public boolean usesJoinTable() {
if ( associationAttribute.getMappedBy() != null ) {
@ -192,18 +188,34 @@ public class PluralAttributeSourceImpl implements AnnotationAttributeSource, Plu
private static PluralAttributeElementSource determineElementSource(
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute,
PluralAttributeSourceImpl pluralAttributeSource,
ConfiguredClass entityClass,
String relativePath) {
switch ( associationAttribute.getNature() ) {
if ( ownerAttributeSource == null ) {
throw new AssertionFailure( "ownerAssociationSource must be non-null." );
}
final PluralAssociationAttribute associationAttribute = pluralAttributeSource.pluralAssociationAttribute();
switch ( pluralAttributeSource.pluralAssociationAttribute().getNature() ) {
case MANY_TO_MANY:
return new ManyToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute, false, relativePath );
return associationAttribute.getMappedBy() == null ?
new ManyToManyPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath ) :
new ManyToManyMappedByPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath );
case MANY_TO_ANY:
return new ManyToAnyPluralAttributeElementSourceImpl( associationAttribute, relativePath );
return new ManyToAnyPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath );
case ONE_TO_MANY:
return usesJoinTable( ownerAttributeSource ) ?
new ManyToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute, true, relativePath ) :
new OneToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute, relativePath );
boolean usesJoinTable = ownerAttributeSource.isSingular() ?
( (ToOneAttributeSource) ownerAttributeSource ).getContainingTableName() != null :
( (PluralAttributeSource) ownerAttributeSource ).usesJoinTable();
if ( usesJoinTable ) {
return associationAttribute.getMappedBy() == null ?
new ManyToManyPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath ) :
new ManyToManyMappedByPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath );
}
else {
return associationAttribute.getMappedBy() == null ?
new OneToManyPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath ) :
new OneToManyMappedByPluralAttributeElementSourceImpl( pluralAttributeSource, relativePath );
}
case ELEMENT_COLLECTION_BASIC:
return new BasicPluralAttributeElementSourceImpl( associationAttribute, entityClass, relativePath );
case ELEMENT_COLLECTION_EMBEDDABLE: {
@ -226,14 +238,7 @@ public class PluralAttributeSourceImpl implements AnnotationAttributeSource, Plu
// todo - see org.hibernate.metamodel.internal.Binder#bindOneToManyCollectionKey
// todo - needs to cater for @CollectionTable and @JoinTable
if ( associationAttribute.getMappedBy() != null ) {
if ( ownerAttributeSource.isSingular() ) {
ToOneAttributeSource ownerSingularAttributeSource = (ToOneAttributeSource) ownerAttributeSource;
throw new NotYetImplementedException( "mappedBy many-to-many owned by many-to-one not supported yet." );
}
else {
PluralAttributeSource ownerPluralAttributeSource = (PluralAttributeSource) ownerAttributeSource;
return ownerPluralAttributeSource.getCollectionTableSpecificationSource();
}
throw new IllegalStateException( "Cannot get collection table because this association is not the owner." );
}
final AnnotationInstance joinTableAnnotation = associationAttribute.getJoinTableAnnotation();
return joinTableAnnotation == null ? null : new TableSourceImpl( joinTableAnnotation );
@ -387,7 +392,22 @@ public class PluralAttributeSourceImpl implements AnnotationAttributeSource, Plu
associationAttribute.getMappedBy()
);
// Initialize resolved entitySource.
elementSource = determineElementSource( ownerAttributeSource, associationAttribute, entityClass, "" ); //TODO not sure what relativePath should be here
elementSource = determineElementSource( ownerAttributeSource, this, entityClass, "" ); //TODO not sure what relativePath should be here
if ( !MappedByAssociationSource.class.isInstance( elementSource ) ) {
throw new AssertionFailure( "expected a mappedBy association." );
}
final AssociationSource ownerAssociationSource;
if ( ownerAttributeSource.isSingular() ) {
ownerAssociationSource = (ToOneAttributeSource) ownerAttributeSource;
}
else {
final PluralAttributeSource pluralAttributeSource = (PluralAttributeSource) ownerAttributeSource;
if ( !AssociationSource.class.isInstance( pluralAttributeSource.getElementSource() ) ) {
throw new AssertionFailure( "Owner is not an association." );
}
ownerAssociationSource = (AssociationSource) pluralAttributeSource.getElementSource();
}
ownerAssociationSource.addMappedByAssociationSource( (MappedByAssociationSource) elementSource );
}
return elementSource;
}

View File

@ -267,8 +267,12 @@ public class RootEntitySourceImpl extends EntitySourceImpl implements RootEntity
break;
case MANY_TO_ONE:
case ONE_TO_ONE:
//others??
attributeSources.add( new ToOneAttributeSourceImpl( (SingularAssociationAttribute) attr,"" ) );
final SingularAssociationAttribute associationAttribute = (SingularAssociationAttribute) attr;
final SingularAttributeSource attributeSource =
associationAttribute.getMappedBy() == null ?
new ToOneAttributeSourceImpl( associationAttribute, "" ) :
new ToOneMappedByAttributeSourceImpl( associationAttribute, "" );
attributeSources.add( attributeSource );
}
}
return attributeSources;

View File

@ -27,7 +27,7 @@ import java.util.ArrayList;
import java.util.List;
import org.hibernate.engine.FetchStyle;
import org.hibernate.metamodel.internal.source.annotations.attribute.PrimaryKeyJoinColumn;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
import org.hibernate.metamodel.spi.binding.CustomSQL;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
@ -45,21 +45,21 @@ public class SecondaryTableSourceImpl implements SecondaryTableSource {
public SecondaryTableSourceImpl(
TableSpecificationSource joinTable,
List<PrimaryKeyJoinColumn> joinColumns) {
List<? extends Column> joinColumns) {
this.joinTable = joinTable;
// todo : following normal annotation idiom for source, we probably want to move this stuff up to EntityClass...
columnSources = new ArrayList<ColumnSource>();
final List<String> targetColumnNames = new ArrayList<String>();
boolean hadNamedTargetColumnReferences = false;
for ( PrimaryKeyJoinColumn primaryKeyJoinColumnSource : joinColumns ) {
for ( Column joinColumn : joinColumns ) {
columnSources.add(
new ColumnSourceImpl(
primaryKeyJoinColumnSource
joinColumn
)
);
targetColumnNames.add( primaryKeyJoinColumnSource.getReferencedColumnName() );
if ( primaryKeyJoinColumnSource.getReferencedColumnName() != null ) {
targetColumnNames.add( joinColumn.getReferencedColumnName() );
if ( joinColumn.getReferencedColumnName() != null ) {
hadNamedTargetColumnReferences = true;
}
}
@ -138,7 +138,7 @@ public class SecondaryTableSourceImpl implements SecondaryTableSource {
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
List<Value> columns = new ArrayList<Value>();
for ( String name : targetColumnNames ) {
// the nulls represent table, schema and catalog name which are ignored anyway...

View File

@ -41,6 +41,7 @@ import org.hibernate.metamodel.internal.source.annotations.entity.ConfiguredClas
import org.hibernate.metamodel.internal.source.annotations.entity.EmbeddableClass;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
/**
* @author Strong Liu <stliu@hibernate.org>
@ -110,7 +111,12 @@ public class SourceHelper {
switch ( associationAttribute.getNature() ) {
case ONE_TO_ONE:
case MANY_TO_ONE: {
ToOneAttributeSourceImpl source = new ToOneAttributeSourceImpl( (SingularAssociationAttribute) associationAttribute, relativePath );
final SingularAssociationAttribute singularAssociationAttribute =
(SingularAssociationAttribute) associationAttribute;
final SingularAttributeSource source =
associationAttribute.getMappedBy() == null ?
new ToOneAttributeSourceImpl( singularAssociationAttribute, relativePath ) :
new ToOneMappedByAttributeSourceImpl( singularAssociationAttribute, relativePath );
attributeList.add( source );
break;
}

View File

@ -33,65 +33,54 @@ import org.jboss.jandex.AnnotationInstance;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.metamodel.internal.Binder;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.SingularAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHelper;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.AttributeSourceResolutionContext;
import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSourceNatureResolver;
import org.hibernate.type.ForeignKeyDirection;
/**
* @author Hardy Ferentschik
* @author Gail Badner
*/
public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implements ToOneAttributeSource {
private final AssociationAttribute associationAttribute;
private final Set<CascadeStyle> cascadeStyles;
private SingularAttributeSource.Nature nature;
public class ToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl implements ToOneAttributeSource {
private List<RelationalValueSource> relationalValueSources;
private String containingTableName;
public ToOneAttributeSourceImpl(SingularAssociationAttribute associationAttribute, String relativePath) {
super( associationAttribute, relativePath );
this.associationAttribute = associationAttribute;
this.cascadeStyles = EnumConversionHelper.cascadeTypeToCascadeStyleSet(
associationAttribute.getCascadeTypes(),
associationAttribute.getHibernateCascadeTypes(),
associationAttribute.getContext()
);
this.nature = determineNatureIfPossible( associationAttribute );
if ( associationAttribute.getMappedBy() != null ) {
throw new IllegalArgumentException( "associationAttribute.getMappedBy() must be null" );
}
// Need to initialize relationalValueSources before determining logicalJoinTableName.
this.relationalValueSources = resolveRelationalValueSources( associationAttribute );
// Need to initialize logicalJoinTableName before determining nature.
this.containingTableName = resolveContainingTableName( associationAttribute, relationalValueSources );
setNature( determineNatureIfPossible( associationAttribute ) );
}
private static Nature determineNatureIfPossible(SingularAssociationAttribute associationAttribute) {
private Nature determineNatureIfPossible(
SingularAssociationAttribute associationAttribute) {
if ( MappedAttribute.Nature.MANY_TO_ONE.equals( associationAttribute.getNature() ) ) {
return Nature.MANY_TO_ONE;
}
else if ( MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute.getNature() ) ) {
if ( associationAttribute.getMappedBy() != null ) {
// This means it is a one-to-one, but it is not working yet.
//return Nature.ONE_TO_ONE;
throw new NotYetImplementedException( "@OneToOne with mappedBy specified is not supported yet." );
if ( getContainingTableName() != null ) {
return Nature.MANY_TO_ONE;
}
else if ( associationAttribute.hasPrimaryKeyJoinColumn() ) {
return Nature.ONE_TO_ONE;
}
else if ( associationAttribute.getJoinTableAnnotation() != null ) {
return Nature.MANY_TO_ONE;
}
else if ( associationAttribute.isId() ) {
// if this association is part of the ID then this can't be a one-to-one
return Nature.MANY_TO_ONE;
@ -110,48 +99,36 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
}
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolver.ToOneAttributeSourceNatureResolutionContext context) {
if ( nature != null ) { return nature; }
final List<org.hibernate.metamodel.spi.relational.Column> idColumns = context.getIdentifierColumns();
if ( associationAttribute.getJoinColumnValues().size() != idColumns.size() ) {
nature = Nature.MANY_TO_ONE;
public void resolveToOneAttributeSource(AttributeSourceResolutionContext context) {
if ( getNature() != null ) {
return;
}
else {
Set<String> joinColumnNames = new HashSet<String>( associationAttribute.getJoinColumnValues().size() );
for ( Column joinColumn : associationAttribute.getJoinColumnValues() ) {
joinColumnNames.add( joinColumn.getName() );
// It would be nice to have the following block in determineNatureIfPossible(),
// but it requires context.resolveIdentifierColumns(), it's here instead.
if ( MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute().getNature() ) ) {
final List<org.hibernate.metamodel.spi.relational.Column> idColumns = context.resolveIdentifierColumns();
if ( associationAttribute().getJoinColumnValues().size() != idColumns.size() ) {
setNature( Nature.MANY_TO_ONE );
}
// if join columns are the entity's ID, then it is a one-to-one (mapToPk == true)
boolean areJoinColumnsSameAsIdColumns = true;
for ( org.hibernate.metamodel.spi.relational.Column idColumn : idColumns ) {
if ( ! joinColumnNames.contains( idColumn.getColumnName().getText() ) ) {
areJoinColumnsSameAsIdColumns = false;
break;
else {
Set<String> joinColumnNames = new HashSet<String>( associationAttribute().getJoinColumnValues().size() );
for ( Column joinColumn : associationAttribute().getJoinColumnValues() ) {
joinColumnNames.add( joinColumn.getName() );
}
// if join columns are the entity's ID, then it is a one-to-one (mapToPk == true)
boolean areJoinColumnsSameAsIdColumns = true;
for ( org.hibernate.metamodel.spi.relational.Column idColumn : idColumns ) {
if ( ! joinColumnNames.contains( idColumn.getColumnName().getText() ) ) {
areJoinColumnsSameAsIdColumns = false;
break;
}
}
setNature( areJoinColumnsSameAsIdColumns ? Nature.ONE_TO_ONE : Nature.MANY_TO_ONE );
}
nature = areJoinColumnsSameAsIdColumns ? Nature.ONE_TO_ONE : Nature.MANY_TO_ONE;
}
return nature;
}
@Override
public Nature getNature() {
return nature;
}
@Override
public String getReferencedEntityName() {
return associationAttribute.getReferencedEntityType();
}
@Override
public boolean isUnique() {
return MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute.getNature() );
}
@Override
public boolean isNotFoundAnException() {
return !associationAttribute.isIgnoreNotFound();
if ( getNature() == null ) {
throw new NotYetImplementedException( "unknown type of to-one attribute." );
}
}
@Override
@ -174,7 +151,7 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
@Override
public String defaultName(NamingStrategy namingStrategy) {
return namingStrategy.foreignKeyColumnName(
associationAttribute.getName(),
associationAttribute().getName(),
entityName,
tableName,
referencedAttributeBinding.getAttribute().getName()
@ -186,32 +163,85 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
}
}
private final ValueHolder<List<RelationalValueSource>> relationalValues = new ValueHolder<List<RelationalValueSource>>( new ValueHolder.DeferredInitializer<List<RelationalValueSource>>() {
@Override
public List<RelationalValueSource> initialize() {
if ( associationAttribute.getJoinColumnValues().isEmpty() ) {
return Collections.emptyList();
}
List<RelationalValueSource> valueSources = new ArrayList<RelationalValueSource>(
associationAttribute.getJoinColumnValues()
.size()
);
for ( Column column : associationAttribute.getJoinColumnValues() ) {
valueSources.add( new ColumnSourceImpl( column ) );
}
return valueSources;
}
} );
@Override
public List<RelationalValueSource> relationalValueSources() {
return relationalValues.getValue();
return relationalValueSources;
}
@Override
public String getContainingTableName() {
return containingTableName;
}
private static List<RelationalValueSource> resolveRelationalValueSources(AssociationAttribute associationAttribute) {
final List<RelationalValueSource> valueSources;
final List<Column> joinColumns;
if ( associationAttribute.getJoinTableAnnotation() == null ) {
joinColumns = associationAttribute.getJoinColumnValues();
}
else {
joinColumns = associationAttribute.getInverseJoinColumnValues();
}
if ( joinColumns.isEmpty() ) {
valueSources = Collections.emptyList();
}
else {
valueSources = new ArrayList<RelationalValueSource>( joinColumns.size() );
for ( Column joinColumn : joinColumns ) {
valueSources.add(
new ColumnSourceImpl(
associationAttribute,
joinColumn,
getDefaultLogicalJoinTableName( associationAttribute )
)
);
}
}
return valueSources;
}
private static String getDefaultLogicalJoinTableName(AssociationAttribute associationAttribute) {
if ( associationAttribute.getJoinTableAnnotation() == null ) {
return null;
}
return JandexHelper.getValue( associationAttribute.getJoinTableAnnotation(), "name", String.class );
}
private static String resolveContainingTableName(
AssociationAttribute associationAttribute,
List<RelationalValueSource> relationalValueSources) {
if ( relationalValueSources.isEmpty() ) {
return getDefaultLogicalJoinTableName( associationAttribute );
}
String logicalTableName = relationalValueSources.get( 0 ).getContainingTableName();
for ( int i = 1; i< relationalValueSources.size(); i++ ) {
if ( logicalTableName == null ) {
if ( relationalValueSources.get( i ).getContainingTableName() != null ) {
throw new IllegalStateException( "Relational value sources refer to null and non-null containing tables." );
}
}
else if ( !logicalTableName.equals( relationalValueSources.get( i ).getContainingTableName() ) ) {
throw new IllegalStateException( "Relational value sources do not refer to the same containing table." );
}
}
return logicalTableName;
}
@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
return associationAttribute.getJoinColumnValues()
.isEmpty() ? null : new AnnotationJoinColumnResolutionDelegate();
List<Column> joinColumns =
associationAttribute().getJoinTableAnnotation() == null ?
associationAttribute().getJoinColumnValues() :
associationAttribute().getInverseJoinColumnValues();
boolean hasReferencedColumn = false;
for ( Column joinColumn : joinColumns ) {
if ( joinColumn.getReferencedColumnName() != null ) {
hasReferencedColumn = true;
break;
}
}
return hasReferencedColumn ? new AnnotationJoinColumnResolutionDelegate() : null;
}
@Override
@ -219,66 +249,23 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
return null;
}
@Override
public Iterable<CascadeStyle> getCascadeStyles() {
return cascadeStyles;
}
@Override
public FetchTiming getFetchTiming() {
return associationAttribute.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE;
}
@Override
public FetchStyle getFetchStyle() {
if ( associationAttribute.getFetchStyle() != null ) {
return associationAttribute.getFetchStyle();
}
else {
return associationAttribute.isLazy() ? FetchStyle.SELECT : FetchStyle.JOIN;
}
}
@Override
public boolean isUnWrapProxy() {
return associationAttribute.isUnWrapProxy();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "ToOneAttributeSourceImpl" );
sb.append( "{associationAttribute=" ).append( associationAttribute );
sb.append( ", cascadeStyles=" ).append( cascadeStyles );
sb.append( '}' );
return sb.toString();
}
@Override
public ForeignKeyDirection getForeignKeyDirection() {
return getNature() == Nature.ONE_TO_ONE && !associationAttribute.isOptional() ?
ForeignKeyDirection.FROM_PARENT :
ForeignKeyDirection.TO_PARENT;
}
public class AnnotationJoinColumnResolutionDelegate
implements ForeignKeyContributingSource.JoinColumnResolutionDelegate {
private final String logicalJoinTableName;
public AnnotationJoinColumnResolutionDelegate() {
logicalJoinTableName = resolveLogicalJoinTableName();
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
final List<Value> values = new ArrayList<Value>();
for ( Column column : associationAttribute.getJoinColumnValues() ) {
if ( column.getReferencedColumnName() == null ) {
final List<Column> joinColumns =
associationAttribute().getJoinTableAnnotation() == null ?
associationAttribute().getJoinColumnValues() :
associationAttribute().getInverseJoinColumnValues();
for ( Column joinColumn : joinColumns ) {
if ( joinColumn.getReferencedColumnName() == null ) {
return context.resolveRelationalValuesForAttribute( null );
}
org.hibernate.metamodel.spi.relational.Column resolvedColumn = context.resolveColumn(
column.getReferencedColumnName(),
logicalJoinTableName,
joinColumn.getReferencedColumnName(),
null,
null,
null
);
@ -290,7 +277,7 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
@Override
public TableSpecification getReferencedTable(JoinColumnResolutionContext context) {
return context.resolveTable(
logicalJoinTableName,
null,
null,
null
);
@ -304,7 +291,7 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
private String resolveLogicalJoinTableName() {
final AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation(
associationAttribute.annotations(),
associationAttribute().annotations(),
JPADotNames.JOIN_TABLE
);

View File

@ -0,0 +1,119 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.source.annotations;
import java.util.List;
import org.hibernate.metamodel.internal.Binder;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.SingularAssociationAttribute;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.source.AttributeSourceResolutionContext;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
/**
* @author Gail Badner
*/
public class ToOneMappedByAttributeSourceImpl extends AbstractToOneAttributeSourceImpl implements MappedByAssociationSource {
private ToOneAttributeSource owner;
public ToOneMappedByAttributeSourceImpl(SingularAssociationAttribute associationAttribute, String relativePath) {
super( associationAttribute, relativePath);
if ( associationAttribute.getMappedBy() == null ) {
throw new IllegalArgumentException( "associationAttribute.getMappedBy() must be non-null" );
}
}
@Override
public void resolveToOneAttributeSource(AttributeSourceResolutionContext context) {
if ( getNature() != null && owner != null) {
return;
}
if ( owner == null ) {
owner = (ToOneAttributeSource) context.resolveAttributeSource(
associationAttribute().getReferencedEntityType(),
associationAttribute().getMappedBy()
);
owner.addMappedByAssociationSource( this );
}
if ( getNature() == null ) {
final Nature nature;
if ( MappedAttribute.Nature.MANY_TO_ONE.equals( associationAttribute().getNature() ) ) {
nature = Nature.MANY_TO_ONE;
}
else if ( MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute().getNature() ) ) {
if ( owner.getContainingTableName() != null ) {
nature = Nature.MANY_TO_ONE;
}
else {
nature = Nature.ONE_TO_ONE;
}
}
else {
throw new AssertionError(String.format(
"Wrong attribute nature[%s] for toOne attribute: %s",
associationAttribute().getNature(), associationAttribute().getRole()
));
}
setNature( nature );
}
}
@Override
public boolean isMappedBy() {
return true;
}
@Override
public String getMappedBy() {
return associationAttribute().getMappedBy();
}
@Override
public List<RelationalValueSource> relationalValueSources() {
throw new UnsupportedOperationException( "Not supported for a \"mappedBy\" association." );
}
@Override
public String getContainingTableName() {
throw new UnsupportedOperationException( "Not supported for a \"mappedBy\" association." );
}
@Override
public String getExplicitForeignKeyName() {
throw new UnsupportedOperationException( "Not supported for a \"mappedBy\" association." );
}
@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
throw new UnsupportedOperationException( "Not supported for a \"mappedBy\" association." );
}
@Override
public List<Binder.DefaultNamingStrategy> getDefaultNamingStrategies(String entityName, String tableName, AttributeBinding referencedAttributeBinding) {
throw new UnsupportedOperationException( "Not supported for a \"mappedBy\" association." );
}
}

View File

@ -38,13 +38,11 @@ import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.logging.Logger;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.engine.FetchStyle;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
@ -65,6 +63,7 @@ import org.hibernate.metamodel.spi.source.MappingException;
*
* @author Hardy Ferentschik
* @author Brett Meyer
* @author Gail Badner
*/
public class AssociationAttribute extends MappedAttribute {
private static final CoreMessageLogger coreLogger = Logger.getMessageLogger(
@ -76,7 +75,6 @@ public class AssociationAttribute extends MappedAttribute {
private final String referencedEntityType;
private final Class<?> referencedAttributeType;
private final String mappedBy;
private final boolean isJpaInverse;
private final Set<CascadeType> cascadeTypes;
private final Set<org.hibernate.annotations.CascadeType> hibernateCascadeTypes;
private final boolean isOptional;
@ -91,27 +89,6 @@ public class AssociationAttribute extends MappedAttribute {
private final AnnotationInstance joinTableAnnotation;
private AttributeTypeResolver resolver;
static AssociationAttribute createAssociationAttribute(
ClassInfo classInfo,
String name,
Class<?> attributeType,
Nature attributeNature,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
EntityBindingContext context) {
return new AssociationAttribute(
classInfo,
name,
attributeType,
attributeType,
attributeNature,
accessType,
annotations,
context
);
}
AssociationAttribute(
ClassInfo classInfo,
String name,
@ -150,24 +127,27 @@ public class AssociationAttribute extends MappedAttribute {
this.referencedEntityType = determineReferencedEntityType( associationAnnotation, referencedAttributeType );
this.referencedAttributeType = referencedAttributeType;
this.mappedBy = determineMappedByAttributeName( associationAnnotation );
this.isJpaInverse = mappedBy != null;
this.isOptional = determineOptionality( associationAnnotation );
this.isLazy = determineIsLazy( associationAnnotation );
this.isUnWrapProxy = determinIsUnwrapProxy();
this.isOrphanRemoval = determineOrphanRemoval( associationAnnotation );
this.cascadeTypes = determineCascadeTypes( associationAnnotation );
this.hibernateCascadeTypes = determineHibernateCascadeTypes( annotations );
determineJoinColumnAnnotations( annotations );
determineJoinTableAnnotations( annotations, referencedAttributeType );
joinColumnValues.trimToSize();
inverseJoinColumnValues.trimToSize();
if ( this.mappedBy == null ) {
determineJoinColumnAnnotations( annotations );
determineJoinTableAnnotations( annotations, referencedAttributeType );
joinColumnValues.trimToSize();
inverseJoinColumnValues.trimToSize();
this.joinTableAnnotation = determineExplicitJoinTable( annotations );
}
else {
this.joinTableAnnotation = null;
}
this.fetchStyle = determineFetchStyle();
this.referencedIdAttributeName = determineMapsId();
this.mapsId = referencedIdAttributeName != null;
this.joinTableAnnotation = determineExplicitJoinTable( annotations );
}
public boolean isIgnoreNotFound() {
@ -211,14 +191,23 @@ public class AssociationAttribute extends MappedAttribute {
}
public List<Column> getJoinColumnValues() {
if ( mappedBy != null ) {
throw new IllegalStateException( "Cannot determine join column information because assocation is not owner." );
}
return joinColumnValues;
}
public List<Column> getInverseJoinColumnValues() {
if ( mappedBy != null ) {
throw new IllegalStateException( "Cannot determine inverse join column information because assocation is not owner." );
}
return inverseJoinColumnValues;
}
public AnnotationInstance getJoinTableAnnotation() {
if ( mappedBy != null ) {
throw new IllegalStateException( "Cannot determine join table information because assocation is not owner." );
}
return joinTableAnnotation;
}
@ -271,7 +260,6 @@ public class AssociationAttribute extends MappedAttribute {
}
@Override
public PropertyGeneration getPropertyGeneration() {
return PropertyGeneration.NEVER;
@ -458,6 +446,12 @@ public class AssociationAttribute extends MappedAttribute {
}
private void determineJoinColumnAnnotations(Map<DotName, List<AnnotationInstance>> annotations) {
// If mappedBy is defined, then annotations for this association are on the
// owning side of the association.
if ( mappedBy != null ) {
throw new IllegalStateException( "Cannot determine join column information because association is not the owner." );
}
Collection<AnnotationInstance> joinColumnAnnotations = JandexHelper.getAnnotations(
annotations,
JPADotNames.JOIN_COLUMN,
@ -468,7 +462,6 @@ public class AssociationAttribute extends MappedAttribute {
joinColumnValues.add( new Column( joinColumnAnnotation ) );
}
// @JoinColumn as part of @CollectionTable
AnnotationInstance collectionTableAnnotation = JandexHelper.getSingleAnnotation(
annotations,
@ -487,21 +480,13 @@ public class AssociationAttribute extends MappedAttribute {
private void determineJoinTableAnnotations(
Map<DotName, List<AnnotationInstance>> annotations,
Class<?> referencedAttributeType ) {
// If JPA and 'mappedBy' (inverse side), override the annotations
// with the owning side.
if ( isJpaInverse ) {
// TODO: Pull some of this into JandexHelper.
IndexView index = JandexHelper.indexForClass(
getContext().getServiceRegistry().getService(
ClassLoaderService.class ), referencedAttributeType );
ClassInfo classInfo = index.getClassByName( DotName.createSimple(
referencedAttributeType.getName() ) );
annotations = JandexHelper.getMemberAnnotations(
classInfo, getMappedBy(), getContext().getServiceRegistry() );
// If mappedBy is defined, then annotations for this association are on the
// owning side of the association.
if ( mappedBy != null ) {
throw new IllegalStateException( "Cannot determine join table information because association is not the owner." );
}
// @JoinColumn as part of @JoinTable
AnnotationInstance joinTableAnnotation = JandexHelper.getSingleAnnotation(
annotations,
@ -515,25 +500,22 @@ public class AssociationAttribute extends MappedAttribute {
JandexHelper.getValue( joinTableAnnotation, "inverseJoinColumns", AnnotationInstance[].class )
);
// If the mappedBy inverse, flipped. Confused yet?
for ( AnnotationInstance annotation : columnsList ) {
if ( isJpaInverse ) {
inverseJoinColumnValues.add( new Column( annotation ) );
} else {
joinColumnValues.add( new Column( annotation ) );
}
joinColumnValues.add( new Column( annotation ) );
}
for ( AnnotationInstance annotation : inverseColumnsList ) {
if ( isJpaInverse ) {
joinColumnValues.add( new Column( annotation ) );
} else {
inverseJoinColumnValues.add( new Column( annotation ) );
}
inverseJoinColumnValues.add( new Column( annotation ) );
}
}
}
private AnnotationInstance determineExplicitJoinTable(Map<DotName, List<AnnotationInstance>> annotations) {
// If mappedBy is defined, then annotations for this association are on the
// owning side of the association.
if ( mappedBy != null ) {
throw new IllegalStateException( "Cannot determine join table information because association is not the owner." );
}
AnnotationInstance annotationInstance = null;
AnnotationInstance collectionTableAnnotation = JandexHelper.getSingleAnnotation(
annotations,
@ -582,5 +564,3 @@ public class AssociationAttribute extends MappedAttribute {
return annotationInstance;
}
}

View File

@ -0,0 +1,72 @@
/**
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal.source.hbm;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.metamodel.spi.source.AssociationSource;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
/**
+ * @author Gail Badner
+ */
public abstract class AbstractPluralAssociationElementSourceImpl
extends AbstractHbmSourceNode implements AssociationSource {
private final PluralAttributeSource pluralAttributeSource;
private final Set<MappedByAssociationSource> ownedAssociationSources = new HashSet<MappedByAssociationSource>( );
public AbstractPluralAssociationElementSourceImpl(
MappingDocument mappingDocument,
PluralAttributeSource pluralAttributeSource) {
super( mappingDocument );
this.pluralAttributeSource = pluralAttributeSource;
}
@Override
public AttributeSource getAttributeSource() {
return pluralAttributeSource;
}
@Override
public Set<MappedByAssociationSource> getOwnedAssociationSources() {
return ownedAssociationSources;
}
@Override
public void addMappedByAssociationSource(MappedByAssociationSource attributeSource) {
if ( attributeSource == null ) {
throw new IllegalArgumentException( "attributeSource must be non-null." );
}
ownedAssociationSources.add( attributeSource );
}
@Override
public boolean isMappedBy() {
return false;
}
}

View File

@ -143,6 +143,7 @@ public abstract class AbstractPluralAttributeSourceImpl
.getOneToMany().getClazz());
return new OneToManyPluralAttributeElementSourceImpl(
sourceMappingDocument(),
this,
pluralAttributeElement.getOneToMany(),
pluralAttributeElement.getCascade()
);
@ -152,6 +153,7 @@ public abstract class AbstractPluralAttributeSourceImpl
.getManyToMany().getClazz());
return new ManyToManyPluralAttributeElementSourceImpl(
sourceMappingDocument(),
this,
pluralAttributeElement.getManyToMany(),
pluralAttributeElement.getCascade()
);

View File

@ -24,7 +24,9 @@
package org.hibernate.metamodel.internal.source.hbm;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.engine.FetchStyle;
@ -36,7 +38,10 @@ import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.AttributeSourceResolutionContext;
import org.hibernate.metamodel.spi.source.HibernateTypeSource;
import org.hibernate.metamodel.spi.source.MappedByAssociationSource;
import org.hibernate.metamodel.spi.source.MappingException;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
@ -46,6 +51,7 @@ import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSourceNode implements ToOneAttributeSource{
private final SingularAttributeBinding.NaturalIdMutability naturalIdMutability;
private final String propertyRef;
private final Set<MappedByAssociationSource> ownedAssociationSources = new HashSet<MappedByAssociationSource>( );
AbstractToOneAttributeSourceImpl(
MappingDocument sourceMappingDocument,
@ -201,6 +207,32 @@ public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSource
}
@Override
public Set<MappedByAssociationSource> getOwnedAssociationSources() {
return ownedAssociationSources;
}
@Override
public void addMappedByAssociationSource(MappedByAssociationSource attributeSource) {
ownedAssociationSources.add( attributeSource );
}
@Override
public boolean isMappedBy() {
// only applies to annotations
return false;
}
@Override
public AttributeSource getAttributeSource() {
return this;
}
@Override
public void resolveToOneAttributeSource(AttributeSourceResolutionContext context) {
// nothing to do
}
@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
return propertyRef == null
@ -221,7 +253,7 @@ public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSource
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
return context.resolveRelationalValuesForAttribute( propertyRef );
}

View File

@ -100,7 +100,7 @@ public class JoinedSubclassEntitySourceImpl extends SubclassEntitySourceImpl imp
? null
: new JoinColumnResolutionDelegate() {
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
return context.resolveRelationalValuesForAttribute( key.getPropertyRef() );
}

View File

@ -32,6 +32,7 @@ import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jaxb.spi.hbm.JaxbColumnElement;
import org.hibernate.jaxb.spi.hbm.JaxbKeyManyToOneElement;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.source.AttributeSourceResolutionContext;
import org.hibernate.metamodel.spi.source.MetaAttributeSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
@ -116,11 +117,6 @@ class KeyManyToOneSourceImpl
return Nature.MANY_TO_ONE;
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context) {
return getNature();
}
@Override
public boolean isVirtualAttribute() {
return false;

View File

@ -23,8 +23,6 @@
*/
package org.hibernate.metamodel.internal.source.hbm;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.hibernate.engine.FetchTiming;
@ -38,6 +36,7 @@ import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.FilterSource;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.MappingException;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
/**
@ -45,7 +44,7 @@ import org.hibernate.metamodel.spi.source.RelationalValueSource;
* @author Gail Badner
*/
public class ManyToManyPluralAttributeElementSourceImpl
extends AbstractHbmSourceNode
extends AbstractPluralAssociationElementSourceImpl
implements ManyToManyPluralAttributeElementSource {
private final JaxbManyToManyElement manyToManyElement;
private final Iterable<CascadeStyle> cascadeStyles;
@ -54,9 +53,10 @@ public class ManyToManyPluralAttributeElementSourceImpl
private final FilterSource[] filterSources;
public ManyToManyPluralAttributeElementSourceImpl(
MappingDocument mappingDocument,
final PluralAttributeSource pluralAttributeSource,
final JaxbManyToManyElement manyToManyElement,
String cascadeString) {
super( mappingDocument );
super( mappingDocument, pluralAttributeSource );
this.manyToManyElement = manyToManyElement;
this.cascadeStyles = Helper.interpretCascadeStyles( cascadeString, bindingContext() );
@ -133,12 +133,6 @@ public class ManyToManyPluralAttributeElementSourceImpl
return manyToManyElement.getPropertyRef();
}
@Override
// used by JPA instead of referenced entity attribute
public Collection<String> getReferencedColumnNames() {
return Collections.emptyList();
}
@Override
public List<RelationalValueSource> relationalValueSources() {
return valueSources;
@ -248,7 +242,7 @@ public class ManyToManyPluralAttributeElementSourceImpl
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
return context.resolveRelationalValuesForAttribute( manyToManyElement.getPropertyRef() );
}

View File

@ -148,11 +148,6 @@ class ManyToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl {
return Nature.MANY_TO_ONE;
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context) {
return getNature();
}
@Override
public boolean areValuesIncludedInInsertByDefault() {
return manyToOneElement.isInsert();

View File

@ -27,21 +27,23 @@ import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jaxb.spi.hbm.JaxbOneToManyElement;
import org.hibernate.metamodel.spi.source.OneToManyPluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
/**
* @author Steve Ebersole
*/
public class OneToManyPluralAttributeElementSourceImpl
extends AbstractHbmSourceNode
extends AbstractPluralAssociationElementSourceImpl
implements OneToManyPluralAttributeElementSource {
private final JaxbOneToManyElement oneToManyElement;
private final Iterable<CascadeStyle> cascadeStyles;
public OneToManyPluralAttributeElementSourceImpl(
MappingDocument mappingDocument,
final PluralAttributeSource pluralAttributeSource,
final JaxbOneToManyElement oneToManyElement,
String cascadeString) {
super( mappingDocument );
super( mappingDocument, pluralAttributeSource );
this.oneToManyElement = oneToManyElement;
this.cascadeStyles = Helper.interpretCascadeStyles( cascadeString, bindingContext() );
}

View File

@ -29,6 +29,7 @@ import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.jaxb.spi.hbm.JaxbColumnElement;
import org.hibernate.jaxb.spi.hbm.JaxbOneToOneElement;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.source.AttributeSourceResolutionContext;
import org.hibernate.metamodel.spi.source.MetaAttributeSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.type.ForeignKeyDirection;
@ -134,11 +135,6 @@ class OneToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl {
return Nature.ONE_TO_ONE;
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context) {
return getNature();
}
@Override
public boolean isVirtualAttribute() {
return false;

View File

@ -93,7 +93,7 @@ public class PluralAttributeKeySourceImpl
? null
: new JoinColumnResolutionDelegate() {
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
return context.resolveRelationalValuesForAttribute( keyElement.getPropertyRef() );
}

View File

@ -176,7 +176,7 @@ class SecondaryTableSourceImpl extends AbstractHbmSourceNode implements Secondar
}
@Override
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context) {
return context.resolveRelationalValuesForAttribute( getReferencedAttributeName() );
}

View File

@ -23,13 +23,13 @@
*/
package org.hibernate.metamodel.spi.binding;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.spi.domain.PluralAttribute;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
@ -46,25 +46,36 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind
}
@Override
public AttributeBinding locateAttributeBinding(List<Value> values) {
public SingularAttributeBinding locateAttributeBinding(TableSpecification table, List<? extends Value> values) {
for ( AttributeBinding attributeBinding : attributeBindingMapInternal().values() ) {
if ( !attributeBinding.getAttribute().isSingular() ) {
continue;
}
SingularAttributeBinding basicAttributeBinding = (SingularAttributeBinding) attributeBinding;
List<org.hibernate.metamodel.spi.relational.Value> attributeValues = new ArrayList<Value>();
for ( RelationalValueBinding relationalBinding : basicAttributeBinding.getRelationalValueBindings() ) {
attributeValues.add( relationalBinding.getValue() );
}
if ( attributeValues.equals( values ) ) {
return attributeBinding;
SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding;
if ( hasEqualValues( table, values, singularAttributeBinding.getRelationalValueBindings() ) ) {
return singularAttributeBinding;
}
}
return null;
}
private static boolean hasEqualValues(
TableSpecification table,
List<? extends Value> values,
List<RelationalValueBinding> relationalValueBindings) {
if ( values.size() != relationalValueBindings.size() ) {
return false;
}
for ( int i = 0 ; i < values.size() ; i++ ) {
final RelationalValueBinding relationalValueBinding = relationalValueBindings.get( i );
if ( !table.equals( relationalValueBinding.getTable() ) ||
!values.get( i ).equals( relationalValueBinding.getValue() ) ) {
return false;
}
}
return true;
}
@Override
public Class<?> getClassReference() {
return getAttributeContainer().getClassReference();
@ -153,8 +164,7 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
boolean isConstrained,
List<RelationalValueBinding> valueBindings) {
boolean isConstrained) {
final OneToOneAttributeBinding binding = new OneToOneAttributeBinding(
this,
attribute,
@ -165,8 +175,7 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind
metaAttributeContext,
referencedEntityBinding,
referencedAttributeBinding,
isConstrained,
valueBindings
isConstrained
);
registerAttributeBinding( binding );
return binding;
@ -182,8 +191,7 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind
SingularAttributeBinding.NaturalIdMutability naturalIdMutability,
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
List<RelationalValueBinding> valueBindings) {
SingularAttributeBinding referencedAttributeBinding) {
final ManyToOneAttributeBinding binding = new ManyToOneAttributeBinding(
this,
attribute,
@ -194,8 +202,7 @@ public abstract class AbstractAttributeBindingContainer implements AttributeBind
naturalIdMutability,
metaAttributeContext,
referencedEntityBinding,
referencedAttributeBinding,
valueBindings
referencedAttributeBinding
);
registerAttributeBinding( binding );
return binding;

View File

@ -163,8 +163,7 @@ public abstract class AbstractCompositeAttributeBindingContainer
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
boolean isConstrained,
List<RelationalValueBinding> valueBindings) {
boolean isConstrained) {
if ( !isModifiable() ) {
throw new UnsupportedOperationException( "Attribute bindings are read-only and cannot be modified." );
}
@ -177,8 +176,7 @@ public abstract class AbstractCompositeAttributeBindingContainer
metaAttributeContext,
referencedEntityBinding,
referencedAttributeBinding,
isConstrained,
valueBindings
isConstrained
);
}
@ -192,8 +190,7 @@ public abstract class AbstractCompositeAttributeBindingContainer
SingularAttributeBinding.NaturalIdMutability naturalIdMutability,
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
List<RelationalValueBinding> valueBindings) {
SingularAttributeBinding referencedAttributeBinding) {
if ( !isModifiable() ) {
throw new UnsupportedOperationException( "Attribute bindings are read-only and cannot be modified." );
}
@ -206,8 +203,7 @@ public abstract class AbstractCompositeAttributeBindingContainer
naturalIdMutability,
metaAttributeContext,
referencedEntityBinding,
referencedAttributeBinding,
valueBindings
referencedAttributeBinding
);
}

View File

@ -31,6 +31,9 @@ import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
/**
@ -38,9 +41,9 @@ import org.hibernate.metamodel.spi.source.MetaAttributeContext;
*/
public abstract class AbstractSingularAssociationAttributeBinding extends AbstractSingularAttributeBinding
implements SingularAssociationAttributeBinding {
protected final EntityBinding referencedEntityBinding;
protected final SingularAttributeBinding referencedAttributeBinding;
protected final RelationalValueBindingContainer relationalValueBindingContainer;
private final EntityBinding referencedEntityBinding;
private final SingularAttributeBinding referencedAttributeBinding;
private JoinRelationalValueBindingContainer relationalValueBindingContainer;
private CascadeStyle cascadeStyle;
private FetchTiming fetchTiming;
private FetchStyle fetchStyle;
@ -57,7 +60,6 @@ public abstract class AbstractSingularAssociationAttributeBinding extends Abstra
NaturalIdMutability naturalIdMutability,
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
List<RelationalValueBinding> relationalValueBindings,
SingularAttributeBinding referencedAttributeBinding) {
super(
container,
@ -75,7 +77,6 @@ public abstract class AbstractSingularAssociationAttributeBinding extends Abstra
throw new IllegalArgumentException( "referencedAttributeBinding must be non-null." );
}
this.referencedEntityBinding = referencedEntityBinding;
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
this.referencedAttributeBinding = referencedAttributeBinding;
this.isNotFoundAnException = isNotFoundAnException;
}
@ -153,6 +154,28 @@ public abstract class AbstractSingularAssociationAttributeBinding extends Abstra
return referencedAttributeBinding;
}
public void setJoinRelationalValueBindings(
List<RelationalValueBinding> relationalValueBindings,
ForeignKey foreignKey) {
this.relationalValueBindingContainer =
new JoinRelationalValueBindingContainer( relationalValueBindings, foreignKey );
}
@Override
public TableSpecification getTable() {
return relationalValueBindingContainer.getTable();
}
@Override
public ForeignKey getForeignKey() {
return relationalValueBindingContainer.getForeignKey();
}
@Override
public List<Value> getValues() {
return getRelationalValueBindingContainer().values();
}
@Override
protected RelationalValueBindingContainer getRelationalValueBindingContainer() {
return relationalValueBindingContainer;

View File

@ -27,6 +27,7 @@ import java.util.List;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
/**
@ -59,6 +60,11 @@ public abstract class AbstractSingularAttributeBinding
return getRelationalValueBindingContainer().relationalValueBindings();
}
@Override
public List<Value> getValues() {
return getRelationalValueBindingContainer().values();
}
@Override
public boolean hasDerivedValue() {
return getRelationalValueBindingContainer().hasDerivedValue();

View File

@ -89,11 +89,12 @@ public interface AttributeBindingContainer {
/**
* Locate a specific attribute binding, by its values.
*
* @param table The table containing the values
* @param values The list of values
*
* @return The attribute binding or {@code null} if none could be found.
*/
AttributeBinding locateAttributeBinding(List<Value> values);
SingularAttributeBinding locateAttributeBinding(TableSpecification table, List<? extends Value> values);
/**
* Seeks out the entity binding that is the root of this component path.
@ -192,8 +193,7 @@ public interface AttributeBindingContainer {
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
boolean isConstrained,
List<RelationalValueBinding> valueBindings);
boolean isConstrained);
/**
@ -207,7 +207,6 @@ public interface AttributeBindingContainer {
* @param metaAttributeContext
* @param referencedEntityBinding
* @param referencedAttributeBinding
* @param valueBindings
*
* @return The attribute binding instance.
*/
@ -220,8 +219,7 @@ public interface AttributeBindingContainer {
SingularAttributeBinding.NaturalIdMutability naturalIdMutability,
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
List<RelationalValueBinding> valueBindings);
SingularAttributeBinding referencedAttributeBinding);
/**
* Factory method for bag attribute bindings.

View File

@ -25,12 +25,14 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.AssertionFailure;
/**
*
*/
public class BasicPluralAttributeIndexBinding extends AbstractPluralAttributeIndexBinding {
private List<RelationalValueBinding> relationalValueBindings;
private RelationalValueBindingContainer relationalValueBindingContainer;
public BasicPluralAttributeIndexBinding(
IndexedPluralAttributeBinding pluralAttributeBinding) {
@ -39,11 +41,18 @@ public class BasicPluralAttributeIndexBinding extends AbstractPluralAttributeInd
@Override
public List<RelationalValueBinding> getRelationalValueBindings() {
return relationalValueBindings;
return relationalValueBindingContainer.relationalValueBindings();
}
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
this.relationalValueBindings = relationalValueBindings;
if ( relationalValueBindings == null || relationalValueBindings.isEmpty() ) {
throw new AssertionFailure( "relationalValueBindings argument must be non-null and non-empty." );
}
if ( this.relationalValueBindingContainer != null ) {
throw new AssertionFailure( "Relational value bindings have already initialized" );
}
this.relationalValueBindingContainer =
new RelationalValueBindingContainer( relationalValueBindings );
}
@Override

View File

@ -29,6 +29,11 @@ import org.hibernate.engine.spi.CascadeStyle;
* @author Steve Ebersole
*/
public interface Cascadeable {
/**
* Obtain the cascade style to be applied to this association.
*
* @return The cascade style.
*/
public CascadeStyle getCascadeStyle();
public void setCascadeStyle(CascadeStyle cascadeStyle);

View File

@ -346,8 +346,10 @@ public class CompositeAttributeBinding
}
@Override
public AttributeBinding locateAttributeBinding(List<Value> values) {
return compositeAttributeBindingContainer.locateAttributeBinding( values );
public SingularAttributeBinding locateAttributeBinding(
TableSpecification table,
List<? extends Value> values) {
return compositeAttributeBindingContainer.locateAttributeBinding( table, values );
}
@Override
@ -419,8 +421,7 @@ public class CompositeAttributeBinding
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
boolean isConstrained,
List<RelationalValueBinding> valueBindings) {
boolean isConstrained) {
return compositeAttributeBindingContainer.makeOneToOneAttributeBinding(
attribute,
propertyAccessorName,
@ -430,8 +431,7 @@ public class CompositeAttributeBinding
metaAttributeContext,
referencedEntityBinding,
referencedAttributeBinding,
isConstrained,
valueBindings
isConstrained
);
}
@ -445,8 +445,7 @@ public class CompositeAttributeBinding
NaturalIdMutability naturalIdMutability,
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
List<RelationalValueBinding> valueBindings) {
SingularAttributeBinding referencedAttributeBinding) {
return compositeAttributeBindingContainer.makeManyToOneAttributeBinding(
attribute,
propertyAccessorName,
@ -456,8 +455,7 @@ public class CompositeAttributeBinding
naturalIdMutability,
metaAttributeContext,
referencedEntityBinding,
referencedAttributeBinding,
valueBindings
referencedAttributeBinding
);
}

View File

@ -131,6 +131,8 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
public EntityBinding(EntityBinding superEntityBinding) {
this.superEntityBinding = superEntityBinding;
this.superEntityBinding.subEntityBindings.add( this );
// TODO: the ID attribute binding needs to be recreated for this EntityBinding
// otherwise, this != hierarchyDetails.getEntityIdentifier().getAttributeBinding().getContainer()
this.hierarchyDetails = superEntityBinding.getHierarchyDetails();
this.subEntityBindingId = superEntityBinding.nextSubEntityBindingId();
}
@ -216,14 +218,22 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
}
}
public AttributeBinding locateAttributeBinding(List<Value> values, boolean searchParent) {
AttributeBinding attributeBinding = locateAttributeBinding( values );
public SingularAttributeBinding locateAttributeBinding(
TableSpecification table,
List<? extends Value> values,
boolean searchParent) {
SingularAttributeBinding attributeBinding = null;
SingularAttributeBinding idAttributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding();
if ( primaryTable.equals( table ) && idAttributeBinding.getValues().equals( values ) ) {
attributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding();
}
if ( attributeBinding == null ) {
attributeBinding = locateAttributeBinding( table, values );
}
if ( attributeBinding == null && searchParent && getSuperEntityBinding() != null ) {
return getSuperEntityBinding().locateAttributeBinding( values, searchParent );
}
else {
return attributeBinding;
attributeBinding = getSuperEntityBinding().locateAttributeBinding( table, values, searchParent );
}
return attributeBinding;
}
public AttributeBinding locateAttributeBindingByPath(String path, boolean searchParent) {

View File

@ -0,0 +1,80 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
/**
* @author Gail Badner
*/
public class JoinRelationalValueBindingContainer extends RelationalValueBindingContainer {
private final TableSpecification table;
private final ForeignKey foreignKey;
public JoinRelationalValueBindingContainer(
List<RelationalValueBinding> relationalValueBindings,
ForeignKey foreignKey) {
super( relationalValueBindings );
if ( relationalValueBindings.isEmpty() ) {
table = null;
}
else {
table = relationalValueBindings.get( 0 ).getTable();
for ( int i = 1; i< relationalValueBindings.size(); i++ ) {
if ( !table.equals( relationalValueBindings.get( i ).getTable() ) ) {
throw new AssertionFailure(
String.format(
"Multiple tables found in a %s: %s, %s",
getClass().getName(),
table.getLogicalName(),
relationalValueBindings.get( i ).getTable()
)
);
}
}
}
if ( table != null && foreignKey != null && !table.equals( foreignKey.getSourceTable() ) ) {
throw new IllegalStateException(
String.format(
"Unexpected source table for foreign key: %s; expected %s.",
foreignKey.getSourceTable(),
table
)
);
}
this.foreignKey = foreignKey;
}
public TableSpecification getTable() {
return table;
}
public ForeignKey getForeignKey() {
return foreignKey;
}
}

View File

@ -28,6 +28,7 @@ import java.util.List;
import org.hibernate.FetchMode;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.metamodel.spi.relational.ForeignKey;
/**
* Describes plural attributes of {@link org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding.Nature#MANY_TO_MANY} elements
@ -40,8 +41,7 @@ public class ManyToManyPluralAttributeElementBinding extends AbstractPluralAttri
private String manyToManyWhere;
private String manyToManyOrderBy;
private FetchMode fetchMode;
// TODO: really should have value defined (which defines table), but may not know
private RelationalValueBindingContainer relationalValueBindingContainer;
private JoinRelationalValueBindingContainer relationalValueBindingContainer;
ManyToManyPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) {
super( binding );
@ -57,8 +57,17 @@ public class ManyToManyPluralAttributeElementBinding extends AbstractPluralAttri
return Nature.MANY_TO_MANY;
}
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
public void setJoinRelationalValueBindings(
List<RelationalValueBinding> relationalValueBindings,
ForeignKey foreignKey) {
this.relationalValueBindingContainer = new JoinRelationalValueBindingContainer(
relationalValueBindings,
foreignKey
);
}
public ForeignKey getForeignKey() {
return relationalValueBindingContainer.getForeignKey();
}
public String getManyToManyWhere() {

View File

@ -47,8 +47,7 @@ public class ManyToOneAttributeBinding
NaturalIdMutability naturalIdMutability,
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
List<RelationalValueBinding> relationalValueBindings) {
SingularAttributeBinding referencedAttributeBinding) {
super(
container,
attribute,
@ -58,7 +57,8 @@ public class ManyToOneAttributeBinding
isNotFoundAnException,
naturalIdMutability,
metaAttributeContext,
referencedEntityBinding, relationalValueBindings, referencedAttributeBinding
referencedEntityBinding,
referencedAttributeBinding
);
}
}

View File

@ -47,8 +47,7 @@ public class OneToOneAttributeBinding
MetaAttributeContext metaAttributeContext,
EntityBinding referencedEntityBinding,
SingularAttributeBinding referencedAttributeBinding,
boolean isConstrained,
List<RelationalValueBinding> valueBindings) {
boolean isConstrained) {
super(
container,
attribute,
@ -59,7 +58,6 @@ public class OneToOneAttributeBinding
naturalIdMutability,
metaAttributeContext,
referencedEntityBinding,
valueBindings,
referencedAttributeBinding
);
this.isConstrained = isConstrained;

View File

@ -27,18 +27,20 @@ import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
/**
* Describes the binding information pertaining to the plural attribute foreign key.
*
* @author Steve Ebersole
* @author Gail Badner
*/
public class PluralAttributeKeyBinding {
private final AbstractPluralAttributeBinding pluralAttributeBinding;
private final SingularAttributeBinding referencedAttributeBinding;
private RelationalValueBindingContainer relationalValueBindingContainer;
private boolean isCascadeDeleteEnabled;
private JoinRelationalValueBindingContainer relationalValueBindingContainer;
private boolean inverse;
// this knowledge can be implicitly resolved based on the typing information on the referenced owner attribute
@ -70,8 +72,7 @@ public class PluralAttributeKeyBinding {
}
public TableSpecification getCollectionTable() {
// TODO: get table directly from relationalValueBindingContainer
return relationalValueBindingContainer.relationalValueBindings().get( 0 ).getTable();
return relationalValueBindingContainer.getTable();
}
/**
@ -101,14 +102,25 @@ public class PluralAttributeKeyBinding {
return relationalValueBindingContainer.relationalValueBindings();
}
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
public List<Value> getValues() {
return relationalValueBindingContainer.values();
}
public ForeignKey getForeignKey() {
return relationalValueBindingContainer.getForeignKey();
}
public void setJoinRelationalValueBindings(
List<RelationalValueBinding> relationalValueBindings,
ForeignKey foreignKey) {
if ( relationalValueBindings == null || relationalValueBindings.isEmpty() ) {
throw new AssertionFailure( "relationalValueBindings argument must be non-null and non-empty." );
}
if ( this.relationalValueBindingContainer != null ) {
throw new AssertionFailure( "Relational value bindings have already initialized" );
}
this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings );
this.relationalValueBindingContainer = new JoinRelationalValueBindingContainer(
relationalValueBindings,
foreignKey
);
if ( this.relationalValueBindingContainer.hasDerivedValue() ) {
throw new NotYetImplementedException(
"Derived values are not supported when creating a foreign key that targets columns."
@ -117,11 +129,7 @@ public class PluralAttributeKeyBinding {
}
public boolean isCascadeDeleteEnabled() {
return isCascadeDeleteEnabled;
}
public void setCascadeDeleteEnabled(boolean isCascadeDeleteEnabled) {
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
return relationalValueBindingContainer.getForeignKey().getDeleteRule() == ForeignKey.ReferentialAction.CASCADE;
}
public boolean isNullable() {

View File

@ -23,6 +23,9 @@
*/
package org.hibernate.metamodel.spi.binding;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
/**
* Contract describing the attribute binding for singular associations ({@code many-to-one}, {@code one-to-one}).
*
@ -43,4 +46,8 @@ public interface SingularAssociationAttributeBinding extends SingularAttributeBi
public SingularAttributeBinding getReferencedAttributeBinding();
public boolean isNotFoundAnException();
public TableSpecification getTable();
public ForeignKey getForeignKey();
}

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.Value;
/**
* Specialized binding contract for singular (non-collection) attributes
@ -39,6 +40,7 @@ public interface SingularAttributeBinding extends AttributeBinding {
public List<RelationalValueBinding> getRelationalValueBindings();
public List<Value> getValues();
/**
* Convenience method to determine if any {@link RelationalValueBinding simple value bindings} are derived values
* (formula mappings).

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.source;
/**
+ * @author Gail Badner
+ */
public interface AssociationPluralAttributeElementSource extends PluralAttributeElementSource, AssociationSource {
}

View File

@ -0,0 +1,58 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.source;
import java.util.Set;
/**
* @author Gail Badner
*/
public interface AssociationSource extends CascadeStyleSource {
public AttributeSource getAttributeSource();
/**
* Obtain the name of the referenced entity.
*
* @return The name of the referenced entity
*/
public String getReferencedEntityName();
public boolean isNotFoundAnException();
/**
* Returns the attribute source that is owned by this {@link AssociationSource},
* if there is one.
* <p/>
* Specifically, this method returns the {@link AttributeSource} that is
* "mappedBy" this {@link AssociationSource}.
*
* @return
*/
public Set<MappedByAssociationSource> getOwnedAssociationSources();
public void addMappedByAssociationSource(MappedByAssociationSource attributeSource);
public boolean isMappedBy();
}

View File

@ -23,6 +23,10 @@
*/
package org.hibernate.metamodel.spi.source;
import java.util.List;
import org.hibernate.metamodel.spi.relational.Column;
/**
*
* @author Gail Badner
@ -30,4 +34,5 @@ package org.hibernate.metamodel.spi.source;
public interface AttributeSourceResolutionContext {
public IdentifierSource resolveIdentifierSource(String entityName);
public AttributeSource resolveAttributeSource(String entityName, String attributeName);
public List<Column> resolveIdentifierColumns();
}

View File

@ -66,7 +66,7 @@ public interface ForeignKeyContributingSource {
*
* @return The resolved target columns.
*/
public List<Value> getJoinColumns(JoinColumnResolutionContext context);
public List<? extends Value> getJoinColumns(JoinColumnResolutionContext context);
public TableSpecification getReferencedTable(JoinColumnResolutionContext context);
@ -90,7 +90,7 @@ public interface ForeignKeyContributingSource {
*
* @return The corresponding referenced columns
*/
public List<Value> resolveRelationalValuesForAttribute(String attributeName);
public List<? extends Value> resolveRelationalValuesForAttribute(String attributeName);
public TableSpecification resolveTableForAttribute(String attributeName);

View File

@ -27,5 +27,5 @@ package org.hibernate.metamodel.spi.source;
* @author Steve Ebersole
*/
public interface ManyToAnyPluralAttributeElementSource
extends PluralAttributeElementSource, CascadeStyleSource {
extends PluralAttributeElementSource, AssociationSource {
}

View File

@ -31,13 +31,11 @@ import org.hibernate.engine.FetchTiming;
* @author Steve Ebersole
*/
public interface ManyToManyPluralAttributeElementSource
extends PluralAttributeElementSource, CascadeStyleSource, RelationalValueSourceContainer, ForeignKeyContributingSource, Orderable {
extends PluralAttributeElementSource, AssociationSource, RelationalValueSourceContainer, ForeignKeyContributingSource, Orderable {
public String getReferencedEntityName();
public String getReferencedEntityAttributeName();
public Collection<String> getReferencedColumnNames();
public boolean isNotFoundAnException();
public String getExplicitForeignKeyName();

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -23,32 +23,10 @@
*/
package org.hibernate.metamodel.spi.source;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
/**
* Contract describing sources for attributes which model associations.
*
* @author Steve Ebersole
* @author Gail Badner
*/
public interface AssociationAttributeSource extends AttributeSource {
/**
* Obtain the cascade styles to be applied to this association.
*
* @return The cascade styles.
*/
public Iterable<CascadeStyle> getCascadeStyles();
public interface MappedByAssociationSource extends AssociationSource {
/**
* Obtain the fetch mode to be applied to this association.
*
* @return The fetch mode.
*/
public FetchMode getFetchMode();
public FetchTiming getFetchTiming();
public FetchStyle getFetchStyle();
String getMappedBy();
}

View File

@ -26,7 +26,7 @@ package org.hibernate.metamodel.spi.source;
/**
* @author Steve Ebersole
*/
public interface OneToManyPluralAttributeElementSource extends PluralAttributeElementSource, CascadeStyleSource {
public interface OneToManyPluralAttributeElementSource extends PluralAttributeElementSource, AssociationSource {
public String getReferencedEntityName();
public boolean isNotFoundAnException();

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel.spi.source;
/**
* @author Steve Ebersole
* @author Gail Badner
*/
public interface PluralAttributeElementSource {
public Nature getNature();
@ -35,10 +36,20 @@ public interface PluralAttributeElementSource {
* @author Steve Ebersole
*/
enum Nature {
BASIC,
AGGREGATE,
ONE_TO_MANY,
MANY_TO_MANY,
MANY_TO_ANY
BASIC( false ),
AGGREGATE( false ),
ONE_TO_MANY( true ),
MANY_TO_MANY( true ),
MANY_TO_ANY( true );
private final boolean isAssociation;
private Nature(boolean isAssociation) {
this.isAssociation = isAssociation;
}
public boolean isAssociation() {
return isAssociation;
}
}
}

View File

@ -35,16 +35,13 @@ import org.hibernate.type.ForeignKeyDirection;
* @author Steve Ebersole
*/
public interface ToOneAttributeSource
extends SingularAttributeSource, ToOneAttributeSourceNatureResolver, ForeignKeyContributingSource, FetchableAttributeSource, CascadeStyleSource {
extends SingularAttributeSource,
ToOneAttributeSourceNatureResolver,
ForeignKeyContributingSource,
FetchableAttributeSource,
AssociationSource {
/**
* Obtain the name of the referenced entity.
*
* @return The name of the referenced entity
*/
public String getReferencedEntityName();
public boolean isUnique();
public boolean isNotFoundAnException();
public boolean isUnWrapProxy();
ForeignKeyDirection getForeignKeyDirection();
public List<Binder.DefaultNamingStrategy> getDefaultNamingStrategies(final String entityName, final String tableName, final AttributeBinding referencedAttributeBinding);

View File

@ -33,10 +33,14 @@ import org.hibernate.metamodel.spi.relational.Column;
*/
public interface ToOneAttributeSourceNatureResolver {
SingularAttributeSource.Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context);
public static interface ToOneAttributeSourceNatureResolutionContext {
boolean areIdentifierColumnsDefined();
List<org.hibernate.metamodel.spi.relational.Column> getIdentifierColumns();
}
/**
* Perform any steps to completely resolve this attribute source.
*
* If this is a {@link MappedByAssociationSource}, resolution must
* resolve the association owner, and this association must be added
* to the owner's "owned" associations.
*
* @param context
*/
void resolveToOneAttributeSource(AttributeSourceResolutionContext context);
}

View File

@ -844,14 +844,14 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
//#3
System.arraycopy(
naturalOrderTableNames,
tableSpan - coreTableSpan,
coreTableSpan,
naturalOrderSubclassTableNameClosure,
coreTableSpan + subclassSpan,
secondaryTableSpan
);
System.arraycopy(
naturalOrderTableKeyColumns,
tableSpan - coreTableSpan,
coreTableSpan,
naturalOrderSubclassTableKeyColumnClosure,
coreTableSpan + subclassSpan,
secondaryTableSpan
@ -929,7 +929,16 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
else {
valueBindings = Collections.EMPTY_LIST;
}
TableSpecification table = attributeBinding.getContainer().seekEntityBinding().getPrimaryTable();// valueBinding.getValue().getTable();
final TableSpecification table;
if ( valueBindings.isEmpty() ) {
table = attributeBinding.getContainer().seekEntityBinding().getPrimaryTable();
}
else {
// TODO: Can relational value bindings for an attribute binding be in more than one table?
// For now, just get the table from the first one.
table = valueBindings.get( 0 ).getTable();
}
final String tableName = table.getQualifiedName( factory.getDialect() );
if ( i < hydrateSpan ) {
propertyTableNumbers[i] = getTableId( tableName, tableNames );

View File

@ -28,6 +28,7 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import java.util.List;
import java.util.Set;
import javax.persistence.CollectionTable;
@ -108,7 +109,8 @@ public class UniqueConstraintBindingTest extends BaseAnnotationBindingTestCase {
@ElementCollection
@CollectionTable(name = "CollectionTable", joinColumns = @JoinColumn(name = "element"), uniqueConstraints = @UniqueConstraint(columnNames = "element", name = "u4"))
@OrderColumn(name = "element_index")
public int[] elements;
public List<Integer> elements;
// TODO: int[] is not completely supported using the new metamodel yet, so I changed int[] to List<Integer>
}
@Entity

View File

@ -30,7 +30,6 @@ import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.internal.MetadataImpl;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.source.MappingException;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import static junit.framework.Assert.assertNotNull;

View File

@ -48,7 +48,6 @@ import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.type.BagType;
import org.hibernate.type.CollectionType;

View File

@ -30,7 +30,6 @@ import org.junit.Test;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.fail;

View File

@ -27,7 +27,6 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;

View File

@ -27,7 +27,6 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;

View File

@ -57,7 +57,6 @@ import org.junit.Test;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel( message = "@OneToOne with mappedBy specified is not supported yet" )
public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
@Override
protected boolean isCleanupTestDataRequired() {
@ -103,6 +102,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
@Test
@RequiresDialectFeature( DialectChecks.SupportsExpectedLobUsagePattern.class )
@FailureExpectedWithNewMetamodel
public void testVersioning() throws Exception {
Forest forest = new Forest();
forest.setName( "Fontainebleau" );
@ -329,6 +329,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
}
@Test
@FailureExpectedWithNewMetamodel
public void testCascadedDeleteOfChildEntitiesBug2() {
// Relationship is one SoccerTeam to many Players.
// Create a SoccerTeam (parent) and three Players (child).
@ -379,6 +380,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
}
@Test
@FailureExpectedWithNewMetamodel
public void testCascadedDeleteOfChildOneToOne() {
// create two single player teams (for one versus one match of soccer)
// and associate teams with players via the special OneVOne methods.
@ -465,6 +467,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
* defined on a parent MappedSuperclass(s)
*/
@Test
@FailureExpectedWithNewMetamodel
public void testInheritFiltersFromMappedSuperclass() throws Exception {
Session s;
Transaction tx;
@ -670,7 +673,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
}
catch( AnnotationException ex ) {
assertEquals(
"Either name or defaultForType (or both) attribute should be set in TypeDefinition having typeClass org.hibernate.test.annotations.entity.PhoneNumberType",
"Either name or defaultForType (or both) must be set on TypeDefinition [org.hibernate.test.annotations.entity.PhoneNumberType]",
ex.getMessage());
} finally {
if( sf != null){

View File

@ -26,7 +26,6 @@ package org.hibernate.test.annotations.enumerated.mapkey;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**

View File

@ -31,7 +31,6 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@ -44,7 +43,6 @@ import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class JoinedSubclassTest extends BaseCoreFunctionalTestCase {
@Test
public void testDefault() throws Exception {

View File

@ -27,7 +27,6 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -36,7 +35,6 @@ import static org.junit.Assert.assertNotNull;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class ManyToOneJoinTest extends BaseCoreFunctionalTestCase {
@Test
public void testManyToOneJoinTable() throws Exception {

View File

@ -33,7 +33,6 @@ import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Assert;
@ -42,7 +41,6 @@ import org.junit.Test;
/**
* @author Guenther Demetz
*/
@FailureExpectedWithNewMetamodel( message = "@OneToOne with mappedBy specified is not supported yet" )
public class ImmutableNaturalKeyLookupTest extends BaseCoreFunctionalTestCase {
@TestForIssue(jiraKey = "HHH-4838")

View File

@ -51,7 +51,7 @@ import static org.junit.Assert.assertTrue;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
@FailureExpectedWithNewMetamodel (message = "@Embeddable not detected on class used for @EmbeddedId" )
public class OneToOneTest extends BaseCoreFunctionalTestCase {
@Test
public void testEagerFetching() throws Exception {

View File

@ -41,11 +41,11 @@ import static org.junit.Assert.fail;
* @author Emmanuel Bernard
* @author Gail Badner
*/
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class OptionalOneToOneMappedByTest extends BaseCoreFunctionalTestCase {
// @OneToOne(mappedBy="address") with foreign generator
@Test
@FailureExpectedWithNewMetamodel ( message = "mappedBy @OneToOne with foreign generator" )
public void testBidirForeignIdGenerator() {
Session s = openSession();
Transaction tx = s.beginTransaction();

View File

@ -29,7 +29,6 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@ -42,7 +41,6 @@ import static org.junit.Assert.fail;
* @author Emmanuel Bernard
* @author Gail Badner
*/
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class OptionalOneToOnePKJCTest extends BaseCoreFunctionalTestCase {
@Test

View File

@ -2,6 +2,7 @@
package org.hibernate.test.annotations.onetoone;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
@ -28,7 +29,7 @@ public class SerialNumber {
return id.hashCode();
}
@Id
@EmbeddedId
public SerialNumberPk getId() {
return id;
}

View File

@ -40,7 +40,6 @@ import org.junit.Test;
* @author Emmanuel Bernard
*/
@TestForIssue( jiraKey = "HHH-4851" )
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class HHH4851Test extends BaseCoreFunctionalTestCase {
@Test
public void testHHH4851() throws Exception {