HHH-7436 : Add support for many-to-many associations to new metamodel

This commit is contained in:
Gail Badner 2013-02-19 11:44:42 -08:00
parent 5a993dd903
commit 9d404168aa
9 changed files with 164 additions and 17 deletions

View File

@ -136,6 +136,7 @@ import org.hibernate.metamodel.spi.source.IdentifierSource;
import org.hibernate.metamodel.spi.source.InLineViewSource;
import org.hibernate.metamodel.spi.source.IndexedPluralAttributeSource;
import org.hibernate.metamodel.spi.source.JoinedSubclassEntitySource;
import org.hibernate.metamodel.spi.source.PluralAttributeElementSourceResolver;
import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.ManyToManyPluralAttributeElementSource;
@ -1391,6 +1392,16 @@ public class Binder {
final AttributeBindingContainer attributeBindingContainer,
final PluralAttributeSource attributeSource) {
final PluralAttributeSource.Nature nature = attributeSource.getNature();
if ( attributeSource.getMappedBy() != null ) {
attributeSource.resolvePluralAttributeElementSource(
new PluralAttributeElementSourceResolver.PluralAttributeElementSourceResolutionContext() {
@Override
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) {
return attributeSource( referencedEntityName, mappedBy );
}
}
);
}
final PluralAttribute attribute =
attributeBindingContainer.getAttributeContainer().locatePluralAttribute( attributeSource.getName() );
final AbstractPluralAttributeBinding attributeBinding;
@ -1890,6 +1901,13 @@ public class Binder {
true
)
);
if ( elementSource.isUnique() ) {
for ( RelationalValueBinding relationalValueBinding : elementBinding.getRelationalValueBindings() ) {
if ( ! relationalValueBinding.isDerived() ) {
( (Column) relationalValueBinding.getValue() ).setUnique( true );
}
}
}
if ( !elementBinding.getPluralAttributeBinding().getPluralAttributeKeyBinding().isInverse() &&
!elementBinding.hasDerivedValue() ) {
locateOrCreateForeignKey(
@ -3040,6 +3058,10 @@ public class Binder {
.createSingularAttribute( attributeSource.getName() );
}
private AttributeSource attributeSource(final String entityName, final String attributeName) {
return attributeSourcesByName.get( attributeSourcesByNameKey( entityName, attributeName ) );
}
private static String attributeSourcesByNameKey(
final String entityName,
final String attributeName) {

View File

@ -33,8 +33,6 @@ import java.util.Properties;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.ValueHolder;

View File

@ -36,6 +36,7 @@ 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;
@ -48,16 +49,22 @@ import org.jboss.jandex.AnnotationInstance;
*/
public class ManyToManyPluralAttributeElementSourceImpl 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(
PluralAssociationAttribute associationAttribute) {
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute,
boolean isUnique) {
this.ownerAttributeSource = ownerAttributeSource;
this.associationAttribute = associationAttribute;
this.isUnique = isUnique;
for ( Column column : associationAttribute.getInverseJoinColumnValues() ) {
relationalValueSources.add( new ColumnSourceImpl(
@ -123,8 +130,7 @@ public class ManyToManyPluralAttributeElementSourceImpl implements ManyToManyPlu
@Override
public boolean isUnique() {
// TODO
return false;
return isUnique;
}
@Override

View File

@ -27,15 +27,20 @@ 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 implements OneToManyPluralAttributeElementSource {
private final AttributeSource ownerAttributeSource;
private final PluralAssociationAttribute associationAttribute;
public OneToManyPluralAttributeElementSourceImpl(PluralAssociationAttribute associationAttribute) {
public OneToManyPluralAttributeElementSourceImpl(
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute) {
this.ownerAttributeSource = ownerAttributeSource;
this.associationAttribute = associationAttribute;
}

View File

@ -39,6 +39,7 @@ 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.AttributeSource;
import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource;
import org.hibernate.metamodel.spi.source.FilterSource;
import org.hibernate.metamodel.spi.source.MetaAttributeSource;
@ -48,6 +49,7 @@ import org.hibernate.metamodel.spi.source.PluralAttributeKeySource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.Sortable;
import org.hibernate.metamodel.spi.source.TableSpecificationSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
/**
* @author Hardy Ferentschik
@ -55,23 +57,31 @@ import org.hibernate.metamodel.spi.source.TableSpecificationSource;
public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderable, Sortable {
private final PluralAssociationAttribute associationAttribute;
private final ConfiguredClass entityClass;
private final Nature nature;
private final ExplicitHibernateTypeSource typeSource;
private final PluralAttributeKeySource keySource;
private final PluralAttributeElementSource elementSource;
private final FilterSource[] filterSources;
// If it is not the owner side (i.e., mappedBy != null), then the AttributeSource
// for the owner is required to determine elementSource.
private PluralAttributeElementSource elementSource;
public PluralAttributeSourceImpl(
final PluralAssociationAttribute associationAttribute,
final ConfiguredClass entityClass ) {
this.associationAttribute = associationAttribute;
this.entityClass = entityClass;
this.keySource = new PluralAttributeKeySourceImpl( associationAttribute );
this.typeSource = new ExplicitHibernateTypeSourceImpl( associationAttribute );
this.nature = associationAttribute.getPluralAttributeNature();
this.elementSource = determineElementSource( associationAttribute, entityClass );
if ( associationAttribute.getMappedBy() == null ) {
this.elementSource = determineOwnerElementSource( this, associationAttribute, entityClass );
}
this.filterSources = determineFilterSources(associationAttribute);
}
private FilterSource[] determineFilterSources(PluralAssociationAttribute associationAttribute) {
private static FilterSource[] determineFilterSources(PluralAssociationAttribute associationAttribute) {
AnnotationInstance filtersAnnotation = JandexHelper.getSingleAnnotation(
associationAttribute.annotations(),
HibernateDotNames.FILTERS
@ -108,6 +118,9 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
@Override
public PluralAttributeElementSource getElementSource() {
if ( elementSource == null ) {
throw new IllegalStateException( "elementSource has not been initialized yet." );
}
return elementSource;
}
@ -121,6 +134,23 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
return associationAttribute.getBatchSize();
}
public static boolean usesJoinTable(AttributeSource ownerAttributeSource) {
return ownerAttributeSource.isSingular() ?
( (ToOneAttributeSource) ownerAttributeSource ).getContainingTableName() != null :
( (PluralAttributeSource) ownerAttributeSource ).usesJoinTable();
}
public boolean usesJoinTable() {
if ( associationAttribute.getMappedBy() != null ) {
throw new IllegalStateException( "Cannot determine if a join table is used because plural attribute is not the owner." );
}
// By default, a unidirectional one-to-many (i.e., with mappedBy == null) uses a join table,
// unless it has join columns defined.
return associationAttribute.getJoinTableAnnotation() != null ||
( associationAttribute.getJoinTableAnnotation() == null &&
associationAttribute.getJoinColumnValues().size() == 0 );
}
@Override
public ValueHolder<Class<?>> getElementClassReference() {
// needed for arrays
@ -133,14 +163,19 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
}
}
private static PluralAttributeElementSource determineElementSource(PluralAssociationAttribute associationAttribute, ConfiguredClass entityClass) {
private static PluralAttributeElementSource determineOwnerElementSource(
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute,
ConfiguredClass entityClass) {
switch ( associationAttribute.getNature() ) {
case MANY_TO_MANY:
return new ManyToManyPluralAttributeElementSourceImpl( associationAttribute );
return new ManyToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute, false );
case MANY_TO_ANY:
return new ManyToAnyPluralAttributeElementSourceImpl( associationAttribute );
case ONE_TO_MANY:
return new OneToManyPluralAttributeElementSourceImpl( associationAttribute );
return usesJoinTable( ownerAttributeSource ) ?
new ManyToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute, true ) :
new OneToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute );
case ELEMENT_COLLECTION_BASIC:
return new BasicPluralAttributeElementSourceImpl( associationAttribute );
case ELEMENT_COLLECTION_EMBEDDABLE: {
@ -300,7 +335,21 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
return associationAttribute.getFetchStyle();
}
@Override
public PluralAttributeElementSource resolvePluralAttributeElementSource(
PluralAttributeElementSourceResolutionContext context) {
if ( associationAttribute.getMappedBy() == null ) {
return elementSource;
}
else {
AttributeSource ownerAttributeSource = context.resolveAttributeSource(
associationAttribute.getReferencedEntityType(),
associationAttribute.getMappedBy()
);
elementSource = determineOwnerElementSource( ownerAttributeSource, associationAttribute, entityClass );
return elementSource;
}
}
}

View File

@ -26,12 +26,12 @@ package org.hibernate.metamodel.internal.source.hbm;
import java.util.Collections;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.jaxb.spi.hbm.JaxbClassElement;
import org.hibernate.jaxb.spi.hbm.JaxbFilterElement;
import org.hibernate.jaxb.spi.hbm.PluralAttributeElement;
import org.hibernate.metamodel.spi.binding.Caching;
@ -163,6 +163,34 @@ public abstract class AbstractPluralAttributeSourceImpl
}
}
@Override
public PluralAttributeElementSource resolvePluralAttributeElementSource(PluralAttributeElementSourceResolutionContext context) {
return elementSource;
}
@Override
public boolean usesJoinTable() {
switch ( elementSource.getNature() ) {
case BASIC:
case AGGREGATE:
case ONE_TO_MANY:
return false;
case MANY_TO_MANY:
return true;
case MANY_TO_ANY:
throw new NotYetImplementedException(
String.format( "%s is not implemented yet.", elementSource.getNature() )
);
default:
throw new AssertionFailure(
String.format(
"Unexpected plural attribute element source nature: %s",
elementSource.getNature()
)
);
}
}
public PluralAttributeElement getPluralAttributeElement() {
return pluralAttributeElement;
}

View File

@ -0,0 +1,36 @@
/*
* 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 PluralAttributeElementSourceResolver {
PluralAttributeElementSource resolvePluralAttributeElementSource(PluralAttributeElementSourceResolutionContext context);
public static interface PluralAttributeElementSourceResolutionContext {
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy);
}
}

View File

@ -36,7 +36,7 @@ import org.hibernate.metamodel.spi.binding.CustomSQL;
* @author Steve Ebersole
*/
public interface PluralAttributeSource
extends AttributeSource, FetchableAttributeSource {
extends AttributeSource, FetchableAttributeSource, PluralAttributeElementSourceResolver {
public Nature getNature();
public PluralAttributeKeySource getKeySource();
@ -77,6 +77,8 @@ public interface PluralAttributeSource
public int getBatchSize();
public boolean usesJoinTable();
/**
* Describes the nature of the collection itself as declared by the metadata.
*

View File

@ -49,6 +49,7 @@ public class EntityWithUnidirectionalOneToMany {
}
@OneToMany
@JoinColumn
public Collection<ReferencedEntity> getTheBag() {
return theBag;
}