/* * 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.common.internal; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.AttributeConverter; import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Component; import org.hibernate.mapping.Value; import org.hibernate.orm.persister.collection.spi.CollectionPersister; import org.hibernate.orm.persister.common.spi.AbstractOrmAttribute; import org.hibernate.orm.persister.common.spi.Column; import org.hibernate.orm.persister.embeddable.spi.EmbeddableContainer; import org.hibernate.orm.persister.common.spi.ManagedTypeImplementor; import org.hibernate.orm.persister.common.spi.OrmAttribute; import org.hibernate.orm.persister.common.spi.OrmNavigableSource; import org.hibernate.orm.persister.common.spi.SingularAttribute; import org.hibernate.orm.persister.common.spi.Table; import org.hibernate.orm.persister.embeddable.spi.EmbeddableMapper; import org.hibernate.orm.persister.entity.spi.EntityPersister; import org.hibernate.orm.persister.spi.PersisterCreationContext; import org.hibernate.orm.type.descriptor.sql.spi.SqlTypeDescriptor; import org.hibernate.orm.type.spi.AnyType; import org.hibernate.orm.type.spi.BasicType; import org.hibernate.orm.type.spi.EmbeddedType; import org.hibernate.orm.type.spi.EntityType; import org.hibernate.orm.type.spi.Type; import org.hibernate.orm.type.spi.TypeConfiguration; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.query.sqm.NotYetImplementedException; import org.hibernate.query.sqm.domain.SqmPluralAttributeElement.ElementClassification; import org.hibernate.query.sqm.domain.SqmPluralAttribute.CollectionClassification; import org.hibernate.query.sqm.domain.SqmSingularAttribute.SingularAttributeClassification; import org.hibernate.query.sqm.tree.SqmPropertyPath; import org.hibernate.type.ArrayType; import org.hibernate.type.BagType; import org.hibernate.type.CollectionType; import org.hibernate.type.IdentifierBagType; import org.hibernate.type.ListType; import org.hibernate.type.MapType; import org.hibernate.type.OrderedMapType; import org.hibernate.type.OrderedSetType; import org.hibernate.type.SetType; import org.hibernate.type.SortedMapType; import org.hibernate.type.SortedSetType; /** * For now mainly a helper for reflection into stuff not exposed on the entity/collection persister * contracts * * @author Steve Ebersole */ public class PersisterHelper { /** * Singleton access */ public static final PersisterHelper INSTANCE = new PersisterHelper(); public Table getPropertyTable(EntityPersister persister, String attributeName, Table[] tables) { // todo : needed? throw new NotYetImplementedException( ); } public String[] getSubclassPropertyColumnExpressions(EntityPersister persister, int subclassPropertyNumber) { // todo : needed? throw new NotYetImplementedException( ); } public String[] getSubclassPropertyFormulaExpressions(EntityPersister persister, int subclassPropertyNumber) { // todo : needed? throw new NotYetImplementedException( ); } public static List<Column> makeValues( PersisterCreationContext creationContext, Table table, String[] columns, String[] formulas, // todo : SqlTypeDescriptor[] would be "best", but cannot currently resolve them. callers need TypeConfiguration int[] jdbcTypeCodes) { assert columns != null; assert formulas == null || columns.length == formulas.length; assert jdbcTypeCodes != null; assert jdbcTypeCodes.length == columns.length; final List<Column> values = new ArrayList<>(); for ( int i = 0; i < columns.length; i++ ) { if ( columns[i] != null ) { values.add( table.makeColumn( columns[i], jdbcTypeCodes[i] ) ); } else { if ( formulas == null ) { throw new IllegalStateException( "Column name was null and no formula information was supplied" ); } values.add( table.makeFormula( formulas[i], jdbcTypeCodes[i] ) ); } } return values; } public static List<Column> makeValues( SessionFactoryImplementor factory, // todo : SqlTypeDescriptor[] ? int[] would be enough for now, but SqlTypeDescriptor is nicer SqlTypeDescriptor[] typeDescriptors, String[] columns, String[] formulas, Table table) { assert columns != null; assert formulas == null || columns.length == formulas.length; assert typeDescriptors != null; assert typeDescriptors.length == columns.length; final List<Column> values = new ArrayList<>(); for ( int i = 0; i < columns.length; i++ ) { if ( columns[i] != null ) { values.add( table.makeColumn( columns[i], typeDescriptors[i].getSqlType() ) ); } else { if ( formulas == null ) { throw new IllegalStateException( "Column name was null and no formula information was supplied" ); } values.add( table.makeFormula( formulas[i], typeDescriptors[i].getSqlType() ) ); } } return values; } public OrmAttribute buildAttribute( PersisterCreationContext creationContext, OrmNavigableSource source, Value value, String propertyName, Type propertyType, List<Column> columns) { if ( propertyType instanceof org.hibernate.orm.type.spi.CollectionType ) { assert columns == null || columns.isEmpty(); return buildPluralAttribute( creationContext, (Collection) value, source, propertyName ); } else { return buildSingularAttribute( creationContext, source, value, propertyName, propertyType, columns ); } } public AbstractOrmAttribute buildSingularAttribute( PersisterCreationContext creationContext, OrmNavigableSource source, Value value, String attributeName, Type attributeType, List<Column> columns) { final SingularAttributeClassification classification = interpretSingularAttributeClassification( attributeType ); if ( classification == SingularAttributeClassification.ANY ) { throw new NotYetImplementedException(); } else if ( classification == SingularAttributeClassification.EMBEDDED ) { return new SingularAttributeEmbedded( (ManagedTypeImplementor) source, attributeName, PropertyAccess.DUMMY, SingularAttribute.Disposition.NORMAL, buildEmbeddablePersister( creationContext, (EmbeddableContainer) source, attributeName, (Component) value, columns ) ); } else if ( classification == SingularAttributeClassification.BASIC ) { // todo : need to be able to locate the AttributeConverter (if one) associated with this singular basic attribute // final AttributeConverter attributeConverter = ( (SimpleValue) value ).getAttributeConverterDescriptor().getAttributeConverter(); final AttributeConverter attributeConverter = null; return new SingularAttributeBasic( (ManagedTypeImplementor) source, attributeName, PropertyAccess.DUMMY, (BasicType) attributeType, SingularAttribute.Disposition.NORMAL, attributeConverter, columns ); } else { final EntityType ormEntityType = (EntityType) attributeType; return new SingularAttributeEntity( (ManagedTypeImplementor) source, attributeName, PropertyAccess.DUMMY, SingularAttribute.Disposition.NORMAL, classification, ormEntityType, columns ); } } public EmbeddableMapper buildEmbeddablePersister( PersisterCreationContext creationContext, EmbeddableContainer compositeContainer, String localName, Component component, List<Column> columns) { EmbeddableMapper mapper = creationContext.getTypeConfiguration() .findEmbeddableMapper( compositeContainer.getRolePrefix() + '.' + localName ); if ( mapper == null ) { mapper = creationContext.getPersisterFactory().createEmbeddablePersister( component, compositeContainer, localName, creationContext ); } return mapper; } public OrmAttribute buildPluralAttribute( PersisterCreationContext creationContext, Collection collectionBinding, OrmNavigableSource source, String propertyName) { // todo : resolve cache access final CollectionRegionAccessStrategy cachingAccess = null; // need PersisterCreationContext - we should always have access to that when building persisters, through finalized initialization final CollectionPersister collectionPersister = creationContext.getPersisterFactory().createCollectionPersister( collectionBinding, (ManagedTypeImplementor) source, propertyName, cachingAccess, creationContext ); creationContext.registerCollectionPersister( collectionPersister ); return collectionPersister; } public static org.hibernate.loader.PropertyPath convert(SqmPropertyPath propertyPath) { if ( propertyPath.getParent() == null ) { return new org.hibernate.loader.PropertyPath( null, propertyPath.getLocalPath() ); } org.hibernate.loader.PropertyPath parent = convert( propertyPath.getParent() ); return parent.append( propertyPath.getLocalPath() ); } public static CollectionClassification interpretCollectionClassification(Collection collection) { return interpretCollectionClassification( collection.getCollectionType() ); } public static interface CollectionMetadata { CollectionClassification getCollectionClassification(); ElementClassification getElementClassification(); Type getForeignKeyType(); BasicType getCollectionIdType(); Type getElementType(); Type getIndexType(); } public static class CollectionMetadataImpl implements CollectionMetadata { private final CollectionClassification collectionClassification; private final ElementClassification elementClassification; private final Type foreignKeyType; private final BasicType collectionIdType; private final Type elementType; private final Type indexType; public CollectionMetadataImpl( CollectionClassification collectionClassification, ElementClassification elementClassification, Type foreignKeyType, BasicType collectionIdType, Type elementType, Type indexType) { this.collectionClassification = collectionClassification; this.elementClassification = elementClassification; this.foreignKeyType = foreignKeyType; this.collectionIdType = collectionIdType; this.elementType = elementType; this.indexType = indexType; } @Override public CollectionClassification getCollectionClassification() { return collectionClassification; } @Override public ElementClassification getElementClassification() { return elementClassification; } @Override public Type getForeignKeyType() { return foreignKeyType; } @Override public BasicType getCollectionIdType() { return collectionIdType; } @Override public Type getElementType() { return elementType; } @Override public Type getIndexType() { return indexType; } } public static CollectionMetadata interpretCollectionMetadata(TypeConfiguration typeConfiguration, CollectionType collectionType) { throw new NotYetImplementedException(); // typeConfiguration.findCollectionPersister( ) // final CollectionPersister collectionPersister = factory.().collectionPersister( collectionType.getRole() ); // // return new CollectionMetadataImpl( // interpretCollectionClassification( collectionType ), // interpretElementClassification( collectionPersister ), // collectionPersister.getKeyType(), // (BasicType) collectionPersister.getIdentifierType(), // collectionPersister.getElementType(), // collectionPersister.getIndexType() // ); } public static CollectionClassification interpretCollectionClassification(CollectionType collectionType) { if ( collectionType instanceof BagType || collectionType instanceof IdentifierBagType ) { return CollectionClassification.BAG; } else if ( collectionType instanceof ListType || collectionType instanceof ArrayType ) { return CollectionClassification.LIST; } else if ( collectionType instanceof SetType || collectionType instanceof OrderedSetType || collectionType instanceof SortedSetType ) { return CollectionClassification.SET; } else if ( collectionType instanceof MapType || collectionType instanceof OrderedMapType || collectionType instanceof SortedMapType ) { return CollectionClassification.MAP; } else { final Class javaType = collectionType.getReturnedClass(); if ( Set.class.isAssignableFrom( javaType ) ) { return CollectionClassification.SET; } else if ( Map.class.isAssignableFrom( javaType ) ) { return CollectionClassification.MAP; } else if ( List.class.isAssignableFrom( javaType ) ) { return CollectionClassification.LIST; } return CollectionClassification.BAG; } } private static ElementClassification interpretElementClassification(CollectionPersister collectionPersister) { switch ( collectionPersister.getElementDescriptor().getClassification() ) { case ANY: { return ElementClassification.ANY; } case EMBEDDABLE: { return ElementClassification.EMBEDDABLE; } case ONE_TO_MANY: { return ElementClassification.ONE_TO_MANY; } case MANY_TO_MANY: { return ElementClassification.MANY_TO_MANY; } default: { return ElementClassification.BASIC; } } } public static SingularAttributeClassification interpretSingularAttributeClassification(Type attributeType) { if ( attributeType instanceof EntityType ) { // assume many-to-one for now... return SingularAttributeClassification.MANY_TO_ONE; } if ( attributeType instanceof EmbeddedType ) { return SingularAttributeClassification.EMBEDDED; } if ( attributeType instanceof AnyType ) { return SingularAttributeClassification.ANY; } return SingularAttributeClassification.BASIC; } public static SingularAttributeClassification interpretIdentifierClassification(Type ormIdType) { if ( ormIdType instanceof EmbeddedType ) { return SingularAttributeClassification.EMBEDDED; } else { return SingularAttributeClassification.BASIC; } } }