HHH-6503 - Develop Set-style plural attribute support for new metamodel

This commit is contained in:
Steve Ebersole 2011-08-12 11:47:34 -05:00
parent 524443d848
commit 859b61a7c4
21 changed files with 792 additions and 147 deletions

View File

@ -0,0 +1,52 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.engine;
/**
* Enumeration of values describing <b>HOW</b> fetching should occur.
*
* @author Steve Ebersole
* @see FetchTiming
*/
public enum FetchStyle {
/**
* Performs a separate SQL select to load the indicated data. This can either be eager (the second select is
* issued immediately) or lazy (the second select is delayed until the data is needed).
*/
SELECT,
/**
* Inherently an eager style of fetching. The data to be fetched is obtained as part of an SQL join.
*/
JOIN,
/**
* Initializes a number of indicated data items (entities or collections) in a series of grouped sql selects
* using an in-style sql restriction to define the batch size. Again, can be either eager or lazy.
*/
BATCH,
/**
* Performs fetching of associated data (currently limited to only collections) based on the sql restriction
* used to load the owner. Again, can be either eager or lazy.
*/
SUBSELECT
}

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.engine;
/**
* Enumeration of values describing <b>WHEN</b> fetching should occur.
*
* @author Steve Ebersole
* @see FetchStyle
*/
public enum FetchTiming {
/**
* Perform fetching immediately. Also called eager fetching
*/
IMMEDIATE,
/**
* Performing fetching later, when needed. Also called lazy fetching.
*/
DELAYED,
/**
* Take extra care to ensure laziness. <b>Only available in regards to collections</b>
*/
EXTRA_LAZY
}

View File

@ -640,12 +640,9 @@ public void sessionFactoryClosed(SessionFactory factory) {
if ( accessStrategy == null ) {
final AccessType accessType = model.getHierarchyDetails().getCaching().getAccessType();
LOG.trace("Building cache for entity data [" + model.getEntity().getName() + "]");
EntityRegion entityRegion =
settings.getRegionFactory().buildEntityRegion(
cacheRegionName,
properties,
CacheDataDescriptionImpl.decode( model )
);
EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion(
cacheRegionName, properties, CacheDataDescriptionImpl.decode( model )
);
accessStrategy = entityRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
allCacheRegions.put( cacheRegionName, entityRegion );
@ -670,28 +667,22 @@ public void sessionFactoryClosed(SessionFactory factory) {
"AbstractPluralAttributeBinding has a Singular attribute defined: " + model.getAttribute().getName()
);
}
// TODO: Add AbstractPluralAttributeBinding.getCaching()
final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
final String cacheRegionName = cacheRegionPrefix + model.getCaching().getRegion();
final AccessType accessType = model.getCaching().getAccessType();
CollectionRegionAccessStrategy accessStrategy = null;
if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
// TODO: is model.locateAttribute().getName() the collection's role??? For now, assuming it is
LOG.trace("Building cache for collection data [" + model.getAttribute().getName() + "]");
CollectionRegion collectionRegion =
settings.getRegionFactory()
.buildCollectionRegion(
cacheRegionName, properties, CacheDataDescriptionImpl.decode( model )
);
LOG.trace("Building cache for collection data [" + model.getAttribute().getRole() + "]");
CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion(
cacheRegionName, properties, CacheDataDescriptionImpl.decode( model )
);
accessStrategy = collectionRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
allCacheRegions.put( cacheRegionName, collectionRegion );
}
CollectionPersister persister =
serviceRegistry
.getService( PersisterFactory.class )
.createCollectionPersister( metadata, model, accessStrategy, this );
// TODO: is model.locateAttribute().getName() the collection's role??? For now, assuming it is
collectionPersisters.put( model.getAttribute().getName(), persister.getCollectionMetadata() );
CollectionPersister persister = serviceRegistry
.getService( PersisterFactory.class )
.createCollectionPersister( metadata, model, accessStrategy, this );
collectionPersisters.put( model.getAttribute().getRole(), persister.getCollectionMetadata() );
Type indexType = persister.getIndexType();
if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {
String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );

View File

