Skip to content

Commit

Permalink
HHH-7436 : Add support for many-to-many associations to new metamodel
Browse files Browse the repository at this point in the history
  • Loading branch information
gbadner committed Mar 5, 2013
1 parent 5a993dd commit 9d40416
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 17 deletions.
Expand Up @@ -136,6 +136,7 @@
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;
Expand Down Expand Up @@ -1391,6 +1392,16 @@ private AbstractPluralAttributeBinding bindPluralAttribute(
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;
Expand Down Expand Up @@ -1890,6 +1901,13 @@ public String defaultName() {
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(
Expand Down Expand Up @@ -3040,6 +3058,10 @@ private static SingularAttribute createSingularAttribute(
.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) {
Expand Down
Expand Up @@ -33,8 +33,6 @@

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;
Expand Down
Expand Up @@ -36,6 +36,7 @@
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;
Expand All @@ -47,18 +48,24 @@
* @author Brett Meyer
*/
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(
associationAttribute, null, column ) );
Expand Down Expand Up @@ -123,8 +130,7 @@ public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate(

@Override
public boolean isUnique() {
// TODO
return false;
return isUnique;
}

@Override
Expand Down
Expand Up @@ -27,15 +27,20 @@
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;
}

Expand Down
Expand Up @@ -39,6 +39,7 @@
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;
Expand All @@ -48,30 +49,39 @@
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
*/
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
Expand Down Expand Up @@ -108,6 +118,9 @@ public Nature getNature() {

@Override
public PluralAttributeElementSource getElementSource() {
if ( elementSource == null ) {
throw new IllegalStateException( "elementSource has not been initialized yet." );
}
return elementSource;
}

Expand All @@ -121,6 +134,23 @@ public int getBatchSize() {
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
Expand All @@ -133,14 +163,19 @@ public ValueHolder<Class<?>> getElementClassReference() {
}
}

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: {
Expand Down Expand Up @@ -300,7 +335,21 @@ public FetchStyle getFetchStyle() {
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;
}
}
}


Expand Up @@ -26,12 +26,12 @@
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;
Expand Down Expand Up @@ -163,6 +163,34 @@ else if ( pluralAttributeElement.getManyToAny() != null ) {
}
}

@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;
}
Expand Down
@@ -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);
}
}
Expand Up @@ -36,7 +36,7 @@
* @author Steve Ebersole
*/
public interface PluralAttributeSource
extends AttributeSource, FetchableAttributeSource {
extends AttributeSource, FetchableAttributeSource, PluralAttributeElementSourceResolver {
public Nature getNature();

public PluralAttributeKeySource getKeySource();
Expand Down Expand Up @@ -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.
*
Expand Down
Expand Up @@ -49,6 +49,7 @@ public void setName(String name) {
}

@OneToMany
@JoinColumn
public Collection<ReferencedEntity> getTheBag() {
return theBag;
}
Expand Down

0 comments on commit 9d40416

Please sign in to comment.