/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ package org.hibernate.orm.persister.collection.internal; import java.util.Collections; import java.util.List; import javax.persistence.AttributeConverter; import javax.persistence.metamodel.Type; import org.hibernate.HibernateException; import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Component; import org.hibernate.mapping.IdentifierCollection; import org.hibernate.mapping.IndexedCollection; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Value; import org.hibernate.orm.persister.collection.spi.CollectionPersister; import org.hibernate.orm.persister.collection.spi.CollectionElement; import org.hibernate.orm.persister.collection.spi.CollectionId; import org.hibernate.orm.persister.collection.spi.CollectionIndex; import org.hibernate.orm.persister.collection.spi.CollectionKey; import org.hibernate.orm.persister.common.internal.PersisterHelper; import org.hibernate.orm.persister.common.spi.AbstractOrmAttribute; import org.hibernate.orm.persister.common.spi.Column; import org.hibernate.orm.persister.common.spi.JoinColumnMapping; import org.hibernate.orm.persister.common.spi.ManagedTypeImplementor; import org.hibernate.orm.persister.common.spi.OrmAttribute; import org.hibernate.orm.persister.common.spi.OrmNavigable; import org.hibernate.orm.persister.common.spi.OrmNavigableSource; import org.hibernate.orm.persister.spi.PersisterCreationContext; import org.hibernate.orm.type.descriptor.java.internal.CollectionJavaDescriptor; import org.hibernate.orm.type.descriptor.java.internal.ListJavaDescriptor; import org.hibernate.orm.type.descriptor.java.internal.MapJavaDescriptor; import org.hibernate.orm.type.descriptor.java.internal.SetJavaDescriptor; import org.hibernate.orm.type.descriptor.java.spi.JavaTypeDescriptor; import org.hibernate.orm.type.descriptor.java.spi.JavaTypeDescriptorRegistry; import org.hibernate.orm.type.internal.CollectionTypeImpl; import org.hibernate.orm.type.spi.TypeConfiguration; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.query.sqm.NotYetImplementedException; import org.hibernate.type.BasicType; import org.hibernate.type.EntityType; import static org.hibernate.orm.persister.OrmTypeHelper.convertBasic; import static org.hibernate.orm.persister.OrmTypeHelper.convertComposite; import static org.hibernate.orm.persister.OrmTypeHelper.convertEntity; /** * @author Steve Ebersole */ public class CollectionPersisterImpl<O,C,E> extends AbstractOrmAttribute<O,C> implements CollectionPersister<O,C,E> { public static final String INDEX_NAVIGABLE_NAME = "{index}"; public static final String ELEMENT_NAVIGABLE_NAME = "{element}"; private final OrmNavigableSource source; private final String localName; private final CollectionClassification collectionClassification; private final org.hibernate.orm.type.spi.CollectionType collectionType; private final CollectionKey foreignKeyDescriptor; private CollectionId idDescriptor; private CollectionElement elementDescriptor; private CollectionIndex indexDescriptor; private org.hibernate.orm.persister.common.spi.Table separateCollectionTable; private AttributeConverter indexAttributeConverter; private AttributeConverter elementAttributeConverter; // TODO: encapsulate the protected instance variables! private final String role; private TypeConfiguration typeConfiguration; public CollectionPersisterImpl( Collection collectionBinding, ManagedTypeImplementor source, String localName, CollectionRegionAccessStrategy collectionCaching, PersisterCreationContext creationContext) { super( source, localName, PropertyAccess.DUMMY ); this.source = source; this.localName = localName; this.role = source.getNavigableName() + '.' + this.localName; this.collectionClassification = PersisterHelper.interpretCollectionClassification( collectionBinding ); this.foreignKeyDescriptor = new CollectionKey( this ); this.typeConfiguration = creationContext.getTypeConfiguration(); this.collectionType = new CollectionTypeImpl( role, resolveCollectionJtd( creationContext, collectionClassification ), null, null ); if ( collectionBinding instanceof IndexedCollection ) { final Value indexValueMapping = ( (IndexedCollection) collectionBinding ).getIndex(); if ( indexValueMapping instanceof SimpleValue ) { final SimpleValue simpleIndexValueMapping = (SimpleValue) indexValueMapping; // indexAttributeConverter = simpleIndexValueMapping.getAttributeConverterDescriptor().getAttributeConverter(); } } final Value elementValueMapping = collectionBinding.getElement(); if ( elementValueMapping instanceof SimpleValue ) { final SimpleValue simpleElementValueMapping = (SimpleValue) elementValueMapping; // elementAttributeConverter = simpleElementValueMapping.getAttributeConverterDescriptor().getAttributeConverter(); } } @SuppressWarnings("unchecked") private static JavaTypeDescriptor resolveCollectionJtd( org.hibernate.orm.persister.spi.PersisterCreationContext creationContext, CollectionClassification collectionClassification) { final JavaTypeDescriptorRegistry jtdr = creationContext.getTypeConfiguration().getJavaTypeDescriptorRegistry(); JavaTypeDescriptor jtd; if ( collectionClassification == CollectionClassification.BAG ) { jtd = jtdr.getDescriptor( java.util.Collection.class ); if ( jtd == null ) { // todo : make one jtd = new CollectionJavaDescriptor(); // register the JavaTypeDescriptor we just created. //jtdr.addDescriptor( jtd ); } } else if ( collectionClassification == CollectionClassification.LIST ) { jtd = jtdr.getDescriptor( java.util.List.class ); if ( jtd == null ) { // todo : make one jtd = new ListJavaDescriptor(); // register it with the registry for later jtdr.addDescriptor( jtd ); } } else if ( collectionClassification == CollectionClassification.MAP ) { // todo : what about SortedMap variants? jtd = jtdr.getDescriptor( java.util.Map.class ); if ( jtd == null ) { // make one jtd = new MapJavaDescriptor(); // register it with the registry for later jtdr.addDescriptor( jtd ); } } else if ( collectionClassification == CollectionClassification.SET ) { // todo : what about SortedSet variants? jtd = jtdr.getDescriptor( java.util.Set.class ); if ( jtd == null ) { // todo : make one jtd = new SetJavaDescriptor(); // register it with the registry for later jtdr.addDescriptor( jtd ); } } else { throw new HibernateException( "Could not resolve Java 'collection type' for : " + collectionClassification ); } return jtd; } @Override public void finishInitialization(Collection collectionBinding, PersisterCreationContext creationContext) { if ( collectionBinding instanceof IdentifierCollection ) { this.idDescriptor = new CollectionId( convertBasic( (BasicType) ( (IdentifierCollection) collectionBinding ).getIdentifier().getType(), creationContext.getTypeConfiguration() ), // for now we do not need the id generator... //( (IdentifierCollection) collectionBinding ).getIdentifier().createIdentifierGenerator( ... ) null ); } else { this.idDescriptor = null; } if ( collectionBinding instanceof IndexedCollection ) { final IndexedCollection indexedCollection = (IndexedCollection) collectionBinding; final List<Column> columns = Collections.emptyList(); if ( indexedCollection.getIndex().getType().isAnyType() ) { throw new NotYetImplementedException( ); } else if ( indexedCollection.getIndex().getType().isComponentType() ) { this.indexDescriptor = new CollectionIndexEmbeddedImpl( this, convertComposite( creationContext, CollectionIndex.NAVIGABLE_NAME, (Component) indexedCollection.getIndex(), this, typeConfiguration ), columns ); } else if ( indexedCollection.getIndex().getType().isEntityType() ) { this.indexDescriptor = new CollectionIndexEntityImpl( this, convertEntity( creationContext, (EntityType) indexedCollection.getIndex().getType(), typeConfiguration ), columns ); } else { this.indexDescriptor = new CollectionIndexBasicImpl( this, convertBasic( (BasicType) indexedCollection.getIndex().getType(), typeConfiguration ), columns ); } } else { this.indexDescriptor = null; } final List<Column> elementColumns = Collections.emptyList(); if ( collectionBinding.getElement().getType().isAnyType() ) { throw new NotYetImplementedException( ); } else if ( collectionBinding.getElement().getType().isComponentType() ) { this.elementDescriptor = new CollectionElementEmbeddedImpl( this, convertComposite( creationContext, CollectionIndex.NAVIGABLE_NAME, (Component) collectionBinding.getElement(), this, typeConfiguration ), elementColumns ); } else if ( collectionBinding.getElement().getType().isEntityType() ) { this.elementDescriptor = new CollectionElementEntityImpl( this, convertEntity( creationContext, (EntityType) collectionBinding.getElement().getType(), typeConfiguration ), elementColumns ); } else { this.elementDescriptor = new CollectionElementBasicImpl( this, convertBasic( (BasicType) collectionBinding.getElement().getType(), typeConfiguration ), elementColumns ); } } @Override public String getRoleName() { return role; } @Override public CollectionKey getForeignKeyDescriptor() { return foreignKeyDescriptor; } @Override public CollectionId getIdDescriptor() { return idDescriptor; } @Override public org.hibernate.persister.collection.spi.CollectionIndex getIndexDescriptor() { return indexDescriptor; } @Override public CollectionClassification getCollectionClassification() { return collectionClassification; } @Override public org.hibernate.persister.collection.spi.CollectionElement getElementDescriptor() { return elementDescriptor; } @Override public String getRole() { return getRoleName(); } @Override public CollectionType getCollectionType() { return collectionClassification.toJpaClassification(); } @Override @SuppressWarnings("unchecked") public Type<E> getElementType() { return getElementDescriptor(); } @Override public PersistentAttributeType getPersistentAttributeType() { switch ( getElementDescriptor().getClassification() ) { case MANY_TO_MANY: { return PersistentAttributeType.MANY_TO_MANY; } case ONE_TO_MANY: { return PersistentAttributeType.ONE_TO_MANY; } default: { return PersistentAttributeType.ELEMENT_COLLECTION; } } } @Override public boolean isAssociation() { return false; } @Override public boolean isCollection() { return true; } @Override public BindableType getBindableType() { return BindableType.PLURAL_ATTRIBUTE; } @Override @SuppressWarnings("unchecked") public Class<E> getBindableJavaType() { return getElementDescriptor().getJavaType(); } @Override public String asLoggableText() { return null; } @Override public String getTypeName() { return null; } @Override public OrmNavigable findNavigable(String navigableName) { // only valid navigable-names are: // 1) "{index}" // 2) "{element}" if ( INDEX_NAVIGABLE_NAME.equals( navigableName ) ) { return getIndexDescriptor(); } else if ( ELEMENT_NAVIGABLE_NAME.equals( navigableName ) ) { return getElementDescriptor(); } throw new HibernateException( "Unrecognized navigable-name [" + navigableName + "]; relative to plural attribute only {index} and {element} are valid names" ); } @Override public List<JoinColumnMapping> resolveJoinColumnMappings(OrmAttribute attribute) { return Collections.emptyList(); } @Override public org.hibernate.orm.type.spi.CollectionType getOrmType() { return collectionType; } @Override public CollectionPersister<O, C, E> getCollectionPersister() { return null; } @Override public List<JoinColumnMapping> getJoinColumnMappings() { return null; } @Override public boolean canCompositeContainCollections() { return false; } @Override public String getRolePrefix() { return null; } @Override public PersistenceType getPersistenceType() { return null; } }