@ -31,11 +31,13 @@
import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.domain.Attribute;
import org.hibernate.metamodel.domain.PluralAttribute;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.persister.collection.CollectionPersister;
/**
* TODO : javadoc
@ -48,36 +50,37 @@ public abstract class AbstractPluralAttributeBinding extends AbstractAttributeBi
private Table collectionTable;
private CascadeStyle cascadeStyle;
private FetchMode fetchMode;
private FetchTiming fetchTiming;
private FetchStyle fetchStyle;
private int batchSize = -1;
private CascadeStyle cascadeStyle;
private boolean orphanDelete;
private Caching caching;
private boolean extraLazy;
private boolean inverse;
private boolean mutable = true;
private boolean subselectLoadable;
private String cacheConcurrencyStrategy;
private String cacheRegionName;
private String orderBy;
private Class<? extends CollectionPersister> collectionPersisterClass;
private String where;
private String referencedPropertyName;
private String orderBy;
private boolean sorted;
private Comparator comparator;
private String comparatorClassName;
private boolean orphanDelete;
private int batchSize = -1;
private boolean embedded = true;
private boolean optimisticLocked = true;
private Class collectionPersisterClass;
private String customLoaderName;
private CustomSQL customSqlInsert;
private CustomSQL customSqlUpdate;
private CustomSQL customSqlDelete;
private CustomSQL customSqlDeleteAll;
private String referencedPropertyName;
private final java.util.Map filters = new HashMap();
private final java.util.Set<String> synchronizedTables = new HashSet<String>();
private CustomSQL customSQLInsert;
private CustomSQL customSQLUpdate;
private CustomSQL customSQLDelete;
private CustomSQL customSQLDeleteAll;
private String loaderName;
protected AbstractPluralAttributeBinding(
AttributeBindingContainer container,
PluralAttribute attribute,
@ -156,6 +159,7 @@ public boolean isAssociation() {
|| collectionElement.getCollectionElementNature() == CollectionElementNature.ONE_TO_MANY;
}
@Override
public TableSpecification getCollectionTable() {
return collectionTable;
}
@ -164,10 +168,12 @@ public void setCollectionTable(Table collectionTable) {
this.collectionTable = collectionTable;
}
@Override
public CollectionKey getCollectionKey() {
return collectionKey;
}
@Override
public AbstractCollectionElement getCollectionElement() {
return collectionElement;
}
@ -184,7 +190,12 @@ public void setCascadeStyles(Iterable<CascadeStyle> cascadeStyles) {
if ( style != CascadeStyle.NONE ) {
cascadeStyleList.add( style );
}
if ( style == CascadeStyle.DELETE_ORPHAN ||
style == CascadeStyle.ALL_DELETE_ORPHAN ) {
orphanDelete = true;
}
}
if ( cascadeStyleList.isEmpty() ) {
cascadeStyle = CascadeStyle.NONE;
}
@ -199,39 +210,102 @@ else if ( cascadeStyleList.size() == 1 ) {
}
@Override
public FetchMode getFetchMode() {
return fetchMode;
public boolean isOrphanDelete() {
return orphanDelete;
}
@Override
public void setFetchMode(FetchMode fetchMode) {
this.fetchMode = fetchMode;
public FetchMode getFetchMode() {
if ( getFetchStyle() == FetchStyle.JOIN ) {
return FetchMode.JOIN;
}
else {
return FetchMode.SELECT;
}
}
public boolean isExtraLazy() {
return extraLazy;
@Override
public FetchTiming getFetchTiming() {
return fetchTiming;
}
public boolean isInverse() {
return inverse;
@Override
public void setFetchTiming(FetchTiming fetchTiming) {
this.fetchTiming = fetchTiming;
}
public boolean isMutable() {
return mutable;
@Override
public FetchStyle getFetchStyle() {
return fetchStyle;
}
public boolean isSubselectLoadable() {
return subselectLoadable;
@Override
public void setFetchStyle(FetchStyle fetchStyle) {
this.fetchStyle = fetchStyle;
}
public String getCacheConcurrencyStrategy() {
return cacheConcurrencyStrategy;
@Override
public String getCustomLoaderName() {
return customLoaderName;
}
public String getCacheRegionName() {
return cacheRegionName;
public void setCustomLoaderName(String customLoaderName) {
this.customLoaderName = customLoaderName;
}
@Override
public CustomSQL getCustomSqlInsert() {
return customSqlInsert;
}
public void setCustomSqlInsert(CustomSQL customSqlInsert) {
this.customSqlInsert = customSqlInsert;
}
@Override
public CustomSQL getCustomSqlUpdate() {
return customSqlUpdate;
}
public void setCustomSqlUpdate(CustomSQL customSqlUpdate) {
this.customSqlUpdate = customSqlUpdate;
}
@Override
public CustomSQL getCustomSqlDelete() {
return customSqlDelete;
}
public void setCustomSqlDelete(CustomSQL customSqlDelete) {
this.customSqlDelete = customSqlDelete;
}
@Override
public CustomSQL getCustomSqlDeleteAll() {
return customSqlDeleteAll;
}
public void setCustomSqlDeleteAll(CustomSQL customSqlDeleteAll) {
this.customSqlDeleteAll = customSqlDeleteAll;
}
public Class<? extends CollectionPersister> getCollectionPersisterClass() {
return collectionPersisterClass;
}
public void setCollectionPersisterClass(Class<? extends CollectionPersister> collectionPersisterClass) {
this.collectionPersisterClass = collectionPersisterClass;
}
public Caching getCaching() {
return caching;
}
public void setCaching(Caching caching) {
this.caching = caching;
}
@Override
public String getOrderBy() {
return orderBy;
}
@ -240,6 +314,7 @@ public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
@Override
public String getWhere() {
return where;
}
@ -248,14 +323,53 @@ public void setWhere(String where) {
this.where = where;
}
@Override
public boolean isInverse() {
return inverse;
}
public void setInverse(boolean inverse) {
this.inverse = inverse;
}
@Override
public boolean isMutable() {
return mutable;
}
public void setMutable(boolean mutable) {
this.mutable = mutable;
}
@Override
public int getBatchSize() {
return batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public String getReferencedPropertyName() {
return referencedPropertyName;
}
@Override
public boolean isSorted() {
return sorted;
}
@Override
public Comparator getComparator() {
return comparator;
}
@ -268,47 +382,12 @@ public String getComparatorClassName() {
return comparatorClassName;
}
public boolean isOrphanDelete() {
return orphanDelete;
}
public int getBatchSize() {
return batchSize;
}
public boolean isEmbedded() {
return embedded;
}
public Class getCollectionPersisterClass() {
return collectionPersisterClass;
}
public void addFilter(String name, String condition) {
filters.put( name, condition );
}
@Override
public java.util.Map getFilterMap() {
return filters;
}
public CustomSQL getCustomSQLInsert() {
return customSQLInsert;
}
public CustomSQL getCustomSQLUpdate() {
return customSQLUpdate;
}
public CustomSQL getCustomSQLDelete() {
return customSQLDelete;
}
public CustomSQL getCustomSQLDeleteAll() {
return customSQLDeleteAll;
}
public String getLoaderName() {
return loaderName;
}
}

View File

@ -24,6 +24,8 @@
package org.hibernate.metamodel.binding;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
/**
@ -46,7 +48,19 @@ public interface AssociationAttributeBinding extends AttributeBinding {
*/
public void setCascadeStyles(Iterable<CascadeStyle> cascadeStyles);
public FetchMode getFetchMode();
public FetchTiming getFetchTiming();
public void setFetchTiming(FetchTiming fetchTiming);
public void setFetchMode(FetchMode fetchMode);
public FetchStyle getFetchStyle();
public void setFetchStyle(FetchStyle fetchStyle);
/**
* Temporary. Needed for integration with legacy {@link org.hibernate.mapping} configuration of persisters.
*
* @deprecated
*/
@Deprecated
@SuppressWarnings( {"JavaDoc"})
public FetchMode getFetchMode();
}

View File

@ -0,0 +1,33 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.binding;
/**
* @author Steve Ebersole
*/
public enum CollectionLaziness {
LAZY,
NOT,
EXTRA
}

View File

@ -28,6 +28,8 @@
import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.domain.SingularAttribute;
@ -46,7 +48,8 @@ public class ManyToOneAttributeBinding extends BasicAttributeBinding implements
private String foreignKeyName;
private CascadeStyle cascadeStyle;
private FetchMode fetchMode;
private FetchTiming fetchTiming;
private FetchStyle fetchStyle;
ManyToOneAttributeBinding(AttributeBindingContainer container, SingularAttribute attribute) {
super( container, attribute, false, false );
@ -109,13 +112,42 @@ else if ( cascadeStyleList.size() == 1 ) {
}
@Override
public FetchMode getFetchMode() {
return fetchMode;
public FetchTiming getFetchTiming() {
return fetchTiming;
}
@Override
public void setFetchMode(FetchMode fetchMode) {
this.fetchMode = fetchMode;
public void setFetchTiming(FetchTiming fetchTiming) {
this.fetchTiming = fetchTiming;
}
@Override
public FetchStyle getFetchStyle() {
return fetchStyle;
}
@Override
public void setFetchStyle(FetchStyle fetchStyle) {
if ( fetchStyle == FetchStyle.SUBSELECT ) {
throw new AssertionFailure( "Subselect fetching not yet supported for singular associations" );
}
this.fetchStyle = fetchStyle;
}
@Override
public FetchMode getFetchMode() {
if ( fetchStyle == FetchStyle.JOIN ) {
return FetchMode.JOIN;
}
else if ( fetchStyle == FetchStyle.SELECT ) {
return FetchMode.SELECT;
}
else if ( fetchStyle == FetchStyle.BATCH ) {
// we need the subsequent select...
return FetchMode.SELECT;
}
throw new AssertionFailure( "Unexpected fetch style : " + fetchStyle.name() );
}
@Override

View File

@ -23,6 +23,11 @@
*/
package org.hibernate.metamodel.binding;
import java.util.Comparator;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.domain.Attribute;
import org.hibernate.metamodel.domain.PluralAttribute;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.persister.collection.CollectionPersister;
@ -32,6 +37,9 @@
public interface PluralAttributeBinding extends AssociationAttributeBinding {
// todo : really it is the element (and/or index) that can be associative not the collection itself...
@Override
public PluralAttribute getAttribute();
public CollectionKey getCollectionKey();
public AbstractCollectionElement getCollectionElement();
@ -40,9 +48,33 @@ public interface PluralAttributeBinding extends AssociationAttributeBinding {
public boolean isMutable();
public String getCacheRegionName();
public Caching getCaching();
public String getCacheConcurrencyStrategy();
public Class<? extends CollectionPersister> getCollectionPersisterClass();
public Class<CollectionPersister> getCollectionPersisterClass();
public String getCustomLoaderName();
public CustomSQL getCustomSqlInsert();
public CustomSQL getCustomSqlUpdate();
public CustomSQL getCustomSqlDelete();
public CustomSQL getCustomSqlDeleteAll();
public boolean isOrphanDelete();
String getWhere();
boolean isSorted();
Comparator getComparator();
int getBatchSize();
java.util.Map getFilterMap();
boolean isInverse();
String getOrderBy();
}

View File

@ -29,6 +29,7 @@
import java.util.Set;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.Value;
/**
@ -83,6 +84,11 @@ public Set<Attribute> attributes() {
return Collections.unmodifiableSet( attributeSet );
}
@Override
public String getRoleBaseName() {
return getClassName();
}
@Override
public Attribute locateAttribute(String name) {
return attributeMap.get( name );
@ -266,6 +272,11 @@ public String getName() {
return name;
}
@Override
public String getRole() {
return StringHelper.qualify( attributeContainer.getRoleBaseName(), name );
}
@Override
public Type getElementType() {
return elementType;

View File

@ -32,6 +32,16 @@
* @author Steve Ebersole
*/
public interface AttributeContainer extends Type {
/**
* Obtain the name of this container in terms of creating attribute role names.
* <p/>
* NOTE : A role uniquely names each attribute. The role name is the name of the attribute prefixed by the "path"
* to its container.
*
* @return The container base name for role construction.
*/
public String getRoleBaseName();
/**
* Retrieve an attribute by name.
*

View File

@ -46,4 +46,11 @@ public boolean isAssociation() {
public boolean isComponent() {
return true;
}
@Override
public String getRoleBaseName() {
// todo : this is not really completely accurate atm
// the role base here should really be the role of the component attribute.
return getClassName();
}
}

View File

@ -29,6 +29,7 @@
* @author Steve Ebersole
*/
public interface PluralAttribute extends Attribute {
public String getRole();
public PluralAttributeNature getNature();
public Type getElementType();
public void setElementType(Type elementType);

View File

@ -26,6 +26,8 @@
import java.util.Set;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.source.annotations.EnumConversionHelper;
import org.hibernate.metamodel.source.binder.SingularAttributeNature;
@ -68,6 +70,18 @@ public Iterable<CascadeStyle> getCascadeStyles() {
public FetchMode getFetchMode() {
return associationAttribute.getFetchMode();
}
@Override
public FetchTiming getFetchTiming() {
// todo : implement
return FetchTiming.IMMEDIATE;
}
@Override
public FetchStyle getFetchStyle() {
// todo : implement
return FetchStyle.JOIN;
}
}

View File

@ -24,6 +24,8 @@
package org.hibernate.metamodel.source.binder;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
/**
@ -45,4 +47,8 @@ public interface AssociationAttributeSource extends AttributeSource {
* @return The fetch mode.
*/
public FetchMode getFetchMode();
public FetchTiming getFetchTiming();
public FetchStyle getFetchStyle();
}

View File

@ -43,8 +43,29 @@ public interface AttributeSource {
*/
public boolean isSingular();
/**
* Obtain information about the Hibernate type ({@link org.hibernate.type.Type}) for this attribute.
*
* @return The Hibernate type information
*/
public ExplicitHibernateTypeSource getTypeInformation();
/**
* Obtain the name of the property accessor style used to access this attribute.
*
* @return The property accessor style for this attribute.
*
* @see org.hibernate.property.PropertyAccessor
*/
public String getPropertyAccessorName();
/**
* If the containing entity is using {@link org.hibernate.engine.OptimisticLockStyle#ALL} or
* {@link org.hibernate.engine.OptimisticLockStyle#DIRTY} style optimistic locking, should this attribute
* be used?
*
* @return {@code true} indicates it should be included; {@code false}, it should not.
*/
public boolean isIncludedInOptimisticLocking();
/**

View File

@ -42,6 +42,7 @@
import org.hibernate.metamodel.binding.BasicAttributeBinding;
import org.hibernate.metamodel.binding.BasicCollectionElement;
import org.hibernate.metamodel.binding.CollectionElementNature;
import org.hibernate.metamodel.binding.CollectionLaziness;
import org.hibernate.metamodel.binding.ComponentAttributeBinding;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.EntityDiscriminator;
@ -67,9 +68,11 @@
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.source.LocalBindingContext;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.MetaAttributeContext;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.source.hbm.Helper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -477,7 +480,7 @@ else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SE
}
else {
// todo : implement other collection types
throw new NotYetImplementedException( "Collections other than bag not yet implemented :(" );
throw new NotYetImplementedException( "Collections other than bag and set not yet implemented :(" );
}
doBasicPluralAttributeBinding( attributeSource, pluralAttributeBinding );
@ -492,20 +495,66 @@ else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SE
metadata.addCollection( pluralAttributeBinding );
}
private void doBasicPluralAttributeBinding(
PluralAttributeSource attributeSource,
AbstractPluralAttributeBinding pluralAttributeBinding) {
pluralAttributeBinding.setFetchMode( attributeSource.getFetchMode() );
pluralAttributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() );
private void doBasicPluralAttributeBinding(PluralAttributeSource source, AbstractPluralAttributeBinding binding) {
binding.setFetchTiming( source.getFetchTiming() );
binding.setFetchStyle( source.getFetchStyle() );
binding.setCascadeStyles( source.getCascadeStyles() );
pluralAttributeBinding.setMetaAttributeContext(
binding.setCaching( source.getCaching() );
binding.getHibernateTypeDescriptor().setJavaTypeName(
source.getPluralAttributeNature().reportedJavaType().getName()
);
binding.getHibernateTypeDescriptor().setExplicitTypeName( source.getTypeInformation().getName() );
binding.getHibernateTypeDescriptor().getTypeParameters().putAll( source.getTypeInformation().getParameters() );
if ( StringHelper.isNotEmpty( source.getCustomPersisterClassName() ) ) {
binding.setCollectionPersisterClass(
currentBindingContext.<CollectionPersister>locateClassByName( source.getCustomPersisterClassName() )
);
}
if ( source.getCustomPersisterClassName() != null ) {
binding.setCollectionPersisterClass(
metadata.<CollectionPersister>locateClassByName( source.getCustomPersisterClassName() )
);
}
binding.setCustomLoaderName( source.getCustomLoaderName() );
binding.setCustomSqlInsert( source.getCustomSqlInsert() );
binding.setCustomSqlUpdate( source.getCustomSqlUpdate() );
binding.setCustomSqlDelete( source.getCustomSqlDelete() );
binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() );
binding.setMetaAttributeContext(
buildMetaAttributeContext(
attributeSource.metaAttributes(),
pluralAttributeBinding.getContainer().getMetaAttributeContext()
source.metaAttributes(),
binding.getContainer().getMetaAttributeContext()
)
);
doBasicAttributeBinding( attributeSource, pluralAttributeBinding );
doBasicAttributeBinding( source, binding );
}
private CollectionLaziness interpretLaziness(String laziness) {
if ( laziness == null ) {
laziness = Boolean.toString( metadata.getMappingDefaults().areAssociationsLazy() );
}
if ( "extra".equals( laziness ) ) {
return CollectionLaziness.EXTRA;
}
else if ( "false".equals( laziness ) ) {
return CollectionLaziness.NOT;
}
else if ( "true".equals( laziness ) ) {
return CollectionLaziness.LAZY;
}
throw new MappingException(
String.format( "Unexpected collection laziness value %s", laziness ),
currentBindingContext.getOrigin()
);
}
private void bindCollectionTable(
@ -856,7 +905,8 @@ private void resolveToOneInformation(ToOneAttributeSource attributeSource, ManyT
attributeBinding.setReferencedAttributeName( attributeSource.getReferencedEntityAttributeName() );
attributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() );
attributeBinding.setFetchMode( attributeSource.getFetchMode() );
attributeBinding.setFetchTiming( attributeSource.getFetchTiming() );
attributeBinding.setFetchStyle( attributeSource.getFetchStyle() );
}
private MetaAttributeContext buildMetaAttributeContext(EntitySource entitySource) {

View File

@ -23,15 +23,30 @@
*/
package org.hibernate.metamodel.source.binder;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Describes the nature of the collection itself as declared by the metadata.
*
* @author Steve Ebersole
*/
public enum PluralAttributeNature {
BAG,
ID_BAG,
SET,
LIST,
MAP
BAG( Collection.class ),
ID_BAG( Collection.class ),
SET( Set.class ),
LIST( List.class ),
MAP( Map.class );
private final Class<?> reportedJavaType;
PluralAttributeNature(Class<?> reportedJavaType) {
this.reportedJavaType = reportedJavaType;
}
public Class<?> reportedJavaType() {
return reportedJavaType;
}
}

View File

@ -23,6 +23,9 @@
*/
package org.hibernate.metamodel.source.binder;
import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.CustomSQL;
/**
* @author Steve Ebersole
*/
@ -40,7 +43,26 @@ public interface PluralAttributeSource extends AssociationAttributeSource {
public String getCollectionTableComment();
public String getCollectionTableCheck();
public Caching getCaching();
/**
* Obtain the name of a custom persister class to be used.
*
* @return The custom persister class name
*/
public String getCustomPersisterClassName();
public String getWhere();
public boolean isInverse();
public String getCustomLoaderName();
public CustomSQL getCustomSqlInsert();
public CustomSQL getCustomSqlUpdate();
public CustomSQL getCustomSqlDelete();
public CustomSQL getCustomSqlDeleteAll();
}

View File

@ -46,22 +46,6 @@ public interface SingularAttributeSource extends AttributeSource, RelationalValu
*/
public SingularAttributeNature getNature();
/**
* Obtain information about the Hibernate type ({@link org.hibernate.type.Type}) for this attribute.
*
* @return The Hibernate type information
*/
public ExplicitHibernateTypeSource getTypeInformation();
/**
* Obtain the name of the property accessor style used to access this attribute.
*
* @return The property accessor style for this attribute.
*
* @see org.hibernate.property.PropertyAccessor
*/
public String getPropertyAccessorName();
/**
* Determine whether this attribute is insertable.
*
@ -91,13 +75,4 @@ public interface SingularAttributeSource extends AttributeSource, RelationalValu
* @return {@code true} to indicate the attribute should be lazily loaded.
*/
public boolean isLazy();
/**
* If the containing entity is using {@link org.hibernate.engine.OptimisticLockStyle#ALL} or
* {@link org.hibernate.engine.OptimisticLockStyle#DIRTY} style optimistic locking, should this attribute
* be used?
*
* @return {@code true} indicates it should be included; {@code false}, it should not.
*/
public boolean isIncludedInOptimisticLocking();
}

View File

@ -23,17 +23,28 @@
*/
package org.hibernate.metamodel.source.hbm;
import java.util.Collections;
import java.util.Map;
import org.hibernate.FetchMode;
import org.hibernate.cache.spi.access.AccessType;
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.StringHelper;
import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.CustomSQL;
import org.hibernate.metamodel.source.LocalBindingContext;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.binder.AttributeSourceContainer;
import org.hibernate.metamodel.source.binder.ExplicitHibernateTypeSource;
import org.hibernate.metamodel.source.binder.MetaAttributeSource;
import org.hibernate.metamodel.source.binder.PluralAttributeElementSource;
import org.hibernate.metamodel.source.binder.PluralAttributeKeySource;
import org.hibernate.metamodel.source.binder.PluralAttributeSource;
import org.hibernate.metamodel.source.hbm.jaxb.mapping.PluralAttributeElement;
import org.hibernate.metamodel.source.hbm.jaxb.mapping.XMLCacheElement;
/**
* @author Steve Ebersole
@ -42,17 +53,31 @@ public abstract class AbstractPluralAttributeSourceImpl implements PluralAttribu
private final PluralAttributeElement pluralAttributeElement;
private final AttributeSourceContainer container;
private final ExplicitHibernateTypeSource typeInformation;
private final PluralAttributeKeySource keySource;
private final PluralAttributeElementSource elementSource;
protected AbstractPluralAttributeSourceImpl(
PluralAttributeElement pluralAttributeElement,
final PluralAttributeElement pluralAttributeElement,
AttributeSourceContainer container) {
this.pluralAttributeElement = pluralAttributeElement;
this.container = container;
this.keySource = new PluralAttributeKeySourceImpl( pluralAttributeElement.getKey(), container );
this.elementSource = interpretElementType();
this.typeInformation = new ExplicitHibernateTypeSource() {
@Override
public String getName() {
return pluralAttributeElement.getCollectionType();
}
@Override
public Map<String, String> getParameters() {
return Collections.emptyMap();
}
};
}
private PluralAttributeElementSource interpretElementType() {
@ -135,6 +160,20 @@ public String getCollectionTableCheck() {
return pluralAttributeElement.getCheck();
}
@Override
public Caching getCaching() {
final XMLCacheElement cache = pluralAttributeElement.getCache();
if ( cache == null ) {
return null;
}
final String region = cache.getRegion() != null
? cache.getRegion()
: StringHelper.qualify( container().getPath(), getName() );
final AccessType accessType = Enum.valueOf( AccessType.class, cache.getUsage() );
final boolean cacheLazyProps = !"non-lazy".equals( cache.getInclude() );
return new Caching( region, accessType, cacheLazyProps );
}
@Override
public String getWhere() {
return pluralAttributeElement.getWhere();
@ -150,6 +189,11 @@ public boolean isSingular() {
return false;
}
@Override
public ExplicitHibernateTypeSource getTypeInformation() {
return typeInformation;
}
@Override
public String getPropertyAccessorName() {
return pluralAttributeElement.getAccess();
@ -165,6 +209,38 @@ public boolean isInverse() {
return pluralAttributeElement.isInverse();
}
@Override
public String getCustomPersisterClassName() {
return pluralAttributeElement.getPersister();
}
@Override
public String getCustomLoaderName() {
return pluralAttributeElement.getLoader() == null
? null
: pluralAttributeElement.getLoader().getQueryRef();
}
@Override
public CustomSQL getCustomSqlInsert() {
return Helper.buildCustomSql( pluralAttributeElement.getSqlInsert() );
}
@Override
public CustomSQL getCustomSqlUpdate() {
return Helper.buildCustomSql( pluralAttributeElement.getSqlUpdate() );
}
@Override
public CustomSQL getCustomSqlDelete() {
return Helper.buildCustomSql( pluralAttributeElement.getSqlDelete() );
}
@Override
public CustomSQL getCustomSqlDeleteAll() {
return Helper.buildCustomSql( pluralAttributeElement.getSqlDeleteAll() );
}
@Override
public Iterable<MetaAttributeSource> metaAttributes() {
return Helper.buildMetaAttributeSources( pluralAttributeElement.getMeta() );
@ -175,6 +251,86 @@ public Iterable<CascadeStyle> getCascadeStyles() {
return Helper.interpretCascadeStyles( pluralAttributeElement.getCascade(), bindingContext() );
}
@Override
public FetchTiming getFetchTiming() {
final String fetchSelection = pluralAttributeElement.getFetch() != null ?
pluralAttributeElement.getFetch().value() :
null;
final String lazySelection = pluralAttributeElement.getLazy() != null
? pluralAttributeElement.getLazy().value()
: null;
final String outerJoinSelection = pluralAttributeElement.getOuterJoin() != null
? pluralAttributeElement.getOuterJoin().value()
: null;
if ( lazySelection == null ) {
if ( "join".equals( fetchSelection ) || "true".equals( outerJoinSelection ) ) {
return FetchTiming.IMMEDIATE;
}
else if ( "false".equals( outerJoinSelection ) ) {
return FetchTiming.DELAYED;
}
else {
return bindingContext().getMappingDefaults().areAssociationsLazy()
? FetchTiming.DELAYED
: FetchTiming.IMMEDIATE;
}
}
else if ( "extra".equals( lazySelection ) ) {
return FetchTiming.EXTRA_LAZY;
}
else if ( "true".equals( lazySelection ) ) {
return FetchTiming.DELAYED;
}
else if ( "false".equals( lazySelection ) ) {
return FetchTiming.IMMEDIATE;
}
throw new MappingException(
String.format(
"Unexpected lazy selection [%s] on '%s'",
lazySelection,
pluralAttributeElement.getName()
),
bindingContext().getOrigin()
);
}
@Override
public FetchStyle getFetchStyle() {
final String fetchSelection = pluralAttributeElement.getFetch() != null ?
pluralAttributeElement.getFetch().value() :
null;
final String outerJoinSelection = pluralAttributeElement.getOuterJoin() != null
? pluralAttributeElement.getOuterJoin().value()
: null;
final int batchSize = Helper.getIntValue( pluralAttributeElement.getBatchSize(), -1 );
if ( fetchSelection == null ) {
if ( outerJoinSelection == null ) {
return batchSize > 1 ? FetchStyle.BATCH : FetchStyle.SELECT;
}
else {
if ( "auto".equals( outerJoinSelection ) ) {
return bindingContext().getMappingDefaults().areAssociationsLazy()
? FetchStyle.SELECT
: FetchStyle.JOIN;
}
else {
return "true".equals( outerJoinSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT;
}
}
}
else {
if ( "subselect".equals( fetchSelection ) ) {
return FetchStyle.SUBSELECT;
}
else {
return "join".equals( fetchSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT;
}
}
}
@Override
public FetchMode getFetchMode() {
return pluralAttributeElement.getFetch() == null

View File

@ -26,9 +26,12 @@
import java.util.List;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.source.LocalBindingContext;
import org.hibernate.metamodel.source.MappingException;
import org.hibernate.metamodel.source.binder.ExplicitHibernateTypeSource;
import org.hibernate.metamodel.source.binder.MetaAttributeSource;
import org.hibernate.metamodel.source.binder.RelationalValueSource;
@ -131,6 +134,82 @@ public Iterable<CascadeStyle> getCascadeStyles() {
return Helper.interpretCascadeStyles( manyToOneElement.getCascade(), bindingContext );
}
@Override
public FetchTiming getFetchTiming() {
final String fetchSelection = manyToOneElement.getFetch() != null
? manyToOneElement.getFetch().value()
: null;
final String lazySelection = manyToOneElement.getLazy() != null
? manyToOneElement.getLazy().value()
: null;
final String outerJoinSelection = manyToOneElement.getOuterJoin() != null
? manyToOneElement.getOuterJoin().value()
: null;
if ( lazySelection == null ) {
if ( "join".equals( fetchSelection ) || "true".equals( outerJoinSelection ) ) {
return FetchTiming.IMMEDIATE;
}
else if ( "false".equals( outerJoinSelection ) ) {
return FetchTiming.DELAYED;
}
else {
return bindingContext.getMappingDefaults().areAssociationsLazy()
? FetchTiming.DELAYED
: FetchTiming.IMMEDIATE;
}
}
else if ( "extra".equals( lazySelection ) ) {
return FetchTiming.EXTRA_LAZY;
}
else if ( "true".equals( lazySelection ) ) {
return FetchTiming.DELAYED;
}
else if ( "false".equals( lazySelection ) ) {
return FetchTiming.IMMEDIATE;
}
throw new MappingException(
String.format(
"Unexpected lazy selection [%s] on '%s'",
lazySelection,
manyToOneElement.getName()
),
bindingContext.getOrigin()
);
}
@Override
public FetchStyle getFetchStyle() {
// todo : handle batch fetches?
final String fetchSelection = manyToOneElement.getFetch() != null
? manyToOneElement.getFetch().value()
: null;
final String outerJoinSelection = manyToOneElement.getOuterJoin() != null
? manyToOneElement.getOuterJoin().value()
: null;
if ( fetchSelection == null ) {
if ( outerJoinSelection == null ) {
return FetchStyle.SELECT;
}
else {
if ( "auto".equals( outerJoinSelection ) ) {
return bindingContext.getMappingDefaults().areAssociationsLazy()
? FetchStyle.SELECT
: FetchStyle.JOIN;
}
else {
return "true".equals( outerJoinSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT;
}
}
}
else {
return "join".equals( fetchSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT;
}
}
@Override
public FetchMode getFetchMode() {
return manyToOneElement.getFetch() == null