From 61c04a0b30706201f8effd9376c8e23488ec9133 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 23 Jul 2012 23:58:28 -0500 Subject: [PATCH] HHH-6159 - Create EntityManagerFactoryBuilder : integrate EntityManagerFactoryBuilder with metamodel codebase --- .../java/org/hibernate/boot/package-info.java | 0 .../boot/spi/CacheRegionDefinition.java | 81 ++ .../hibernate/boot/spi/JaccDefinition.java | 60 ++ .../org/hibernate/cfg/AvailableSettings.java | 31 + .../java/org/hibernate/cfg/Configuration.java | 2 +- .../org/hibernate/cfg/MetadataSourceType.java | 3 +- .../engine/spi/SessionFactoryImplementor.java | 8 + .../hibernate/internal/CoreMessageLogger.java | 15 + .../internal/SessionFactoryImpl.java | 33 +- .../util/config/ConfigurationHelper.java | 27 +- .../metamodel/internal/AbstractAttribute.java | 131 +++ .../internal/AbstractIdentifiableType.java | 317 ++++++ .../internal/AbstractManagedType.java | 479 +++++++++ .../jpa/metamodel/internal/AbstractType.java | 43 + .../jpa/metamodel/internal/BasicTypeImpl.java | 47 + .../internal/EmbeddableTypeImpl.java | 57 + .../metamodel/internal/EntityTypeImpl.java | 71 ++ .../JpaMetaModelPopulationSetting.java | 45 + .../internal/MappedSuperclassTypeImpl.java | 48 + .../jpa/metamodel/internal/MetamodelImpl.java | 121 +++ .../internal/PluralAttributeImpl.java | 223 ++++ .../internal/SingularAttributeImpl.java | 128 +++ .../internal/UnsupportedFeature.java | 44 + .../internal/builder/AttributeBuilder.java | 536 ++++++++++ .../internal/builder/AttributeMetadata.java | 93 ++ .../builder/AttributeTypeDescriptor.java | 62 ++ .../builder/BaseAttributeMetadata.java | 112 ++ .../internal/builder/MemberResolver.java | 47 + .../internal/builder/MetamodelBuilder.java | 392 +++++++ .../builder/PluralAttributeMetadata.java | 58 ++ .../builder/PluralAttributeMetadataImpl.java | 195 ++++ .../builder/SingularAttributeMetadata.java | 41 + .../SingularAttributeMetadataImpl.java | 88 ++ .../internal/legacy/AbstractAttribute.java | 142 +++ .../legacy/AbstractIdentifiableType.java | 318 ++++++ .../internal/legacy/AbstractManagedType.java | 529 ++++++++++ .../internal/legacy/AbstractType.java | 44 + .../internal/legacy/AttributeFactory.java | 979 ++++++++++++++++++ .../internal/legacy/AttributeImplementor.java | 33 + .../internal/legacy/BasicTypeImpl.java | 46 + .../internal/legacy/EmbeddableTypeImpl.java | 56 + .../internal/legacy/EntityTypeImpl.java | 68 ++ .../legacy/MappedSuperclassTypeImpl.java | 24 + .../internal/legacy/MetadataContext.java | 485 +++++++++ .../internal/legacy/MetamodelImpl.java | 238 +++++ .../internal/legacy/PluralAttributeImpl.java | 260 +++++ .../legacy/SingularAttributeImpl.java | 145 +++ .../hibernate/jpa/metamodel/package-info.java | 1 + .../java/org/hibernate/jpa/package-info.java | 1 + .../hibernate/metamodel/MetadataSources.java | 29 + .../hibernate/metamodel/internal/Binder.java | 15 +- ...AnnotationMetadataSourceProcessorImpl.java | 7 + .../source/hbm/ListAttributeIndexSource.java | 32 +- .../source/hbm/MapAttributeIndexSource.java | 151 ++- .../source/hbm/MapAttributeSource.java | 3 +- .../AbstractPluralAttributeBinding.java | 1 - .../binding/AttributeBindingContainer.java | 6 +- .../BasicPluralAttributeIndexBinding.java | 40 +- .../binding/CompositeAttributeBinding.java | 6 +- .../metamodel/spi/binding/EntityBinding.java | 6 +- .../metamodel/spi/binding/ListBinding.java | 2 +- .../metamodel/spi/binding/MapBinding.java | 6 +- .../spi/binding/PluralAttributeBinding.java | 1 - .../binding/PluralAttributeIndexBinding.java | 6 +- .../binding/PluralAttributeIndexNature.java | 48 + .../binding/PluralAttributeKeyBinding.java | 2 + .../source/PluralAttributeIndexNature.java | 38 + .../source/PluralAttributeIndexSource.java | 2 +- .../service/ServiceRegistryBuilder.java | 9 + .../org/hibernate/jpa/AvailableSettings.java | 39 +- .../EntityManagerFactoryBuilderImpl.java | 285 +---- ...nagerFactoryBuilderUsingMetamodelImpl.java | 661 ++++++++++++ .../org/hibernate/jpa/boot/spi/Bootstrap.java | 43 + .../JpaBootstrapServiceRegistryBuilder.java | 76 ++ .../boot/spi/JpaUnifiedSettingsBuilder.java | 251 +++++ .../internal/EntityManagerFactoryImpl.java | 54 +- .../internal/EntityManagerMessageLogger.java | 34 +- .../internal/util/SharedCacheModeHelper.java | 46 + .../jpa/test/criteria/QueryBuilderTest.java | 2 +- .../jpa/test/metadata/MetadataTest.java | 2 +- 80 files changed, 8431 insertions(+), 479 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/package-info.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/spi/CacheRegionDefinition.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/spi/JaccDefinition.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractAttribute.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractIdentifiableType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractManagedType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/BasicTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EmbeddableTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EntityTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/JpaMetaModelPopulationSetting.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MappedSuperclassTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MetamodelImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/PluralAttributeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/SingularAttributeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/UnsupportedFeature.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeBuilder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeMetadata.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeTypeDescriptor.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/BaseAttributeMetadata.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MemberResolver.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MetamodelBuilder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadata.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadataImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadata.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadataImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractAttribute.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractIdentifiableType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractManagedType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeFactory.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeImplementor.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/BasicTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EmbeddableTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EntityTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MappedSuperclassTypeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetadataContext.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetamodelImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/PluralAttributeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/SingularAttributeImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/metamodel/package-info.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/package-info.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexNature.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexNature.java create mode 100644 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderUsingMetamodelImpl.java create mode 100644 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaBootstrapServiceRegistryBuilder.java create mode 100644 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaUnifiedSettingsBuilder.java create mode 100644 hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/util/SharedCacheModeHelper.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/package-info.java b/hibernate-core/src/main/java/org/hibernate/boot/package-info.java new file mode 100644 index 0000000000..e69de29bb2 diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/CacheRegionDefinition.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/CacheRegionDefinition.java new file mode 100644 index 0000000000..4838e12cc7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/CacheRegionDefinition.java @@ -0,0 +1,81 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.boot.spi; + +/** + * Models the definition of caching settings for a particular region. Generally as found in either: + * Though certainly other custom sources are acceptable too. + * + * @author Steve Ebersole + */ +public class CacheRegionDefinition { + public static enum CacheRegionType { + ENTITY, + COLLECTION, + QUERY + } + + private final CacheRegionType regionType; + private final String role; + private final String usage; + private final String region; + private final boolean cacheLazy; + + public CacheRegionDefinition( + CacheRegionType cacheType, + String role, + String usage, + String region, + boolean cacheLazy) { + this.regionType = cacheType; + this.role = role; + this.usage = usage; + this.region = region; + this.cacheLazy = cacheLazy; + } + + public CacheRegionType getRegionType() { + return regionType; + } + + public String getRole() { + return role; + } + + public String getUsage() { + return usage; + } + + public String getRegion() { + return region; + } + + public boolean isCacheLazy() { + return cacheLazy; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/JaccDefinition.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/JaccDefinition.java new file mode 100644 index 0000000000..cc361f1b76 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/JaccDefinition.java @@ -0,0 +1,60 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.boot.spi; + +/** + * Models the definition of JACC-based security settings. Generally as found in {@code cfg.xml}, though certainly + * other custom sources are acceptable too. + * + * @author Steve Ebersole + */ +public class JaccDefinition { + private final String contextId; + private final String role; + private final String clazz; + private final String actions; + + public JaccDefinition(String contextId, String role, String clazz, String actions) { + this.contextId = contextId; + this.role = role; + this.clazz = clazz; + this.actions = actions; + } + + public String getContextId() { + return contextId; + } + + public String getRole() { + return role; + } + + public String getClazz() { + return clazz; + } + + public String getActions() { + return actions; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index ca1521be42..5fb625c077 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -602,4 +602,35 @@ public interface AvailableSettings { * */ public static final String INTERCEPTOR = "hibernate.sessionFactory.interceptor"; + + /** + * Setting which defines the order (and therefore precedence) in whcih Hibernate will process mapping information. + * Valid values include: + * + * Starting in 5.0 it is also valid to pass a value of {@link org.hibernate.metamodel.MetadataSourceProcessingOrder} + * which is an enum specifying which should be processed first. + */ + public static final String METADATA_PROCESSING_ORDER = "hibernate.mapping.precedence"; + + /** + * Setting that controls whether we seek out JPA "static metamodel" classes and populate them. Accepts + * 3 values: + */ + public static final String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population"; + } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java index 272241b070..c3da353492 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java @@ -182,7 +182,7 @@ public class Configuration implements Serializable { public static final String USE_NEW_ID_GENERATOR_MAPPINGS = AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS; - public static final String ARTEFACT_PROCESSING_ORDER = "hibernate.mapping.precedence"; + public static final String ARTEFACT_PROCESSING_ORDER = AvailableSettings.METADATA_PROCESSING_ORDER; /** * Class name of the class needed to enable Search. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/MetadataSourceType.java b/hibernate-core/src/main/java/org/hibernate/cfg/MetadataSourceType.java index 662dc53197..a7616704fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/MetadataSourceType.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/MetadataSourceType.java @@ -22,6 +22,7 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.cfg; + import org.hibernate.HibernateException; /** @@ -51,7 +52,7 @@ public String toString() { return name; } - static MetadataSourceType parsePrecedence(String value) { + public static MetadataSourceType parsePrecedence(String value) { if ( HBM.name.equalsIgnoreCase( value ) ) { return HBM; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java index 2d64f87ef2..cfe9ac6240 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java @@ -23,6 +23,7 @@ */ package org.hibernate.engine.spi; +import javax.persistence.metamodel.Metamodel; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -287,4 +288,11 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory { @Deprecated @SuppressWarnings("JavaDoc") public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver(); + + /** + * Obtain the JPA Metamodel instance. + * + * @since 5.0 + */ + public Metamodel getJpaMetamodel(); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 4cc0fd0986..8bac6f1bb5 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1574,4 +1574,19 @@ void cannotResolveNonNullableTransientDependencies(String transientEntityString, @LogMessage(level = INFO) @Message(value = "NaturalId queries executed to database: %s", id = 442) void naturalIdQueriesExecuted(long naturalIdQueriesExecutionCount); + + + // moved from hibernate-entitymanager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + @LogMessage( level = ERROR ) + @Message( value = "Illegal argument on static metamodel field injection : %s#%s; expected type : %s; encountered type : %s", id = 15007 ) + void illegalArgumentOnStaticMetamodelFieldInjection( String metamodelClassName, + String attributeName, + String attributeJavaType, + String metamodelFieldJavaType ); + + @LogMessage( level = ERROR ) + @Message( value = "Unable to locate static metamodel field : %s#%s", id = 15011 ) + void unableToLocateStaticMetamodelField( String metamodelClassName, + String attributeName ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 5ba21d5705..439484d74a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -25,6 +25,7 @@ import javax.naming.Reference; import javax.naming.StringRefAddr; +import javax.persistence.metamodel.Metamodel; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; @@ -111,9 +112,9 @@ import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.integrator.spi.Integrator; import org.hibernate.integrator.spi.IntegratorService; -import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.config.StrategyInstanceResolver; +import org.hibernate.jpa.metamodel.internal.JpaMetaModelPopulationSetting; +import org.hibernate.jpa.metamodel.internal.builder.MetamodelBuilder; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; @@ -211,6 +212,7 @@ public final class SessionFactoryImpl private final transient TypeHelper typeHelper; private final transient TransactionEnvironment transactionEnvironment; private final transient SessionFactoryOptions sessionFactoryOptions; + private final transient Metamodel jpaMetamodel; @SuppressWarnings( {"unchecked", "ThrowableResultOfMethodCallIgnored"}) public SessionFactoryImpl( @@ -600,6 +602,23 @@ public void sessionFactoryClosed(SessionFactory factory) { this.transactionEnvironment = new TransactionEnvironmentImpl( this ); this.observer.sessionFactoryCreated( this ); + + final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting = determineJpaMetaModelPopulationSetting( cfg ); + if ( jpaMetaModelPopulationSetting != JpaMetaModelPopulationSetting.DISABLED ) { + this.jpaMetamodel = org.hibernate.jpa.metamodel.internal.legacy.MetamodelImpl.buildMetamodel( + cfg.getClassMappings(), + this, + jpaMetaModelPopulationSetting == JpaMetaModelPopulationSetting.IGNORE_UNSUPPORTED + ); + } + else { + jpaMetamodel = null; + } + } + + protected JpaMetaModelPopulationSetting determineJpaMetaModelPopulationSetting(Configuration cfg) { + final String setting = cfg.getProperties().getProperty( AvailableSettings.JPA_METAMODEL_POPULATION ); + return JpaMetaModelPopulationSetting.parse( setting ); } @SuppressWarnings({ "unchecked" }) @@ -738,6 +757,8 @@ public void sessionFactoryClosed(SessionFactory factory) { // Prepare persisters and link them up with their cache // region/access-strategy + final MetamodelBuilder jpaMetamodelBuilder = new MetamodelBuilder( this ); + StringBuilder stringBuilder = new StringBuilder(); if ( settings.getCacheRegionPrefix() != null) { stringBuilder @@ -816,6 +837,7 @@ public void sessionFactoryClosed(SessionFactory factory) { ); entityPersisters.put( model.getEntity().getName(), cp ); classMeta.put( model.getEntity().getName(), cp.getClassMetadata() ); + jpaMetamodelBuilder.add( model ); } this.classMetadata = Collections.unmodifiableMap(classMeta); @@ -996,6 +1018,8 @@ public void sessionFactoryClosed(SessionFactory factory) { this.transactionEnvironment = new TransactionEnvironmentImpl( this ); this.observer.sessionFactoryCreated( this ); + + this.jpaMetamodel = jpaMetamodelBuilder.buildMetamodel(); } @SuppressWarnings( {"unchecked"} ) @@ -1779,6 +1803,11 @@ public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver() { return sessionFactoryOptions.getCurrentTenantIdentifierResolver(); } + @Override + public Metamodel getJpaMetamodel() { + return jpaMetamodel; + } + // Serialization handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/config/ConfigurationHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/config/ConfigurationHelper.java index 924961c17e..e727a1093b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/config/ConfigurationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/config/ConfigurationHelper.java @@ -57,14 +57,13 @@ private ConfigurationHelper() { * @return The value, or null if not found */ public static String getString(String name, Map values) { - Object value = values.get( name ); - if ( value == null ) { - return null; - } - if ( String.class.isInstance( value ) ) { - return (String) value; - } - return value.toString(); + return asString( values.get( name ) ); + } + + public static String asString(Object value) { + return value == null + ? null + : value.toString(); } /** @@ -118,6 +117,18 @@ public static boolean getBoolean(String name, Map values, boolean defaultValue) ); } + public static Boolean asBoolean(Object value) { + if ( value == null ) { + return null; + } + if ( Boolean.class.isInstance( value ) ) { + return ( (Boolean) value ); + } + else { + return Boolean.valueOf( value.toString() ); + } + } + /** * Get the config value as an int * diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractAttribute.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractAttribute.java new file mode 100644 index 0000000000..6f962fce0d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractAttribute.java @@ -0,0 +1,131 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.ManagedType; + +import org.hibernate.internal.util.ReflectHelper; + +/** + * Models the commonality of the JPA {@link Attribute} hierarchy. + * + * @author Steve Ebersole + */ +public abstract class AbstractAttribute implements Attribute, Serializable { + private final String name; + private final Class javaType; + private final AbstractManagedType declaringType; + private transient Member member; + private final PersistentAttributeType persistentAttributeType; + + public AbstractAttribute( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + PersistentAttributeType persistentAttributeType) { + this.name = name; + this.javaType = javaType; + this.declaringType = declaringType; + this.member = member; + this.persistentAttributeType = persistentAttributeType; + } + + @Override + public String getName() { + return name; + } + + @Override + public ManagedType getDeclaringType() { + return declaringType; + } + + @Override + public Class getJavaType() { + return javaType; + } + + @Override + public Member getJavaMember() { + return member; + } + + @Override + public PersistentAttributeType getPersistentAttributeType() { + return persistentAttributeType; + } + + /** + * Used by JDK serialization... + * + * @param oos The output stream to which we are being written... + * @throws IOException Indicates a general IO stream exception + */ + protected void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + oos.writeObject( getJavaMember().getDeclaringClass().getName() ); + oos.writeObject( getJavaMember().getName() ); + // should only ever be a field or the getter-method... + oos.writeObject( Method.class.isInstance( getJavaMember() ) ? "method" : "field" ); + } + + /** + * Used by JDK serialization... + * + * @param ois The input stream from which we are being read... + * @throws java.io.IOException Indicates a general IO stream exception + * @throws ClassNotFoundException Indicates a class resolution issue + */ + protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + final String memberDeclaringClassName = ( String ) ois.readObject(); + final String memberName = ( String ) ois.readObject(); + final String memberType = ( String ) ois.readObject(); + + final Class memberDeclaringClass = Class.forName( + memberDeclaringClassName, + false, + declaringType.getJavaType().getClassLoader() + ); + try { + this.member = "method".equals( memberType ) + ? memberDeclaringClass.getMethod( memberName, ReflectHelper.NO_PARAM_SIGNATURE ) + : memberDeclaringClass.getField( memberName ); + } + catch ( Exception e ) { + throw new IllegalStateException( + "Unable to locate member [" + memberDeclaringClassName + "#" + + memberName + "]" + ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractIdentifiableType.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractIdentifiableType.java new file mode 100644 index 0000000000..2a04634ec5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractIdentifiableType.java @@ -0,0 +1,317 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.IdentifiableType; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type; + +/** + * Defines commonality for the JPA {@link IdentifiableType} types. JPA defines + * identifiable types as entities or mapped-superclasses. Basically things to which an + * identifier can be attached. + *

+ * NOTE : Currently we only really have support for direct entities in the Hibernate metamodel + * as the information for them is consumed into the closest actual entity subclass(es) in the + * internal Hibernate mapping-metamodel. + * + * @author Steve Ebersole + */ +public abstract class AbstractIdentifiableType + extends AbstractManagedType + implements IdentifiableType, Serializable { + + private final boolean hasIdentifierProperty; + private final boolean isVersioned; + + private SingularAttributeImpl id; + private SingularAttributeImpl version; + private Set> idClassAttributes; + + public AbstractIdentifiableType( + Class javaType, + AbstractIdentifiableType superType, + boolean hasIdentifierProperty, + boolean versioned) { + super( javaType, superType ); + this.hasIdentifierProperty = hasIdentifierProperty; + isVersioned = versioned; + } + + /** + * {@inheritDoc} + */ + public AbstractIdentifiableType getSupertype() { + return ( AbstractIdentifiableType ) super.getSupertype(); + } + + /** + * Indicates if a non-null super type is required to provide the + * identifier attribute(s) if this object does not have a declared + * identifier. + * . + * @return true, if a non-null super type is required to provide + * the identifier attribute(s) if this object does not have a + * declared identifier; false, otherwise. + */ + protected abstract boolean requiresSupertypeForNonDeclaredIdentifier(); + + protected AbstractIdentifiableType requireSupertype() { + if ( getSupertype() == null ) { + throw new IllegalStateException( "No supertype found" ); + } + return getSupertype(); + } + + /** + * {@inheritDoc} + */ + public boolean hasSingleIdAttribute() { + return hasIdentifierProperty; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getId(Class javaType) { + final SingularAttribute id_; + if ( id != null ) { + checkSimpleId(); + id_ = ( SingularAttribute ) id; + if ( javaType != id.getJavaType() ) { + throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() ); + } + } + else { + //yuk yuk bad me + if ( ! requiresSupertypeForNonDeclaredIdentifier()) { + final AbstractIdentifiableType supertype = getSupertype(); + if (supertype != null) { + id_ = supertype.getId( javaType ); + } + else { + id_ = null; + } + } + else { + id_ = requireSupertype().getId( javaType ); + } + } + return id_; + } + + /** + * Centralized check to ensure the id for this hierarchy is a simple one (i.e., does not use + * an id-class). + * + * @see #checkIdClass() + */ + protected void checkSimpleId() { + if ( ! hasIdentifierProperty ) { + throw new IllegalStateException( "This class uses an @IdClass" ); + } + } + + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getDeclaredId(Class javaType) { + checkDeclaredId(); + checkSimpleId(); + if ( javaType != id.getJavaType() ) { + throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() ); + } + return (SingularAttribute) id; + } + + /** + * Centralized check to ensure the id is actually declared on the class mapped here, as opposed to a + * super class. + */ + protected void checkDeclaredId() { + if ( id == null ) { + throw new IllegalArgumentException( "The id attribute is not declared on this type" ); + } + } + + /** + * {@inheritDoc} + */ + public Type getIdType() { + if ( id != null ) { + checkSimpleId(); + return id.getType(); + } + else { + return requireSupertype().getIdType(); + } + } + + private boolean hasIdClassAttributesDefined() { + return idClassAttributes != null || + ( getSupertype() != null && getSupertype().hasIdClassAttributesDefined() ); + } + + /** + * {@inheritDoc} + */ + public Set> getIdClassAttributes() { + if ( idClassAttributes != null ) { + checkIdClass(); + } + else { + // Java does not allow casting requireSupertype().getIdClassAttributes() + // to Set> because the + // superclass X is a different Java type from this X + // (i.e, getSupertype().getJavaType() != getJavaType()). + // It will, however, allow a Set> + // to be initialized with requireSupertype().getIdClassAttributes(), + // since getSupertype().getJavaType() is a superclass of getJavaType() + if ( requiresSupertypeForNonDeclaredIdentifier() ) { + idClassAttributes = new HashSet>( requireSupertype().getIdClassAttributes() ); + } + else if ( getSupertype() != null && hasIdClassAttributesDefined() ) { + idClassAttributes = new HashSet>( getSupertype().getIdClassAttributes() ); + } + } + return idClassAttributes; + } + + /** + * Centralized check to ensure the id for this hierarchy uses an id-class. + * + * @see #checkSimpleId() + */ + private void checkIdClass() { + if ( hasIdentifierProperty ) { + throw new IllegalArgumentException( "This class does not use @IdClass" ); + } + } + + /** + * {@inheritDoc} + */ + public boolean hasVersionAttribute() { + return isVersioned; + } + + public boolean hasDeclaredVersionAttribute() { + return isVersioned && version != null; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getVersion(Class javaType) { + if ( ! hasVersionAttribute() ) { + return null; + } + final SingularAttribute version_; + if ( version != null ) { + version_ = ( SingularAttribute ) version; + if ( javaType != version.getJavaType() ) { + throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() ); + } + } + else { + version_ = requireSupertype().getVersion( javaType ); + } + return version_; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getDeclaredVersion(Class javaType) { + checkDeclaredVersion(); + if ( javaType != version.getJavaType() ) { + throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() ); + } + return ( SingularAttribute ) version; + } + + /** + * For used to retrieve the declared version when populating the static metamodel. + * + * @return The declared + */ + public SingularAttribute getDeclaredVersion() { + checkDeclaredVersion(); + return version; + } + + /** + * Centralized check to ensure the version (if one) is actually declared on the class mapped here, as opposed to a + * super class. + */ + protected void checkDeclaredVersion() { + if ( version == null || ( getSupertype() != null && getSupertype().hasVersionAttribute() )) { + throw new IllegalArgumentException( "The version attribute is not declared on this type" ); + } + } + + public Builder getBuilder() { + final AbstractManagedType.Builder managedBuilder = super.getBuilder(); + return new Builder() { + public void applyIdAttribute(SingularAttributeImpl idAttribute) { + AbstractIdentifiableType.this.id = idAttribute; + managedBuilder.addAttribute( idAttribute ); + } + + public void applyIdClassAttributes(Set> idClassAttributes) { + for ( SingularAttribute idClassAttribute : idClassAttributes ) { + if ( AbstractIdentifiableType.this == idClassAttribute.getDeclaringType() ) { + @SuppressWarnings({ "unchecked" }) + SingularAttribute declaredAttribute = ( SingularAttribute ) idClassAttribute; + addAttribute( declaredAttribute ); + } + } + AbstractIdentifiableType.this.idClassAttributes = idClassAttributes; + } + + public void applyVersionAttribute(SingularAttributeImpl versionAttribute) { + AbstractIdentifiableType.this.version = versionAttribute; + managedBuilder.addAttribute( versionAttribute ); + } + + public void addAttribute(Attribute attribute) { + managedBuilder.addAttribute( attribute ); + } + }; + } + + public static interface Builder extends AbstractManagedType.Builder { + public void applyIdAttribute(SingularAttributeImpl idAttribute); + public void applyIdClassAttributes(Set> idClassAttributes); + public void applyVersionAttribute(SingularAttributeImpl versionAttribute); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractManagedType.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractManagedType.java new file mode 100644 index 0000000000..7634bc5d3b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractManagedType.java @@ -0,0 +1,479 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Bindable; +import javax.persistence.metamodel.CollectionAttribute; +import javax.persistence.metamodel.ListAttribute; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SetAttribute; +import javax.persistence.metamodel.SingularAttribute; + +import org.hibernate.annotations.common.AssertionFailure; + +/** + * Defines commonality for the JPA {@link ManagedType} hierarchy of interfaces. + * + * @author Steve Ebersole + */ +public abstract class AbstractManagedType + extends AbstractType + implements ManagedType, Serializable { + + private final AbstractManagedType superType; + + private final Map> declaredAttributes + = new HashMap>(); + private final Map> declaredSingularAttributes + = new HashMap>(); + private final Map> declaredPluralAttributes + = new HashMap>(); + + protected AbstractManagedType(Class javaType, AbstractManagedType superType) { + super( javaType ); + this.superType = superType; + } + + public AbstractManagedType getSupertype() { + return superType; + } + + private boolean locked = false; + + public Builder getBuilder() { + if ( locked ) { + throw new IllegalStateException( "Type has been locked" ); + } + return new Builder() { + public void addAttribute(Attribute attribute) { + declaredAttributes.put( attribute.getName(), attribute ); + final Bindable.BindableType bindableType = ( ( Bindable ) attribute ).getBindableType(); + switch ( bindableType ) { + case SINGULAR_ATTRIBUTE : { + declaredSingularAttributes.put( attribute.getName(), (SingularAttribute) attribute ); + break; + } + case PLURAL_ATTRIBUTE : { + declaredPluralAttributes.put(attribute.getName(), (PluralAttribute) attribute ); + break; + } + default : { + throw new AssertionFailure( "unknown bindable type: " + bindableType ); + } + } + } + }; + } + + public void lock() { + locked = true; + } + + public static interface Builder { + public void addAttribute(Attribute attribute); + } + + + @Override + @SuppressWarnings({ "unchecked" }) + public Set> getAttributes() { + HashSet attributes = new HashSet>( declaredAttributes.values() ); + if ( getSupertype() != null ) { + attributes.addAll( getSupertype().getAttributes() ); + } + return attributes; + } + + @Override + public Set> getDeclaredAttributes() { + return new HashSet>( declaredAttributes.values() ); + } + + @Override + @SuppressWarnings({ "unchecked" }) + public Attribute getAttribute(String name) { + Attribute attribute = declaredAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getAttribute( name ); + } + return attribute; + } + + @Override + public Attribute getDeclaredAttribute(String name) { + final Attribute attr = declaredSingularAttributes.get( name ); + checkNotNull( "Attribute ", attr, name ); + return attr; + } + + private void checkNotNull(String attributeType, Attribute attribute, String name) { + if ( attribute == null ) { + throw new IllegalArgumentException( attributeType + " named " + name + " is not present" ); + } + } + + @Override + @SuppressWarnings({ "unchecked" }) + public Set> getSingularAttributes() { + HashSet attributes = new HashSet>( declaredSingularAttributes.values() ); + if ( getSupertype() != null ) { + attributes.addAll( getSupertype().getSingularAttributes() ); + } + return attributes; + } + + @Override + public Set> getDeclaredSingularAttributes() { + return new HashSet>( declaredSingularAttributes.values() ); + } + + @Override + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getSingularAttribute(String name) { + SingularAttribute attribute = declaredSingularAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getSingularAttribute( name ); + } + return attribute; + } + + @Override + public SingularAttribute getDeclaredSingularAttribute(String name) { + final SingularAttribute attr = declaredSingularAttributes.get( name ); + checkNotNull( "SingularAttribute ", attr, name ); + return attr; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getSingularAttribute(String name, Class type) { + SingularAttribute attribute = declaredSingularAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getSingularAttribute( name ); + } + checkTypeForSingleAttribute( "SingularAttribute ", attribute, name, type ); + return ( SingularAttribute ) attribute; + } + + @Override + @SuppressWarnings( "unchecked") + public SingularAttribute getDeclaredSingularAttribute(String name, Class javaType) { + final SingularAttribute attr = declaredSingularAttributes.get( name ); + checkTypeForSingleAttribute( "SingularAttribute ", attr, name, javaType ); + return ( SingularAttribute ) attr; + } + + private void checkTypeForSingleAttribute( + String attributeType, + SingularAttribute attribute, + String name, + Class javaType) { + if ( attribute == null || ( javaType != null && !attribute.getBindableJavaType().equals( javaType ) ) ) { + if ( isPrimitiveVariant( attribute, javaType ) ) { + return; + } + throw new IllegalArgumentException( + attributeType + " named " + name + + ( javaType != null ? " and of type " + javaType.getName() : "" ) + + " is not present" + ); + } + } + + @SuppressWarnings({ "SimplifiableIfStatement" }) + protected boolean isPrimitiveVariant(SingularAttribute attribute, Class javaType) { + if ( attribute == null ) { + return false; + } + Class declaredType = attribute.getBindableJavaType(); + + if ( declaredType.isPrimitive() ) { + return ( Boolean.class.equals( javaType ) && Boolean.TYPE.equals( declaredType ) ) + || ( Character.class.equals( javaType ) && Character.TYPE.equals( declaredType ) ) + || ( Byte.class.equals( javaType ) && Byte.TYPE.equals( declaredType ) ) + || ( Short.class.equals( javaType ) && Short.TYPE.equals( declaredType ) ) + || ( Integer.class.equals( javaType ) && Integer.TYPE.equals( declaredType ) ) + || ( Long.class.equals( javaType ) && Long.TYPE.equals( declaredType ) ) + || ( Float.class.equals( javaType ) && Float.TYPE.equals( declaredType ) ) + || ( Double.class.equals( javaType ) && Double.TYPE.equals( declaredType ) ); + } + + if ( javaType.isPrimitive() ) { + return ( Boolean.class.equals( declaredType ) && Boolean.TYPE.equals( javaType ) ) + || ( Character.class.equals( declaredType ) && Character.TYPE.equals( javaType ) ) + || ( Byte.class.equals( declaredType ) && Byte.TYPE.equals( javaType ) ) + || ( Short.class.equals( declaredType ) && Short.TYPE.equals( javaType ) ) + || ( Integer.class.equals( declaredType ) && Integer.TYPE.equals( javaType ) ) + || ( Long.class.equals( declaredType ) && Long.TYPE.equals( javaType ) ) + || ( Float.class.equals( declaredType ) && Float.TYPE.equals( javaType ) ) + || ( Double.class.equals( declaredType ) && Double.TYPE.equals( javaType ) ); + } + + return false; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public Set> getPluralAttributes() { + HashSet attributes = new HashSet>( declaredPluralAttributes.values() ); + if ( getSupertype() != null ) { + attributes.addAll( getSupertype().getPluralAttributes() ); + } + return attributes; + } + + @Override + public Set> getDeclaredPluralAttributes() { + return new HashSet>( declaredPluralAttributes.values() ); + } + + @Override + @SuppressWarnings({ "unchecked" }) + public CollectionAttribute getCollection(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicCollectionCheck( attribute, name ); + return ( CollectionAttribute ) attribute; + } + + private PluralAttribute getPluralAttribute(String name) { + return declaredPluralAttributes.get( name ); + } + + private void basicCollectionCheck(PluralAttribute attribute, String name) { + checkNotNull( "CollectionAttribute", attribute, name ); + if ( ! CollectionAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a CollectionAttribute: " + attribute.getClass() ); + } + } + + @Override + @SuppressWarnings( "unchecked") + public CollectionAttribute getDeclaredCollection(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicCollectionCheck( attribute, name ); + return ( CollectionAttribute ) attribute; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public SetAttribute getSet(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicSetCheck( attribute, name ); + return (SetAttribute) attribute; + } + + private void basicSetCheck(PluralAttribute attribute, String name) { + checkNotNull( "SetAttribute", attribute, name ); + if ( ! SetAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a SetAttribute: " + attribute.getClass() ); + } + } + + @Override + @SuppressWarnings( "unchecked") + public SetAttribute getDeclaredSet(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicSetCheck( attribute, name ); + return ( SetAttribute ) attribute; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public ListAttribute getList(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicListCheck( attribute, name ); + return (ListAttribute) attribute; + } + + private void basicListCheck(PluralAttribute attribute, String name) { + checkNotNull( "ListAttribute", attribute, name ); + if ( ! ListAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a ListAttribute: " + attribute.getClass() ); + } + } + + @Override + public ListAttribute getDeclaredList(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicListCheck( attribute, name ); + return ( ListAttribute ) attribute; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public MapAttribute getMap(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicMapCheck( attribute, name ); + return (MapAttribute) attribute; + } + + private void basicMapCheck(PluralAttribute attribute, String name) { + checkNotNull( "MapAttribute", attribute, name ); + if ( ! MapAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a MapAttribute: " + attribute.getClass() ); + } + } + + @Override + public MapAttribute getDeclaredMap(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicMapCheck( attribute, name ); + return ( MapAttribute ) attribute; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public CollectionAttribute getCollection(String name, Class elementType) { + PluralAttribute attribute = declaredPluralAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkCollectionElementType( attribute, name, elementType ); + return ( CollectionAttribute ) attribute; + } + + @Override + public CollectionAttribute getDeclaredCollection(String name, Class elementType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkCollectionElementType( attribute, name, elementType ); + return ( CollectionAttribute ) attribute; + } + + private void checkCollectionElementType(PluralAttribute attribute, String name, Class elementType) { + checkTypeForPluralAttributes( "CollectionAttribute", attribute, name, elementType, PluralAttribute.CollectionType.COLLECTION ); + } + + private void checkTypeForPluralAttributes( + String attributeType, + PluralAttribute attribute, + String name, + Class elementType, + PluralAttribute.CollectionType collectionType) { + if ( attribute == null + || ( elementType != null && !attribute.getBindableJavaType().equals( elementType ) ) + || attribute.getCollectionType() != collectionType ) { + throw new IllegalArgumentException( + attributeType + " named " + name + + ( elementType != null ? " and of element type " + elementType : "" ) + + " is not present" + ); + } + } + + @Override + @SuppressWarnings({ "unchecked" }) + public SetAttribute getSet(String name, Class elementType) { + PluralAttribute attribute = declaredPluralAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkSetElementType( attribute, name, elementType ); + return ( SetAttribute ) attribute; + } + + private void checkSetElementType(PluralAttribute attribute, String name, Class elementType) { + checkTypeForPluralAttributes( "SetAttribute", attribute, name, elementType, PluralAttribute.CollectionType.SET ); + } + + @Override + public SetAttribute getDeclaredSet(String name, Class elementType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkSetElementType( attribute, name, elementType ); + return ( SetAttribute ) attribute; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public ListAttribute getList(String name, Class elementType) { + PluralAttribute attribute = declaredPluralAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkListElementType( attribute, name, elementType ); + return ( ListAttribute ) attribute; + } + + private void checkListElementType(PluralAttribute attribute, String name, Class elementType) { + checkTypeForPluralAttributes( "ListAttribute", attribute, name, elementType, PluralAttribute.CollectionType.LIST ); + } + + @Override + public ListAttribute getDeclaredList(String name, Class elementType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkListElementType( attribute, name, elementType ); + return ( ListAttribute ) attribute; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public MapAttribute getMap(String name, Class keyType, Class valueType) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkMapValueType( attribute, name, valueType ); + final MapAttribute mapAttribute = ( MapAttribute ) attribute; + checkMapKeyType( mapAttribute, name, keyType ); + return mapAttribute; + } + + private void checkMapValueType(PluralAttribute attribute, String name, Class valueType) { + checkTypeForPluralAttributes( "MapAttribute", attribute, name, valueType, PluralAttribute.CollectionType.MAP); + } + + private void checkMapKeyType(MapAttribute mapAttribute, String name, Class keyType) { + if ( mapAttribute.getKeyJavaType() != keyType ) { + throw new IllegalArgumentException( "MapAttribute named " + name + " does not support a key of type " + keyType ); + } + } + + @Override + public MapAttribute getDeclaredMap(String name, Class keyType, Class valueType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkMapValueType( attribute, name, valueType ); + final MapAttribute mapAttribute = ( MapAttribute ) attribute; + checkMapKeyType( mapAttribute, name, keyType ); + return mapAttribute; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractType.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractType.java new file mode 100644 index 0000000000..f8069c91f8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/AbstractType.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal; +import java.io.Serializable; +import javax.persistence.metamodel.Type; + +/** + * Defines commonality for the JPA {@link Type} hierarchy of interfaces. + * + * @author Steve Ebersole + */ +public abstract class AbstractType implements Type, Serializable { + private final Class javaType; + + public AbstractType(Class javaType) { + this.javaType = javaType; + } + + public Class getJavaType() { + return javaType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/BasicTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/BasicTypeImpl.java new file mode 100644 index 0000000000..c7e9cc4f3f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/BasicTypeImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal; +import java.io.Serializable; +import javax.persistence.metamodel.BasicType; + +/** + * @author Emmanuel Bernard + */ +public class BasicTypeImpl implements BasicType, Serializable { + private final Class clazz; + private PersistenceType persistenceType; + + @Override + public PersistenceType getPersistenceType() { + return persistenceType; + } + + @Override + public Class getJavaType() { + return clazz; + } + + public BasicTypeImpl(Class clazz, PersistenceType persistenceType) { + this.clazz = clazz; + this.persistenceType = persistenceType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EmbeddableTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EmbeddableTypeImpl.java new file mode 100644 index 0000000000..e12e492104 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EmbeddableTypeImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal; + +import java.io.Serializable; +import javax.persistence.metamodel.EmbeddableType; + +import org.hibernate.type.ComponentType; + +/** + * @author Emmanuel Bernard + */ +public class EmbeddableTypeImpl + extends AbstractManagedType + implements EmbeddableType, Serializable { + + private final AbstractManagedType parent; + private final ComponentType hibernateType; + + public EmbeddableTypeImpl(Class javaType, AbstractManagedType parent, ComponentType hibernateType) { + super( javaType, null ); + this.parent = parent; + this.hibernateType = hibernateType; + } + + @Override + public PersistenceType getPersistenceType() { + return PersistenceType.EMBEDDABLE; + } + + public AbstractManagedType getParent() { + return parent; + } + + public ComponentType getHibernateType() { + return hibernateType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EntityTypeImpl.java new file mode 100644 index 0000000000..4a57088836 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/EntityTypeImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal; +import java.io.Serializable; +import javax.persistence.metamodel.EntityType; + +/** + * Defines the Hibernate implementation of the JPA {@link EntityType} contract. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class EntityTypeImpl + extends AbstractIdentifiableType + implements EntityType, Serializable { + private final String jpaEntityName; + + public EntityTypeImpl( + Class javaType, + AbstractIdentifiableType superType, + String jpaEntityName, + boolean hasIdentifierProperty, + boolean isVersioned) { + super( javaType, superType, hasIdentifierProperty, isVersioned ); + this.jpaEntityName = jpaEntityName; + } + + @Override + public String getName() { + return jpaEntityName; + } + + @Override + public BindableType getBindableType() { + return BindableType.ENTITY_TYPE; + } + + @Override + public Class getBindableJavaType() { + return getJavaType(); + } + + @Override + public PersistenceType getPersistenceType() { + return PersistenceType.ENTITY; + } + + @Override + protected boolean requiresSupertypeForNonDeclaredIdentifier() { + return true; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/JpaMetaModelPopulationSetting.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/JpaMetaModelPopulationSetting.java new file mode 100644 index 0000000000..1b5836555c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/JpaMetaModelPopulationSetting.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal; + +/** +* @author Steve Ebersole +*/ +public enum JpaMetaModelPopulationSetting { + ENABLED, + DISABLED, + IGNORE_UNSUPPORTED; + + public static JpaMetaModelPopulationSetting parse(String setting) { + if ( "enabled".equalsIgnoreCase( setting ) ) { + return ENABLED; + } + else if ( "disabled".equalsIgnoreCase( setting ) ) { + return DISABLED; + } + else { + return IGNORE_UNSUPPORTED; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MappedSuperclassTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MappedSuperclassTypeImpl.java new file mode 100644 index 0000000000..ccd6706f89 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MappedSuperclassTypeImpl.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal; + +import javax.persistence.metamodel.MappedSuperclassType; + +/** + * @author Emmanuel Bernard + */ +public class MappedSuperclassTypeImpl extends AbstractIdentifiableType implements MappedSuperclassType { + public MappedSuperclassTypeImpl( + Class javaType, + AbstractIdentifiableType superType, + boolean hasIdentifierProperty, + boolean versioned) { + super( javaType, superType, hasIdentifierProperty, versioned ); + } + + public PersistenceType getPersistenceType() { + return PersistenceType.MAPPED_SUPERCLASS; + } + + @Override + protected boolean requiresSupertypeForNonDeclaredIdentifier() { + return false; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MetamodelImpl.java new file mode 100644 index 0000000000..5bde4e525e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/MetamodelImpl.java @@ -0,0 +1,121 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal; + +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.Metamodel; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.hibernate.internal.util.collections.CollectionHelper; + +/** + * Hibernate implementation of the JPA {@link javax.persistence.metamodel.Metamodel} contract. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class MetamodelImpl implements Metamodel, Serializable { + private final Map, EntityTypeImpl> entityTypeMap; + private final Map, MappedSuperclassTypeImpl> mappedSuperclassTypeMap; + private final Map, EmbeddableTypeImpl> embeddableTypeMap; + + /** + * Instantiate the metamodel. + * + * @param entityTypeMap The entity mappings. + * @param mappedSuperclassTypeMap The {@link javax.persistence.MappedSuperclass} mappings + * @param embeddableTypeMap The embeddable (component) mappings. + */ + public MetamodelImpl( + Map, EntityTypeImpl> entityTypeMap, + Map, MappedSuperclassTypeImpl> mappedSuperclassTypeMap, + Map, EmbeddableTypeImpl> embeddableTypeMap) { + this.entityTypeMap = entityTypeMap; + this.mappedSuperclassTypeMap = mappedSuperclassTypeMap; + this.embeddableTypeMap = embeddableTypeMap; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public EntityType entity(Class cls) { + final EntityType entityType = entityTypeMap.get( cls ); + if ( entityType == null ) { + throw new IllegalArgumentException( "Not an entity: " + cls ); + } + return (EntityType) entityType; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public ManagedType managedType(Class cls) { + ManagedType type = entityTypeMap.get( cls ); + if ( type == null ) { + type = mappedSuperclassTypeMap.get( cls ); + } + if ( type == null ) { + type = embeddableTypeMap.get( cls ); + } + if ( type == null ) { + throw new IllegalArgumentException( "Not an managed type: " + cls ); + } + return (ManagedType) type; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public EmbeddableType embeddable(Class cls) { + final EmbeddableType embeddableType = embeddableTypeMap.get( cls ); + if ( embeddableType == null ) { + throw new IllegalArgumentException( "Not an embeddable: " + cls ); + } + return (EmbeddableType) embeddableType; + } + + @Override + public Set> getManagedTypes() { + final int setSize = CollectionHelper.determineProperSizing( + entityTypeMap.size() + mappedSuperclassTypeMap.size() + embeddableTypeMap.size() + ); + final Set> managedTypes = new HashSet>( setSize ); + managedTypes.addAll( entityTypeMap.values() ); + managedTypes.addAll( mappedSuperclassTypeMap.values() ); + managedTypes.addAll( embeddableTypeMap.values() ); + return managedTypes; + } + + @Override + public Set> getEntities() { + return new HashSet>( entityTypeMap.values() ); + } + + @Override + public Set> getEmbeddables() { + return new HashSet>( embeddableTypeMap.values() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/PluralAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/PluralAttributeImpl.java new file mode 100644 index 0000000000..466e91234d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/PluralAttributeImpl.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal; + +import java.io.Serializable; +import java.lang.reflect.Member; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.persistence.metamodel.CollectionAttribute; +import javax.persistence.metamodel.ListAttribute; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SetAttribute; +import javax.persistence.metamodel.Type; + +import org.hibernate.metamodel.spi.binding.PluralAttributeBinding; + +/** + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public abstract class PluralAttributeImpl + extends AbstractAttribute + implements PluralAttribute, Serializable { + + private final Type elementType; + + @SuppressWarnings("unchecked") + private PluralAttributeImpl(Builder builder) { + super( + builder.attributeBinding.getAttribute().getName(), + builder.collectionClass, + builder.owner, + builder.member, + builder.persistentAttributeType + ); + this.elementType = builder.elementType; + } + + public static class Builder { + private final Class collectionClass; + private AbstractManagedType owner; + private PluralAttributeBinding attributeBinding; + private Member member; + private Type keyType; + private Type elementType; + private PersistentAttributeType persistentAttributeType; + + public Builder(Class collectionClass) { + this.collectionClass = collectionClass; + } + + public Builder owner(AbstractManagedType owner) { + this.owner = owner; + return this; + } + + public Builder member(Member member) { + this.member = member; + return this; + } + + public Builder binding(PluralAttributeBinding attributeBinding) { + this.attributeBinding = attributeBinding; + return this; + } + + public Builder elementType(Type elementType) { + this.elementType = elementType; + return this; + } + + public Builder keyType(Type keyType) { + this.keyType = keyType; + return this; + } + + public Builder persistentAttributeType(PersistentAttributeType attrType) { + this.persistentAttributeType = attrType; + return this; + } + + @SuppressWarnings( "unchecked" ) + public PluralAttributeImpl build() { + //apply strict spec rules first + if ( Map.class.equals( collectionClass ) ) { + return ( PluralAttributeImpl ) new MapAttributeImpl( this ); + } + else if ( Set.class.equals( collectionClass ) ) { + return ( PluralAttributeImpl ) new SetAttributeImpl( this ); + } + else if ( List.class.equals( collectionClass ) ) { + return ( PluralAttributeImpl ) new ListAttributeImpl( this ); + } + else if ( Collection.class.equals( collectionClass ) ) { + return ( PluralAttributeImpl ) new CollectionAttributeImpl( this ); + } + + //apply loose rules + if ( Map.class.isAssignableFrom( collectionClass ) ) { + return ( PluralAttributeImpl ) new MapAttributeImpl( this ); + } + else if ( Set.class.isAssignableFrom( collectionClass ) ) { + return ( PluralAttributeImpl ) new SetAttributeImpl( this ); + } + else if ( List.class.isAssignableFrom( collectionClass ) ) { + return ( PluralAttributeImpl ) new ListAttributeImpl( this ); + } + else if ( Collection.class.isAssignableFrom( collectionClass ) ) { + return ( PluralAttributeImpl ) new CollectionAttributeImpl( this ); + } + throw new UnsupportedOperationException( "Unknown collection: " + collectionClass ); + } + } + + public static Builder builder(Class collectionClass) { + return new Builder( collectionClass ); + } + + @Override + public Type getElementType() { + return elementType; + } + + @Override + public boolean isAssociation() { + return true; + } + + @Override + public boolean isCollection() { + return true; + } + + @Override + public BindableType getBindableType() { + return BindableType.PLURAL_ATTRIBUTE; + } + + @Override + public Class getBindableJavaType() { + return elementType.getJavaType(); + } + + static class SetAttributeImpl extends PluralAttributeImpl,E> implements SetAttribute { + SetAttributeImpl(Builder xceBuilder) { + super( xceBuilder ); + } + + @Override + public CollectionType getCollectionType() { + return CollectionType.SET; + } + } + + static class CollectionAttributeImpl extends PluralAttributeImpl,E> implements CollectionAttribute { + CollectionAttributeImpl(Builder xceBuilder) { + super( xceBuilder ); + } + + @Override + public CollectionType getCollectionType() { + return CollectionType.COLLECTION; + } + } + + static class ListAttributeImpl extends PluralAttributeImpl,E> implements ListAttribute { + ListAttributeImpl(Builder xceBuilder) { + super( xceBuilder ); + } + + @Override + public CollectionType getCollectionType() { + return CollectionType.LIST; + } + } + + static class MapAttributeImpl extends PluralAttributeImpl,V> implements MapAttribute { + private final Type keyType; + + @SuppressWarnings("unchecked") + MapAttributeImpl(Builder xceBuilder) { + super( xceBuilder ); + this.keyType = xceBuilder.keyType; + } + + @Override + public CollectionType getCollectionType() { + return CollectionType.MAP; + } + + @Override + public Class getKeyJavaType() { + return keyType.getJavaType(); + } + + @Override + public Type getKeyType() { + return keyType; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/SingularAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/SingularAttributeImpl.java new file mode 100644 index 0000000000..ec478c3a21 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/SingularAttributeImpl.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal; +import java.io.Serializable; +import java.lang.reflect.Member; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type; + +/** + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public class SingularAttributeImpl + extends AbstractAttribute + implements SingularAttribute, Serializable { + private final boolean isIdentifier; + private final boolean isVersion; + private final boolean isOptional; + private final Type attributeType; + + public SingularAttributeImpl( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + boolean isIdentifier, + boolean isVersion, + boolean isOptional, + Type attributeType, + PersistentAttributeType persistentAttributeType) { + super( name, javaType, declaringType, member, persistentAttributeType ); + this.isIdentifier = isIdentifier; + this.isVersion = isVersion; + this.isOptional = isOptional; + this.attributeType = attributeType; + } + + /** + * Subclass used to simply instantiation of singular attributes representing an entity's + * identifier. + */ + public static class Identifier extends SingularAttributeImpl { + public Identifier( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + Type attributeType, + PersistentAttributeType persistentAttributeType) { + super( name, javaType, declaringType, member, true, false, false, attributeType, persistentAttributeType ); + } + } + + /** + * Subclass used to simply instantiation of singular attributes representing an entity's + * version. + */ + public static class Version extends SingularAttributeImpl { + public Version( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + Type attributeType, + PersistentAttributeType persistentAttributeType) { + super( name, javaType, declaringType, member, false, true, false, attributeType, persistentAttributeType ); + } + } + + @Override + public boolean isId() { + return isIdentifier; + } + + @Override + public boolean isVersion() { + return isVersion; + } + + @Override + public boolean isOptional() { + return isOptional; + } + + @Override + public Type getType() { + return attributeType; + } + + @Override + public boolean isAssociation() { + return false; + } + + @Override + public boolean isCollection() { + return false; + } + + @Override + public BindableType getBindableType() { + return BindableType.SINGULAR_ATTRIBUTE; + } + + @Override + public Class getBindableJavaType() { + return attributeType.getJavaType(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/UnsupportedFeature.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/UnsupportedFeature.java new file mode 100644 index 0000000000..176c47f580 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/UnsupportedFeature.java @@ -0,0 +1,44 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal; + +/** + * Represents Hibernate mapping features that are not supported in JPA metamodel. Used to allow control over how + * such features are handled in regards to building the JPA {@link javax.persistence.metamodel.Metamodel} instance. + * + * @author Steve Ebersole +*/ +public enum UnsupportedFeature { + ANY( "ANY mappings not supported in JPA metamodel" ); + + private final String message; + + UnsupportedFeature(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeBuilder.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeBuilder.java new file mode 100644 index 0000000000..4b896262b9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeBuilder.java @@ -0,0 +1,536 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal.builder; + +import javax.persistence.OneToOne; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.IdentifiableType; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.Type; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; + +import org.jboss.logging.Logger; + +import org.hibernate.HibernateException; +import org.hibernate.annotations.common.AssertionFailure; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.jpa.metamodel.internal.AbstractIdentifiableType; +import org.hibernate.jpa.metamodel.internal.AbstractManagedType; +import org.hibernate.jpa.metamodel.internal.BasicTypeImpl; +import org.hibernate.jpa.metamodel.internal.EmbeddableTypeImpl; +import org.hibernate.jpa.metamodel.internal.MappedSuperclassTypeImpl; +import org.hibernate.jpa.metamodel.internal.PluralAttributeImpl; +import org.hibernate.jpa.metamodel.internal.SingularAttributeImpl; +import org.hibernate.jpa.metamodel.internal.UnsupportedFeature; +import org.hibernate.metamodel.spi.binding.AttributeBinding; +import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding; +import org.hibernate.metamodel.spi.binding.IndexedPluralAttributeBinding; +import org.hibernate.metamodel.spi.binding.PluralAttributeBinding; +import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding; +import org.hibernate.metamodel.spi.binding.PluralAttributeElementNature; +import org.hibernate.metamodel.spi.binding.PluralAttributeIndexNature; +import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; +import org.hibernate.metamodel.spi.domain.PluralAttributeNature; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.type.ComponentType; +import org.hibernate.type.EmbeddedComponentType; +import org.hibernate.type.EntityType; + +import static javax.persistence.metamodel.Attribute.PersistentAttributeType; + +/** + * A factory for building {@link Attribute} instances. Exposes 3 main services:

    + *
  1. {@link #buildAttribute} for building normal attributes
  2. + *
  3. {@link #buildIdAttribute} for building identifier attributes
  4. + *
  5. {@link #buildVersionAttribute} for building version attributes}
  6. + *
      + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class AttributeBuilder { + private static final Logger LOG = Logger.getLogger( AttributeBuilder.class.getName() ); + + /** + * The context for attribute building + */ + public static interface Context { + public Type locateEntityTypeByName(String entityName); + + public void registerEmbeddedableType(EmbeddableTypeImpl embeddableType); + + public SessionFactoryImplementor getSessionFactory(); + + public EntityPersister getSubClassEntityPersister(MappedSuperclassTypeImpl mappedSuperclass); + + public void handleUnsupportedFeature(UnsupportedFeature feature); + } + + private final Context context; + + public AttributeBuilder(Context context) { + this.context = context; + } + + /** + * Build a normal attribute. + * + * @param ownerType The descriptor of the attribute owner (aka declarer). + * @param attributeBinding The Hibernate attribute binding descriptor + * @return The built attribute descriptor or null if the attribute is not part of the JPA 2 model (eg backrefs) + */ + public Attribute buildAttribute(AbstractManagedType ownerType, AttributeBinding attributeBinding) { + if ( attributeBinding.getAttribute().isSynthetic() ) { + // hide synthetic/virtual properties (fabricated by Hibernate) from the JPA metamodel. + LOG.tracef( + "Skipping synthetic property %s(%s)", + ownerType.getJavaType().getName(), + attributeBinding.getAttribute().getName() + ); + return null; + } + LOG.trace("Building attribute [" + ownerType.getJavaType().getName() + "." + attributeBinding.getAttribute().getName() + "]"); + final AttributeMetadata attributeMetadata = determineAttributeMetadata( + ownerType, + attributeBinding, + NORMAL_MEMBER_RESOLVER + ); + if ( attributeMetadata == null ) { + return null; + } + if ( attributeMetadata.isPlural() ) { + return buildPluralAttribute( (PluralAttributeMetadata) attributeMetadata ); + } + final SingularAttributeMetadata singularAttributeMetadata = (SingularAttributeMetadata)attributeMetadata; + final Type metaModelType = getMetaModelType( singularAttributeMetadata.getAttributeTypeDescriptor() ); + //noinspection unchecked + return new SingularAttributeImpl( + attributeMetadata.getName(), + attributeMetadata.getJavaType(), + ownerType, + attributeMetadata.getMember(), + false, + false, + true, // todo : need to handle this somehow : property.isOptional(), + metaModelType, + attributeMetadata.getPersistentAttributeType() + ); + } + + /** + * Build the identifier attribute descriptor + * + * @param ownerType The descriptor of the attribute owner (aka declarer). + * @param attributeBinding The Hibernate attribute binding descriptor + * + * @return The built attribute descriptor + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttributeImpl buildIdAttribute(AbstractIdentifiableType ownerType, AttributeBinding attributeBinding) { + LOG.trace( + "Building identifier attribute [" + ownerType.getJavaType().getName() + "#" + + attributeBinding.getAttribute().getName() + "]" + ); + final SingularAttributeMetadata attributeMetadata = (SingularAttributeMetadata) determineAttributeMetadata( + ownerType, + attributeBinding, + IDENTIFIER_MEMBER_RESOLVER + ); + final Type metaModelType = getMetaModelType( attributeMetadata.getAttributeTypeDescriptor() ); + return new SingularAttributeImpl.Identifier( + attributeBinding.getAttribute().getName(), + attributeMetadata.getJavaType(), + ownerType, + attributeMetadata.getMember(), + metaModelType, + attributeMetadata.getPersistentAttributeType() + ); + } + + /** + * Build the version attribute descriptor + * + * @param ownerType The descriptor of the attribute owner (aka declarer). + * @param attributeBinding The Hibernate attribute binding descriptor + * + * @return The built attribute descriptor + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttributeImpl buildVersionAttribute(AbstractIdentifiableType ownerType, AttributeBinding attributeBinding) { + LOG.trace("Building version attribute [ownerType.getJavaType().getName()" + "." + "property.getName()]"); + final SingularAttributeMetadata attributeMetadata = (SingularAttributeMetadata) determineAttributeMetadata( + ownerType, + attributeBinding, + VERSION_MEMBER_RESOLVER + ); + final Type metaModelType = getMetaModelType( attributeMetadata.getAttributeTypeDescriptor() ); + return new SingularAttributeImpl.Version( + attributeBinding.getAttribute().getName(), + attributeMetadata.getJavaType(), + ownerType, + attributeMetadata.getMember(), + metaModelType, + attributeMetadata.getPersistentAttributeType() + ); + } + + @SuppressWarnings( "unchecked" ) + private PluralAttribute buildPluralAttribute(PluralAttributeMetadata attributeMetadata) { + final Type elementType = getMetaModelType( attributeMetadata.getElementAttributeTypeDescriptor() ); + if ( java.util.Map.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) { + final Type keyType = getMetaModelType( attributeMetadata.getMapKeyAttributeTypeDescriptor() ); + return PluralAttributeImpl.builder( attributeMetadata.getJavaType() ) + .owner( attributeMetadata.getOwnerType() ) + .elementType( elementType ) + .keyType( keyType ) + .member( attributeMetadata.getMember() ) + .binding( (PluralAttributeBinding) attributeMetadata.getAttributeBinding() ) + .persistentAttributeType( attributeMetadata.getPersistentAttributeType() ) + .build(); + } + return PluralAttributeImpl.builder( attributeMetadata.getJavaType() ) + .owner( attributeMetadata.getOwnerType() ) + .elementType( elementType ) + .member( attributeMetadata.getMember() ) + .binding( (PluralAttributeBinding) attributeMetadata.getAttributeBinding() ) + .persistentAttributeType( attributeMetadata.getPersistentAttributeType() ) + .build(); + } + + @SuppressWarnings( "unchecked" ) + private Type getMetaModelType(AttributeTypeDescriptor attributeTypeDescriptor) { + switch ( attributeTypeDescriptor.getValueClassification() ) { + case BASIC: { + return new BasicTypeImpl( + attributeTypeDescriptor.getBindableType(), + Type.PersistenceType.BASIC + ); + } + case ENTITY: { + final org.hibernate.type.EntityType type = (EntityType) attributeTypeDescriptor.getHibernateType(); + return (Type) context.locateEntityTypeByName( type.getAssociatedEntityName() ); + } + case EMBEDDABLE: { + final EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl( + attributeTypeDescriptor.getBindableType(), + attributeTypeDescriptor.getAttributeMetadata().getOwnerType(), + (ComponentType) attributeTypeDescriptor.getHibernateType() + ); + context.registerEmbeddedableType( embeddableType ); + + CompositeAttributeBinding compositeAttributeBinding = + (CompositeAttributeBinding) attributeTypeDescriptor.getHibernateMetamodelType(); + for ( AttributeBinding subAttributeBinding : compositeAttributeBinding.attributeBindings() ) { + final Attribute attribute = buildAttribute( embeddableType, subAttributeBinding ); + if ( attribute != null ) { + embeddableType.getBuilder().addAttribute( attribute ); + } + } + embeddableType.lock(); + return embeddableType; + } + default: { + throw new AssertionFailure( "Unknown type : " + attributeTypeDescriptor.getValueClassification() ); + } + } + } + + private EntityMetamodel getDeclarerEntityMetamodel(IdentifiableType ownerType) { + final Type.PersistenceType persistenceType = ownerType.getPersistenceType(); + if ( persistenceType == Type.PersistenceType.ENTITY) { + return context.getSessionFactory() + .getEntityPersister( ownerType.getJavaType().getName() ) + .getEntityMetamodel(); + } + else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS) { + return context.getSubClassEntityPersister( (MappedSuperclassTypeImpl) ownerType ).getEntityMetamodel(); + } + else { + throw new AssertionFailure( "Cannot get the metamodel for PersistenceType: " + persistenceType ); + } + } + + /** + * Here is most of the nuts and bolts of this factory, where we interpret the known JPA metadata + * against the known Hibernate metadata and build a descriptor for the attribute. + * + * @param jpaOwner The JPA representation of the attribute owner + * @param attributeBinding Hibernate metamodel representation of the attribute binding + * @param memberResolver Strategy for how to resolve the member defining the attribute. + * + * @return The attribute description + */ + @SuppressWarnings({ "unchecked" }) + private AttributeMetadata determineAttributeMetadata( + AbstractManagedType jpaOwner, + AttributeBinding attributeBinding, + MemberResolver memberResolver) { + LOG.trace("Starting attribute metadata determination [" + attributeBinding.getAttribute().getName() + "]"); + final Member member = memberResolver.resolveMember( jpaOwner, attributeBinding ); + LOG.trace(" Determined member [" + member + "]"); + + final org.hibernate.type.Type type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(); + LOG.trace(" Determined type [name=" + type.getName() + ", class=" + type.getClass().getName() + "]"); + + if ( type.isAnyType() ) { + // ANY mappings are currently not supported in the JPA metamodel; see HHH-6589 + context.handleUnsupportedFeature( UnsupportedFeature.ANY ); + return null; + } + + if ( SingularAttributeBinding.class.isInstance( attributeBinding ) ) { + final SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding; + + final PersistentAttributeType jpaAttributeType; + if ( singularAttributeBinding.getAttribute().getSingularAttributeType().isComponent() ) { + jpaAttributeType = PersistentAttributeType.EMBEDDED; + } + else if ( singularAttributeBinding.getAttribute().getSingularAttributeType().isAssociation() ) { + jpaAttributeType = determineSingularAssociationAttributeType( member ); + } + else { + jpaAttributeType = PersistentAttributeType.BASIC; + } + return new SingularAttributeMetadataImpl( attributeBinding, jpaOwner, member, jpaAttributeType ); + } + else { + final PluralAttributeBinding pluralAttributeBinding = (PluralAttributeBinding) attributeBinding; + + // First, determine the type of the elements and use that to help determine the + // collection type) + final PluralAttributeElementBinding elementBinding = pluralAttributeBinding.getPluralAttributeElementBinding(); + final PluralAttributeElementNature elementNature = elementBinding.getPluralAttributeElementNature(); + final PersistentAttributeType persistentAttributeType; + final PersistentAttributeType elementPersistentAttributeType; + PersistentAttributeType keyPersistentAttributeType = null; + + if ( elementNature == PluralAttributeElementNature.MANY_TO_ANY ) { + // ANY mappings are currently not supported in the JPA metamodel; see HHH-6589 + context.handleUnsupportedFeature( UnsupportedFeature.ANY ); + return null; + } + else if ( elementNature == PluralAttributeElementNature.BASIC ) { + elementPersistentAttributeType = PersistentAttributeType.BASIC; + persistentAttributeType = PersistentAttributeType.ELEMENT_COLLECTION; + } + else if ( elementNature == PluralAttributeElementNature.COMPOSITE ) { + elementPersistentAttributeType = PersistentAttributeType.EMBEDDED; + persistentAttributeType = PersistentAttributeType.ELEMENT_COLLECTION; + } + else { + elementPersistentAttributeType = elementNature == PluralAttributeElementNature.MANY_TO_MANY + ? PersistentAttributeType.MANY_TO_MANY + : PersistentAttributeType.ONE_TO_MANY; + persistentAttributeType = elementPersistentAttributeType; + } + + // For maps, also check the key binding + if ( pluralAttributeBinding.getAttribute().getNature() == PluralAttributeNature.MAP ) { + final IndexedPluralAttributeBinding indexedPluralAttributeBinding + = (IndexedPluralAttributeBinding) pluralAttributeBinding; + final PluralAttributeIndexNature indexNature + = indexedPluralAttributeBinding.getPluralAttributeIndexBinding().getPluralAttributeIndexNature(); + + if ( indexNature == PluralAttributeIndexNature.MANY_TO_ANY ) { + context.handleUnsupportedFeature( UnsupportedFeature.ANY ); + return null; + } + else if ( indexNature == PluralAttributeIndexNature.MANY_TO_MANY ) { + keyPersistentAttributeType = Attribute.PersistentAttributeType.MANY_TO_ONE; + } + else if ( indexNature == PluralAttributeIndexNature.COMPOSITE ) { + keyPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED; + } + else { + keyPersistentAttributeType = Attribute.PersistentAttributeType.BASIC; + } + } + else { + // for the sake of symmetry... + if ( pluralAttributeBinding.getPluralAttributeKeyBinding() != null ) { + throw new HibernateException( + String.format( + "Encountered non-Map attribute binding with associated map-key binding : %s#%s", + jpaOwner.getJavaType().getName(), + pluralAttributeBinding.getAttribute().getName() + ) + ); + } + } + + return new PluralAttributeMetadataImpl( + pluralAttributeBinding, + jpaOwner, + member, + persistentAttributeType, + elementPersistentAttributeType, + keyPersistentAttributeType + ); + } + } + + public static PersistentAttributeType determineSingularAssociationAttributeType(Member member) { + if ( Field.class.isInstance( member ) ) { + return ( (Field) member ).getAnnotation( OneToOne.class ) != null + ? PersistentAttributeType.ONE_TO_ONE + : PersistentAttributeType.MANY_TO_ONE; + } + else { + return ( (Method) member ).getAnnotation( OneToOne.class ) != null + ? PersistentAttributeType.ONE_TO_ONE + : PersistentAttributeType.MANY_TO_ONE; + } + } + + public static ParameterizedType getSignatureType(Member member) { + final java.lang.reflect.Type type = Field.class.isInstance( member ) + ? ( ( Field ) member ).getGenericType() + : ( ( Method ) member ).getGenericReturnType(); + //this is a raw type + if ( type instanceof Class ) return null; + return (ParameterizedType) type; + } + + public static PluralAttribute.CollectionType determineCollectionType(Class javaType) { + if ( java.util.List.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.LIST; + } + else if ( java.util.Set.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.SET; + } + else if ( java.util.Map.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.MAP; + } + else if ( java.util.Collection.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.COLLECTION; + } + else { + throw new IllegalArgumentException( "Expecting collection type [" + javaType.getName() + "]" ); + } + } + +// public static boolean isManyToMany(Member member) { +// return Field.class.isInstance( member ) +// ? ( (Field) member ).getAnnotation( ManyToMany.class ) != null +// : ( (Method) member ).getAnnotation( ManyToMany.class ) != null; +// } + + private final MemberResolver EMBEDDED_MEMBER_RESOLVER = new MemberResolver() { + @Override + public Member resolveMember(AbstractManagedType owner, AttributeBinding attributeBinding) { + final EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl ) owner; + final String attributeName = attributeBinding.getAttribute().getName(); + return embeddableType.getHibernateType() + .getComponentTuplizer() + .getGetter( embeddableType.getHibernateType().getPropertyIndex( attributeName ) ) + .getMember(); + } + }; + + + private final MemberResolver VIRTUAL_IDENTIFIER_MEMBER_RESOLVER = new MemberResolver() { + @Override + public Member resolveMember(AbstractManagedType owner, AttributeBinding attributeBinding) { + final IdentifiableType identifiableType = (IdentifiableType) owner; + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + if ( ! entityMetamodel.getIdentifierProperty().isVirtual() ) { + throw new IllegalArgumentException( "expecting IdClass mapping" ); + } + org.hibernate.type.Type type = entityMetamodel.getIdentifierProperty().getType(); + if ( ! EmbeddedComponentType.class.isInstance( type ) ) { + throw new IllegalArgumentException( "expecting IdClass mapping" ); + } + + final EmbeddedComponentType componentType = (EmbeddedComponentType) type; + final String attributeName = attributeBinding.getAttribute().getName(); + return componentType.getComponentTuplizer() + .getGetter( componentType.getPropertyIndex( attributeName ) ) + .getMember(); + } + }; + + /** + * A {@link Member} resolver for normal attributes. + */ + private final MemberResolver NORMAL_MEMBER_RESOLVER = new MemberResolver() { + @Override + public Member resolveMember(AbstractManagedType owner, AttributeBinding attributeBinding) { + final Type.PersistenceType persistenceType = owner.getPersistenceType(); + if ( Type.PersistenceType.EMBEDDABLE == persistenceType ) { + return EMBEDDED_MEMBER_RESOLVER.resolveMember( owner, attributeBinding ); + } + else if ( Type.PersistenceType.ENTITY == persistenceType + || Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) { + final IdentifiableType identifiableType = (IdentifiableType) owner; + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final String propertyName = attributeBinding.getAttribute().getName(); + final Integer index = entityMetamodel.getPropertyIndexOrNull( propertyName ); + if ( index == null ) { + // just like in #determineIdentifierJavaMember , this *should* indicate we have an IdClass mapping + return VIRTUAL_IDENTIFIER_MEMBER_RESOLVER.resolveMember( owner, attributeBinding ); + } + else { + return entityMetamodel.getTuplizer() + .getGetter( index ) + .getMember(); + } + } + else { + throw new IllegalArgumentException( "Unexpected owner type : " + persistenceType ); + } + } + }; + + private final MemberResolver IDENTIFIER_MEMBER_RESOLVER = new MemberResolver() { + @Override + public Member resolveMember(AbstractManagedType owner, AttributeBinding attributeBinding) { + final IdentifiableType identifiableType = (IdentifiableType) owner; + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final String attributeName = attributeBinding.getAttribute().getName(); + if ( ! attributeName.equals( entityMetamodel.getIdentifierProperty().getName() ) ) { + // this *should* indicate processing part of an IdClass... + return VIRTUAL_IDENTIFIER_MEMBER_RESOLVER.resolveMember( owner, attributeBinding ); + } + return entityMetamodel.getTuplizer().getIdentifierGetter().getMember(); + } + }; + + private final MemberResolver VERSION_MEMBER_RESOLVER = new MemberResolver() { + @Override + public Member resolveMember(AbstractManagedType owner, AttributeBinding attributeBinding) { + final IdentifiableType identifiableType = (IdentifiableType) owner; + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final String versionPropertyName = attributeBinding.getAttribute().getName(); + if ( ! versionPropertyName.equals( entityMetamodel.getVersionProperty().getName() ) ) { + // this should never happen, but to be safe... + throw new IllegalArgumentException( "Given property did not match declared version property" ); + } + return entityMetamodel.getTuplizer().getVersionGetter().getMember(); + } + }; +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeMetadata.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeMetadata.java new file mode 100644 index 0000000000..5924dd84e0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeMetadata.java @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import javax.persistence.metamodel.Attribute; +import java.lang.reflect.Member; + +import org.hibernate.jpa.metamodel.internal.AbstractManagedType; +import org.hibernate.metamodel.spi.binding.AttributeBinding; + +/** + * Basic contract for describing an attribute in a format needed while building the JPA metamodel. + * + * The "description" is described:
        + *
      1. partially in terms of JPA ({@link #getPersistentAttributeType} and {@link #getOwnerType})
      2. + *
      3. partially in terms of Hibernate metamodel ({@link #getAttributeBinding})
      4. + *
      5. and partially just in terms of the java model itself ({@link #getMember} and {@link #getJavaType})
      6. + *
      + * + * @param The attribute owner type + * @param The attribute type. + */ +public interface AttributeMetadata { + /** + * Retrieve the name of the attribute + * + * @return The attribute name + */ + public String getName(); + + /** + * Retrieve the member defining the attribute + * + * @return The attribute member + */ + public Member getMember(); + + /** + * Retrieve the attribute java type. + * + * @return The java type of the attribute. + */ + public Class getJavaType(); + + /** + * Get the JPA attribute type classification for this attribute. + * + * @return The JPA attribute type classification + */ + public Attribute.PersistentAttributeType getPersistentAttributeType(); + + /** + * Retrieve the attribute owner's metamodel information + * + * @return The metamodel information for the attribute owner + */ + public AbstractManagedType getOwnerType(); + + /** + * Retrieve the Hibernate property mapping related to this attribute. + * + * @return The Hibernate property mapping + */ + public AttributeBinding getAttributeBinding(); + + /** + * Is the attribute plural (a collection)? + * + * @return True if it is plural, false otherwise. + */ + public boolean isPlural(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeTypeDescriptor.java new file mode 100644 index 0000000000..53bbb95174 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/AttributeTypeDescriptor.java @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +/** + * Centralized access to a variety of information about a the type of an attribute being built for the JPA metamodel. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public interface AttributeTypeDescriptor { + /** + * Enum of the simplified types a value might be. These relate more to the Hibernate classification + * then the JPA classification + */ + enum ValueClassification { + EMBEDDABLE, + ENTITY, + BASIC + } + + public org.hibernate.metamodel.spi.domain.Type getHibernateMetamodelType(); + + public org.hibernate.type.Type getHibernateType(); + + public Class getBindableType(); + + /** + * Retrieve the simplified value classification + * + * @return The value type + */ + public ValueClassification getValueClassification(); + + /** + * Retrieve the metadata about the attribute from which this value comes + * + * @return The "containing" attribute metadata. + */ + public AttributeMetadata getAttributeMetadata(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/BaseAttributeMetadata.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/BaseAttributeMetadata.java new file mode 100644 index 0000000000..28a0467522 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/BaseAttributeMetadata.java @@ -0,0 +1,112 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import javax.persistence.metamodel.Attribute; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import org.hibernate.jpa.metamodel.internal.AbstractManagedType; +import org.hibernate.metamodel.spi.binding.AttributeBinding; + +/** + * Base implementation of AttributeMetadata + * + * @author Steve Ebersole + */ +public abstract class BaseAttributeMetadata implements AttributeMetadata { + private final AttributeBinding attributeBinding; + private final AbstractManagedType ownerType; + private final Member member; + private final Class javaType; + private final Attribute.PersistentAttributeType persistentAttributeType; + + @SuppressWarnings({ "unchecked" }) + public BaseAttributeMetadata( + AttributeBinding attributeBinding, + AbstractManagedType ownerType, + Member member, + Attribute.PersistentAttributeType persistentAttributeType) { + this.attributeBinding = attributeBinding; + this.ownerType = ownerType; + this.member = member; + this.persistentAttributeType = persistentAttributeType; + final Class declaredType; + // we can support method or field members here. Is there really any other valid type? + if ( Field.class.isInstance( member ) ) { + declaredType = ( (Field) member ).getType(); + } + else if ( Method.class.isInstance( member ) ) { + declaredType = ( (Method) member ).getReturnType(); + } + else { + throw new IllegalArgumentException( "Cannot determine java-type from given member [" + member + "]" ); + } + this.javaType = declaredType; + } + + @Override + public String getName() { + return attributeBinding.getAttribute().getName(); + } + + @Override + public Member getMember() { + return member; + } + + public String getMemberDescription() { + return determineMemberDescription( getMember() ); + } + + public String determineMemberDescription(Member member) { + return member.getDeclaringClass().getName() + '#' + member.getName(); + } + + @Override + public Class getJavaType() { + return javaType; + } + + @Override + public Attribute.PersistentAttributeType getPersistentAttributeType() { + return persistentAttributeType; + } + + @Override + public AbstractManagedType getOwnerType() { + return ownerType; + } + + @Override + public boolean isPlural() { + return ! attributeBinding.getAttribute().isSingular(); + } + + @Override + public AttributeBinding getAttributeBinding() { + return attributeBinding; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MemberResolver.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MemberResolver.java new file mode 100644 index 0000000000..8581f00d43 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MemberResolver.java @@ -0,0 +1,47 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import java.lang.reflect.Member; + +import org.hibernate.jpa.metamodel.internal.AbstractManagedType; +import org.hibernate.metamodel.spi.binding.AttributeBinding; + +/** + * Contract for how we resolve the {@link java.lang.reflect.Member} for a given attribute context. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public interface MemberResolver { + /** + * Resolve the member. + * + * @param owner The JPA Metamodel representation of the class tha owns the member to be resolved + * @param attributeBinding Hibernate metamodel representation of the attribute for which to resolve the member. + * + * @return The resolved member. + */ + public Member resolveMember(AbstractManagedType owner, AttributeBinding attributeBinding); +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MetamodelBuilder.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MetamodelBuilder.java new file mode 100644 index 0000000000..da6a25a3de --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/MetamodelBuilder.java @@ -0,0 +1,392 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.jboss.logging.Logger; + +import org.hibernate.HibernateException; +import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.jpa.metamodel.internal.AbstractIdentifiableType; +import org.hibernate.jpa.metamodel.internal.EmbeddableTypeImpl; +import org.hibernate.jpa.metamodel.internal.EntityTypeImpl; +import org.hibernate.jpa.metamodel.internal.MappedSuperclassTypeImpl; +import org.hibernate.jpa.metamodel.internal.MetamodelImpl; +import org.hibernate.jpa.metamodel.internal.UnsupportedFeature; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.KeyValue; +import org.hibernate.mapping.Property; +import org.hibernate.metamodel.spi.binding.AttributeBinding; +import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; +import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding; +import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.HierarchyDetails; +import org.hibernate.metamodel.spi.binding.SingularNonAssociationAttributeBinding; +import org.hibernate.metamodel.spi.domain.Entity; +import org.hibernate.metamodel.spi.domain.Hierarchical; +import org.hibernate.metamodel.spi.domain.Superclass; +import org.hibernate.persister.entity.EntityPersister; + +/** + * Defines the contract for building JPA Metamodel ({@link org.hibernate.jpa.metamodel.internal.MetamodelImpl}). + *

      + * Contract is made up of:

        + *
      1. Instantiating this builder
      2. + *
      3. adding all managed mapping classes to it ({@link #add})
      4. + *
      5. calling {@link #buildMetamodel}
      6. + *
      + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class MetamodelBuilder { + private static final Logger log = Logger.getLogger( MetamodelBuilder.class ); + + private final SessionFactoryImplementor sessionFactory; + + // these maps eventually make up the JPA Metamodel + private final Map,EntityTypeImpl> entityTypeMap = new HashMap, EntityTypeImpl>(); + private final Map, EmbeddableTypeImpl> embeddableTypeMap = new HashMap, EmbeddableTypeImpl>(); + private final Map, MappedSuperclassTypeImpl> mappedSuperclassTypeMap = new HashMap, MappedSuperclassTypeImpl>(); + + // these fields are needed just for the duration of building the metamodel + private final AttributeBuilder attributeBuilder; + private final Map entityTypeByNameMap = new HashMap(); + private final Map mappedSuperclassEntityNameMap = new HashMap(); + private List entityBindingList = new ArrayList(); + private Set alreadyProcessed = new HashSet(); + + + public MetamodelBuilder(SessionFactoryImplementor sessionFactory) { + this.sessionFactory = sessionFactory; + this.attributeBuilder = new AttributeBuilder( new AttributeBuilderContext() ); + } + + public void add(EntityBinding entityBinding) { + locateOrBuildEntityType( entityBinding ); + entityBindingList.add( entityBinding ); + } + + private EntityTypeImpl locateOrBuildEntityType(EntityBinding binding) { + EntityTypeImpl entityType = entityTypeMap.get( binding.getClassReference() ); + if ( entityType == null ) { + entityType = buildEntityType( binding ); + } + return entityType; + } + + @SuppressWarnings("unchecked") + private EntityTypeImpl buildEntityType(EntityBinding entityBinding) { + final Class javaType = entityBinding.getClassReference(); + final AbstractIdentifiableType superType = locateOrBuildSuperType( entityBinding.getEntity().getSuperType(), entityBinding ); + + EntityTypeImpl entityType = new EntityTypeImpl( + javaType, + superType, + entityBinding.getJpaEntityName(), + entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() != null, + entityBinding.isVersioned() + ); + + entityTypeMap.put( javaType, entityType ); + return entityType; + } + + /** + * IMPORTANT!!! This method is called in 2 somewhat different cases:
        + *
      1. resolving super class for @Entity
      2. + *
      3. resolving super class for @MappedSuperclass
      4. + *
      + * Make sure changes fit both uses + * + * @param superDescriptor Hibernate metamodel descriptor of the super class + * @param entityBinding The Hibernate metamodel entity binding; could be describing different class between the + * 2 use cases described above. + * + * @return The super type. + */ + private AbstractIdentifiableType locateOrBuildSuperType(Hierarchical superDescriptor, EntityBinding entityBinding) { + if ( superDescriptor == null ) { + return null; + } + + // the super type here could be either a "mapped superclass" or an entity + if ( Entity.class.isInstance( superDescriptor ) ) { + // make sure super entity binding points to same... + final EntityBinding superBinding = entityBinding.getSuperEntityBinding(); + if ( superBinding == null ) { + throw new IllegalStateException( "EntityBinding with super class of Entity type did not specify super entity binding" ); + } + if ( superBinding.getEntity() != superDescriptor ) { + throw new IllegalStateException( "Super entity binding and descriptor referenced different descriptors" ); + } + return locateOrBuildEntityType( superBinding ); + } + else if ( Superclass.class.isInstance( superDescriptor ) ) { + return locateOrBuildMappedSuperclassType( (Superclass) superDescriptor, entityBinding ); + } + else { + throw new IllegalStateException( + "Unexpected type for entity super descriptor; expecting Entity or Superclass, found [" + + superDescriptor.getClassName() + "]" + ); + } + } + + private MappedSuperclassTypeImpl locateOrBuildMappedSuperclassType(Superclass superDescriptor, EntityBinding entityBinding) { + MappedSuperclassTypeImpl mappedSuperclassType = mappedSuperclassTypeMap.get( superDescriptor.getClassReference() ); + if ( mappedSuperclassType == null ) { + mappedSuperclassType = buildMappedSuperclassType( superDescriptor, entityBinding ); + } + return mappedSuperclassType; + } + + @SuppressWarnings("unchecked") + private MappedSuperclassTypeImpl buildMappedSuperclassType(Superclass superDescriptor, EntityBinding entityBinding) { + final Class javaType = superDescriptor.getClassReference(); + final AbstractIdentifiableType superSuperType = locateOrBuildSuperType( superDescriptor, entityBinding ); + + MappedSuperclassTypeImpl mappedSuperclassType = new MappedSuperclassTypeImpl( + javaType, + superSuperType, + entityBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding() != null, + entityBinding.isVersioned() + ); + + mappedSuperclassTypeMap.put( javaType, mappedSuperclassType ); + mappedSuperclassEntityNameMap.put( mappedSuperclassType, entityBinding.getEntity().getName() ); + return mappedSuperclassType; + } + + public MetamodelImpl buildMetamodel() { + log.trace( "Building JPA Metamodel instance..." ); + // we need to process types from superclasses to subclasses + for ( EntityBinding entityBinding : entityBindingList ) { + processHierarchy( entityBinding ); + } + + for ( EmbeddableTypeImpl embeddable : embeddableTypeMap.values() ) { + populateStaticMetamodel( embeddable ); + } + + + return new MetamodelImpl( + entityTypeMap, + mappedSuperclassTypeMap, + embeddableTypeMap + ); + } + + private void processHierarchy(EntityBinding entityBinding) { + log.trace( " Starting binding [" + entityBinding.getEntity().getName() + "]" ); + processType( entityBinding.getEntity(), entityBinding ); + } + + /** + * Performs a depth-first traversal of the super types... + * + * @param descriptor The type descriptor to process + * @param entityBinding + */ + private void processType(Hierarchical descriptor, EntityBinding entityBinding) { + if ( descriptor == null ) { + return; + } + + if ( alreadyProcessed.contains( descriptor ) ) { + return; + } + alreadyProcessed.add( descriptor ); + + // perform a depth-first traversal of the super types... + processSuperType( descriptor, entityBinding ); + + final AbstractIdentifiableType jpaDescriptor = Entity.class.isInstance( descriptor ) + ? entityTypeMap.get( descriptor.getClassReference() ) + : mappedSuperclassTypeMap.get( descriptor.getClassReference() ); + + applyIdMetadata( descriptor, entityBinding.getHierarchyDetails(), jpaDescriptor ); + applyVersionAttribute( descriptor, entityBinding.getHierarchyDetails(), jpaDescriptor ); + + for ( AttributeBinding attributeBinding : entityBinding.attributeBindings() ) { + if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) { + continue; + } + if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityVersion().getVersioningAttributeBinding() ) { + // skip the version property, it was already handled previously. + continue; + } + final Attribute attribute = attributeBuilder.buildAttribute( jpaDescriptor, attributeBinding ); + if ( attribute != null ) { + //noinspection unchecked + jpaDescriptor.getBuilder().addAttribute( attribute ); + } + } + jpaDescriptor.lock(); + populateStaticMetamodel( jpaDescriptor ); + } + + private void processSuperType(Hierarchical descriptor, EntityBinding entityBinding) { + final Hierarchical superDescriptor = descriptor.getSuperType(); + final EntityBinding superEntityBinding = Entity.class.isInstance( superDescriptor ) + ? entityBinding.getSuperEntityBinding() + : entityBinding; + processType( superDescriptor, superEntityBinding ); + } + + private void applyIdMetadata( + Hierarchical descriptor, + HierarchyDetails hierarchyDetails, + AbstractIdentifiableType jpaDescriptor) { + switch ( hierarchyDetails.getEntityIdentifier().getNature() ) { + case SIMPLE: { + SingularNonAssociationAttributeBinding idAttributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding(); + if ( idAttributeBinding != null ) { + if ( idAttributeBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { + //noinspection unchecked + jpaDescriptor.getBuilder().applyIdAttribute( + attributeBuilder.buildIdAttribute( jpaDescriptor, idAttributeBinding ) + ); + } + } + break; + } + case AGGREGATED_COMPOSITE: { + SingularNonAssociationAttributeBinding idAttributeBinding = hierarchyDetails.getEntityIdentifier().getAttributeBinding(); + if ( idAttributeBinding != null ) { + if ( idAttributeBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { + //noinspection unchecked + jpaDescriptor.getBuilder().applyIdAttribute( + attributeBuilder.buildIdAttribute( jpaDescriptor, idAttributeBinding ) + ); + } + } + break; + } + default: { + // nature == (non-aggregated) COMPOSITE + CompositeAttributeBinding idAttributeBinding = (CompositeAttributeBinding) hierarchyDetails.getEntityIdentifier().getAttributeBinding(); + if ( idAttributeBinding != null ) { + if ( idAttributeBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { + Set idClassAttributes = new HashSet(); + for ( AttributeBinding idClassAttributeBinding : idAttributeBinding.attributeBindings() ) { + idClassAttributes.add( attributeBuilder.buildIdAttribute( jpaDescriptor, idClassAttributeBinding ) ); + } + //noinspection unchecked + jpaDescriptor.getBuilder().applyIdClassAttributes( idClassAttributes ); + } + } + } + } + } + + private void applyVersionAttribute( + Hierarchical descriptor, + HierarchyDetails hierarchyDetails, + AbstractIdentifiableType jpaDescriptor) { + final BasicAttributeBinding versionBinding = hierarchyDetails.getEntityVersion().getVersioningAttributeBinding(); + if ( versionBinding != null ) { + if ( versionBinding.getAttribute().getAttributeContainer().equals( descriptor ) ) { + //noinspection unchecked + jpaDescriptor.getBuilder().applyVersionAttribute( + attributeBuilder.buildVersionAttribute( jpaDescriptor, versionBinding ) + ); + } + } + } + + private void populateStaticMetamodel(AbstractIdentifiableType jpaDescriptor) { + // todo : implement ! + } + + private void populateStaticMetamodel(EmbeddableTypeImpl embeddable) { + // todo : implement ! + } + + + /** + * Implementation of AttributeBuilder.Context + */ + class AttributeBuilderContext implements AttributeBuilder.Context { + public Type locateEntityTypeByName(String entityName) { + return entityTypeByNameMap.get( entityName ); + } + + @Override + public void registerEmbeddedableType(EmbeddableTypeImpl embeddableType) { + embeddableTypeMap.put( embeddableType.getJavaType(), embeddableType ); + } + + public SessionFactoryImplementor getSessionFactory() { + return sessionFactory; + } + + @Override + public EntityPersister getSubClassEntityPersister(MappedSuperclassTypeImpl mappedSuperclass) { + final String entityName = mappedSuperclassEntityNameMap.get( mappedSuperclass ); + if ( entityName == null ) { + throw new HibernateException( + String.format( + "Could not resolve @MappedSuperclass [%s] to entity name", + mappedSuperclass.getJavaType().getName() + ) + ); + } + final EntityPersister entityPersister = sessionFactory.getEntityPersister( entityName ); + if ( entityPersister == null ) { + throw new HibernateException( + String.format( + "Unable to resolve entity name [%s] to EntityPersister for @MappedSuperclass [%s]", + entityName, + mappedSuperclass.getJavaType().getName() + ) + ); + } + return entityPersister; + } + + @Override + public void handleUnsupportedFeature(UnsupportedFeature feature) { + boolean ignoreUnsupported = true; + if ( ignoreUnsupported ) { + log.debug( "Ignoring mapping construct not supported as part of JPA metamodel [" + feature.getMessage() + "]" ); + } + else { + throw new UnsupportedOperationException( feature.getMessage() ); + } + } + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadata.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadata.java new file mode 100644 index 0000000000..c6e54d6167 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadata.java @@ -0,0 +1,58 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import javax.persistence.metamodel.PluralAttribute; + +/** + * Attribute metadata contract for a plural attribute. + * @param The owner type + * @param The attribute type (the collection type) + * @param The collection element type + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +interface PluralAttributeMetadata extends AttributeMetadata { + /** + * Retrieve the JPA collection type classification for this attribute + * + * @return The JPA collection type classification + */ + public PluralAttribute.CollectionType getAttributeCollectionType(); + + /** + * Retrieve the value context for the collection's elements. + * + * @return The value context for the collection's elements. + */ + public AttributeTypeDescriptor getElementAttributeTypeDescriptor(); + + /** + * Retrieve the value context for the collection's keys (if a map, null otherwise). + * + * @return The value context for the collection's keys (if a map, null otherwise). + */ + public AttributeTypeDescriptor getMapKeyAttributeTypeDescriptor(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadataImpl.java new file mode 100644 index 0000000000..d63b63f20d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/PluralAttributeMetadataImpl.java @@ -0,0 +1,195 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.PluralAttribute; +import java.lang.reflect.Member; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; + +import org.hibernate.annotations.common.AssertionFailure; +import org.hibernate.jpa.metamodel.internal.AbstractManagedType; +import org.hibernate.metamodel.spi.binding.IndexedPluralAttributeBinding; +import org.hibernate.metamodel.spi.binding.PluralAttributeBinding; + +/** +* @author Steve Ebersole +*/ +public class PluralAttributeMetadataImpl + extends BaseAttributeMetadata + implements PluralAttributeMetadata { + private final PluralAttribute.CollectionType attributeCollectionType; + private final Attribute.PersistentAttributeType elementPersistentAttributeType; + private final Attribute.PersistentAttributeType keyPersistentAttributeType; + private final Class elementJavaType; + private final Class keyJavaType; + private final AttributeTypeDescriptor elementAttributeTypeDescriptor; + private final AttributeTypeDescriptor keyAttributeTypeDescriptor; + + PluralAttributeMetadataImpl( + PluralAttributeBinding attributeBinding, + AbstractManagedType ownerType, + Member member, + Attribute.PersistentAttributeType persistentAttributeType, + Attribute.PersistentAttributeType elementPersistentAttributeType, + Attribute.PersistentAttributeType keyPersistentAttributeType) { + super( attributeBinding, ownerType, member, persistentAttributeType ); + this.attributeCollectionType = AttributeBuilder.determineCollectionType( getJavaType() ); + this.elementPersistentAttributeType = elementPersistentAttributeType; + this.keyPersistentAttributeType = keyPersistentAttributeType; + + ParameterizedType signatureType = AttributeBuilder.getSignatureType( member ); + if ( keyPersistentAttributeType == null ) { + elementJavaType = signatureType != null ? + getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : + Object.class; //FIXME and honor targetEntity? + keyJavaType = null; + } + else { + keyJavaType = signatureType != null ? + getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : + Object.class; //FIXME and honor targetEntity? + elementJavaType = signatureType != null ? + getClassFromGenericArgument( signatureType.getActualTypeArguments()[1] ) : + Object.class; //FIXME and honor targetEntity? + } + + this.elementAttributeTypeDescriptor = new AttributeTypeDescriptor() { + @Override + public org.hibernate.metamodel.spi.domain.Type getHibernateMetamodelType() { + return getAttributeBinding().getAttribute().getElementType(); + } + + @Override + public org.hibernate.type.Type getHibernateType() { + return getAttributeBinding().getPluralAttributeElementBinding() + .getHibernateTypeDescriptor() + .getResolvedTypeMapping(); + } + + public Class getBindableType() { + return elementJavaType; + } + + public ValueClassification getValueClassification() { + switch ( PluralAttributeMetadataImpl.this.elementPersistentAttributeType ) { + case EMBEDDED: { + return ValueClassification.EMBEDDABLE; + } + case BASIC: { + return ValueClassification.BASIC; + } + default: { + return ValueClassification.ENTITY; + } + } + } + + public AttributeMetadata getAttributeMetadata() { + return PluralAttributeMetadataImpl.this; + } + }; + + // interpret the key, if one + if ( keyPersistentAttributeType != null ) { + this.keyAttributeTypeDescriptor = new AttributeTypeDescriptor() { + @Override + public org.hibernate.metamodel.spi.domain.Type getHibernateMetamodelType() { + return ( (IndexedPluralAttributeBinding) getAttributeBinding() ).getPluralAttributeIndexBinding() + .getPluralAttributeIndexType(); + } + + @Override + public org.hibernate.type.Type getHibernateType() { + return getAttributeBinding().getPluralAttributeKeyBinding() + .getHibernateTypeDescriptor() + .getResolvedTypeMapping(); + } + + public Class getBindableType() { + return keyJavaType; + } + + public ValueClassification getValueClassification() { + switch ( PluralAttributeMetadataImpl.this.keyPersistentAttributeType ) { + case EMBEDDED: { + return ValueClassification.EMBEDDABLE; + } + case BASIC: { + return ValueClassification.BASIC; + } + default: { + return ValueClassification.ENTITY; + } + } + } + + public AttributeMetadata getAttributeMetadata() { + return PluralAttributeMetadataImpl.this; + } + }; + } + else { + keyAttributeTypeDescriptor = null; + } + } + + private Class getClassFromGenericArgument(java.lang.reflect.Type type) { + if ( type instanceof Class ) { + return (Class) type; + } + else if ( type instanceof TypeVariable ) { + final java.lang.reflect.Type upperBound = ( ( TypeVariable ) type ).getBounds()[0]; + return getClassFromGenericArgument( upperBound ); + } + else if ( type instanceof ParameterizedType ) { + final java.lang.reflect.Type rawType = ( (ParameterizedType) type ).getRawType(); + return getClassFromGenericArgument( rawType ); + } + else { + throw new AssertionFailure( + "Fail to process type argument in a generic declaration. Member : " + getMemberDescription() + + " Type: " + type.getClass() + ); + } + } + + @Override + public PluralAttributeBinding getAttributeBinding() { + return (PluralAttributeBinding) super.getAttributeBinding(); + } + + public AttributeTypeDescriptor getElementAttributeTypeDescriptor() { + return elementAttributeTypeDescriptor; + } + + public PluralAttribute.CollectionType getAttributeCollectionType() { + return attributeCollectionType; + } + + public AttributeTypeDescriptor getMapKeyAttributeTypeDescriptor() { + return keyAttributeTypeDescriptor; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadata.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadata.java new file mode 100644 index 0000000000..1fab29eadc --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadata.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +/** + * Attribute metadata contract for a non-plural attribute. + * @param The owner type + * @param The attribute type + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public interface SingularAttributeMetadata extends AttributeMetadata { + /** + * Retrieve the value context for this attribute + * + * @return The attributes value context + */ + public AttributeTypeDescriptor getAttributeTypeDescriptor(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadataImpl.java new file mode 100644 index 0000000000..c14921ac2f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/builder/SingularAttributeMetadataImpl.java @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.builder; + +import javax.persistence.metamodel.Attribute; +import java.lang.reflect.Member; + +import org.hibernate.jpa.metamodel.internal.AbstractManagedType; +import org.hibernate.metamodel.spi.binding.AttributeBinding; +import org.hibernate.metamodel.spi.domain.SingularAttribute; + +/** +* @author Steve Ebersole +*/ +public class SingularAttributeMetadataImpl + extends BaseAttributeMetadata + implements SingularAttributeMetadata { + private final AttributeTypeDescriptor attributeTypeDescriptor; + + public SingularAttributeMetadataImpl( + AttributeBinding attributeBinding, + AbstractManagedType ownerType, + Member member, + Attribute.PersistentAttributeType persistentAttributeType) { + super( attributeBinding, ownerType, member, persistentAttributeType ); + attributeTypeDescriptor = new AttributeTypeDescriptor() { + @Override + public org.hibernate.metamodel.spi.domain.Type getHibernateMetamodelType() { + return ( (SingularAttribute) getAttributeMetadata().getAttributeBinding().getAttribute() ).getSingularAttributeType(); + } + + @Override + public org.hibernate.type.Type getHibernateType() { + return getAttributeMetadata().getAttributeBinding().getHibernateTypeDescriptor().getResolvedTypeMapping(); + } + + @Override + public Class getBindableType() { + return getAttributeMetadata().getJavaType(); + } + + @Override + public ValueClassification getValueClassification() { + switch ( getPersistentAttributeType() ) { + case EMBEDDED: { + return ValueClassification.EMBEDDABLE; + } + case BASIC: { + return ValueClassification.BASIC; + } + default: { + return ValueClassification.ENTITY; + } + } + } + + @Override + public AttributeMetadata getAttributeMetadata() { + return SingularAttributeMetadataImpl.this; + } + }; + } + + public AttributeTypeDescriptor getAttributeTypeDescriptor() { + return attributeTypeDescriptor; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractAttribute.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractAttribute.java new file mode 100644 index 0000000000..3b10a00fbe --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractAttribute.java @@ -0,0 +1,142 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.ManagedType; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import org.hibernate.internal.util.ReflectHelper; + +/** + * Models the commonality of the JPA {@link javax.persistence.metamodel.Attribute} hierarchy. + * + * @author Steve Ebersole + */ +public abstract class AbstractAttribute + implements Attribute, AttributeImplementor, Serializable { + private final String name; + private final Class javaType; + private final AbstractManagedType declaringType; + private transient Member member; + private final PersistentAttributeType persistentAttributeType; + + public AbstractAttribute( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + PersistentAttributeType persistentAttributeType) { + this.name = name; + this.javaType = javaType; + this.declaringType = declaringType; + this.member = member; + this.persistentAttributeType = persistentAttributeType; + } + + /** + * {@inheritDoc} + */ + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + public ManagedType getDeclaringType() { + return declaringType; + } + + /** + * {@inheritDoc} + */ + public Class getJavaType() { + return javaType; + } + + /** + * {@inheritDoc} + */ + public Member getJavaMember() { + return member; + } + + /** + * {@inheritDoc} + */ + public PersistentAttributeType getPersistentAttributeType() { + return persistentAttributeType; + } + + /** + * Used by JDK serialization... + * + * @param ois The input stream from which we are being read... + * @throws java.io.IOException Indicates a general IO stream exception + * @throws ClassNotFoundException Indicates a class resolution issue + */ + protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + final String memberDeclaringClassName = ( String ) ois.readObject(); + final String memberName = ( String ) ois.readObject(); + final String memberType = ( String ) ois.readObject(); + + final Class memberDeclaringClass = Class.forName( + memberDeclaringClassName, + false, + declaringType.getJavaType().getClassLoader() + ); + try { + this.member = "method".equals( memberType ) + ? memberDeclaringClass.getMethod( memberName, ReflectHelper.NO_PARAM_SIGNATURE ) + : memberDeclaringClass.getField( memberName ); + } + catch ( Exception e ) { + throw new IllegalStateException( + "Unable to locate member [" + memberDeclaringClassName + "#" + + memberName + "]" + ); + } + } + + /** + * Used by JDK serialization... + * + * @param oos The output stream to which we are being written... + * @throws java.io.IOException Indicates a general IO stream exception + */ + protected void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + oos.writeObject( getJavaMember().getDeclaringClass().getName() ); + oos.writeObject( getJavaMember().getName() ); + // should only ever be a field or the getter-method... + oos.writeObject( Method.class.isInstance( getJavaMember() ) ? "method" : "field" ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractIdentifiableType.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractIdentifiableType.java new file mode 100644 index 0000000000..2377665136 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractIdentifiableType.java @@ -0,0 +1,318 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.IdentifiableType; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * Defines commonality for the JPA {@link javax.persistence.metamodel.IdentifiableType} types. JPA defines + * identifiable types as entities or mapped-superclasses. Basically things to which an + * identifier can be attached. + *

      + * NOTE : Currently we only really have support for direct entities in the Hibernate metamodel + * as the information for them is consumed into the closest actual entity subclass(es) in the + * internal Hibernate mapping-metamodel. + * + * @author Steve Ebersole + */ +public abstract class AbstractIdentifiableType + extends AbstractManagedType + implements IdentifiableType, Serializable { + + private final boolean hasIdentifierProperty; + private final boolean isVersioned; + + private SingularAttributeImpl id; + private SingularAttributeImpl version; + private Set> idClassAttributes; + + public AbstractIdentifiableType( + Class javaType, + AbstractIdentifiableType superType, + boolean hasIdentifierProperty, + boolean versioned) { + super( javaType, superType ); + this.hasIdentifierProperty = hasIdentifierProperty; + isVersioned = versioned; + } + + /** + * {@inheritDoc} + */ + public AbstractIdentifiableType getSupertype() { + return ( AbstractIdentifiableType ) super.getSupertype(); + } + + /** + * Indicates if a non-null super type is required to provide the + * identifier attribute(s) if this object does not have a declared + * identifier. + * . + * @return true, if a non-null super type is required to provide + * the identifier attribute(s) if this object does not have a + * declared identifier; false, otherwise. + */ + protected abstract boolean requiresSupertypeForNonDeclaredIdentifier(); + + protected AbstractIdentifiableType requireSupertype() { + if ( getSupertype() == null ) { + throw new IllegalStateException( "No supertype found" ); + } + return getSupertype(); + } + + /** + * {@inheritDoc} + */ + public boolean hasSingleIdAttribute() { + return hasIdentifierProperty; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getId(Class javaType) { + final SingularAttribute id_; + if ( id != null ) { + checkSimpleId(); + id_ = ( SingularAttribute ) id; + if ( javaType != id.getJavaType() ) { + throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() ); + } + } + else { + //yuk yuk bad me + if ( ! requiresSupertypeForNonDeclaredIdentifier()) { + final AbstractIdentifiableType supertype = getSupertype(); + if (supertype != null) { + id_ = supertype.getId( javaType ); + } + else { + id_ = null; + } + } + else { + id_ = requireSupertype().getId( javaType ); + } + } + return id_; + } + + /** + * Centralized check to ensure the id for this hierarchy is a simple one (i.e., does not use + * an id-class). + * + * @see #checkIdClass() + */ + protected void checkSimpleId() { + if ( ! hasIdentifierProperty ) { + throw new IllegalStateException( "This class uses an @IdClass" ); + } + } + + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getDeclaredId(Class javaType) { + checkDeclaredId(); + checkSimpleId(); + if ( javaType != id.getJavaType() ) { + throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() ); + } + return (SingularAttribute) id; + } + + /** + * Centralized check to ensure the id is actually declared on the class mapped here, as opposed to a + * super class. + */ + protected void checkDeclaredId() { + if ( id == null ) { + throw new IllegalArgumentException( "The id attribute is not declared on this type" ); + } + } + + /** + * {@inheritDoc} + */ + public Type getIdType() { + if ( id != null ) { + checkSimpleId(); + return id.getType(); + } + else { + return requireSupertype().getIdType(); + } + } + + private boolean hasIdClassAttributesDefined() { + return idClassAttributes != null || + ( getSupertype() != null && getSupertype().hasIdClassAttributesDefined() ); + } + + /** + * {@inheritDoc} + */ + public Set> getIdClassAttributes() { + if ( idClassAttributes != null ) { + checkIdClass(); + } + else { + // Java does not allow casting requireSupertype().getIdClassAttributes() + // to Set> because the + // superclass X is a different Java type from this X + // (i.e, getSupertype().getJavaType() != getJavaType()). + // It will, however, allow a Set> + // to be initialized with requireSupertype().getIdClassAttributes(), + // since getSupertype().getJavaType() is a superclass of getJavaType() + if ( requiresSupertypeForNonDeclaredIdentifier() ) { + idClassAttributes = new HashSet>( requireSupertype().getIdClassAttributes() ); + } + else if ( getSupertype() != null && hasIdClassAttributesDefined() ) { + idClassAttributes = new HashSet>( getSupertype().getIdClassAttributes() ); + } + } + return idClassAttributes; + } + + /** + * Centralized check to ensure the id for this hierarchy uses an id-class. + * + * @see #checkSimpleId() + */ + private void checkIdClass() { + if ( hasIdentifierProperty ) { + throw new IllegalArgumentException( "This class does not use @IdClass" ); + } + } + + /** + * {@inheritDoc} + */ + public boolean hasVersionAttribute() { + return isVersioned; + } + + public boolean hasDeclaredVersionAttribute() { + return isVersioned && version != null; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getVersion(Class javaType) { + if ( ! hasVersionAttribute() ) { + return null; + } + final SingularAttribute version_; + if ( version != null ) { + version_ = ( SingularAttribute ) version; + if ( javaType != version.getJavaType() ) { + throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() ); + } + } + else { + version_ = requireSupertype().getVersion( javaType ); + } + return version_; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getDeclaredVersion(Class javaType) { + checkDeclaredVersion(); + if ( javaType != version.getJavaType() ) { + throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() ); + } + return ( SingularAttribute ) version; + } + + /** + * For used to retrieve the declared version when populating the static metamodel. + * + * @return The declared + */ + public SingularAttribute getDeclaredVersion() { + checkDeclaredVersion(); + return version; + } + + /** + * Centralized check to ensure the version (if one) is actually declared on the class mapped here, as opposed to a + * super class. + */ + protected void checkDeclaredVersion() { + if ( version == null || ( getSupertype() != null && getSupertype().hasVersionAttribute() )) { + throw new IllegalArgumentException( "The version attribute is not declared on this type" ); + } + } + + public Builder getBuilder() { + final AbstractManagedType.Builder managedBuilder = super.getBuilder(); + return new Builder() { + public void applyIdAttribute(SingularAttributeImpl idAttribute) { + AbstractIdentifiableType.this.id = idAttribute; + managedBuilder.addAttribute( idAttribute ); + } + + public void applyIdClassAttributes(Set> idClassAttributes) { + for ( SingularAttribute idClassAttribute : idClassAttributes ) { + if ( AbstractIdentifiableType.this == idClassAttribute.getDeclaringType() ) { + @SuppressWarnings({ "unchecked" }) + SingularAttribute declaredAttribute = ( SingularAttribute ) idClassAttribute; + addAttribute( declaredAttribute ); + } + } + AbstractIdentifiableType.this.idClassAttributes = idClassAttributes; + } + + public void applyVersionAttribute(SingularAttributeImpl versionAttribute) { + AbstractIdentifiableType.this.version = versionAttribute; + managedBuilder.addAttribute( versionAttribute ); + } + + public void addAttribute(Attribute attribute) { + managedBuilder.addAttribute( attribute ); + } + }; + } + + public static interface Builder extends AbstractManagedType.Builder { + public void applyIdAttribute(SingularAttributeImpl idAttribute); + public void applyIdClassAttributes(Set> idClassAttributes); + public void applyVersionAttribute(SingularAttributeImpl versionAttribute); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractManagedType.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractManagedType.java new file mode 100644 index 0000000000..04043de697 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractManagedType.java @@ -0,0 +1,529 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Bindable; +import javax.persistence.metamodel.CollectionAttribute; +import javax.persistence.metamodel.ListAttribute; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SetAttribute; +import javax.persistence.metamodel.SingularAttribute; +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.hibernate.annotations.common.AssertionFailure; + +/** + * Defines commonality for the JPA {@link javax.persistence.metamodel.ManagedType} hierarchy of interfaces. + * + * @author Steve Ebersole + */ +public abstract class AbstractManagedType + extends AbstractType + implements ManagedType, Serializable { + + private final AbstractManagedType superType; + + private final Map> declaredAttributes + = new HashMap>(); + private final Map> declaredSingularAttributes + = new HashMap>(); + private final Map> declaredPluralAttributes + = new HashMap>(); + + protected AbstractManagedType(Class javaType, AbstractManagedType superType) { + super( javaType ); + this.superType = superType; + } + + protected AbstractManagedType getSupertype() { + return superType; + } + + private boolean locked = false; + + public Builder getBuilder() { + if ( locked ) { + throw new IllegalStateException( "Type has been locked" ); + } + return new Builder() { + public void addAttribute(Attribute attribute) { + declaredAttributes.put( attribute.getName(), attribute ); + final Bindable.BindableType bindableType = ( ( Bindable ) attribute ).getBindableType(); + switch ( bindableType ) { + case SINGULAR_ATTRIBUTE : { + declaredSingularAttributes.put( attribute.getName(), (SingularAttribute) attribute ); + break; + } + case PLURAL_ATTRIBUTE : { + declaredPluralAttributes.put(attribute.getName(), (PluralAttribute) attribute ); + break; + } + default : { + throw new AssertionFailure( "unknown bindable type: " + bindableType ); + } + } + } + }; + } + + public void lock() { + locked = true; + } + + public static interface Builder { + public void addAttribute(Attribute attribute); + } + + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public Set> getAttributes() { + HashSet attributes = new HashSet>( declaredAttributes.values() ); + if ( getSupertype() != null ) { + attributes.addAll( getSupertype().getAttributes() ); + } + return attributes; + } + + /** + * {@inheritDoc} + */ + public Set> getDeclaredAttributes() { + return new HashSet>( declaredAttributes.values() ); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public Attribute getAttribute(String name) { + Attribute attribute = declaredAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getAttribute( name ); + } + return attribute; + } + + /** + * {@inheritDoc} + */ + public Attribute getDeclaredAttribute(String name) { + final Attribute attr = declaredSingularAttributes.get( name ); + checkNotNull( "Attribute ", attr, name ); + return attr; + } + + private void checkNotNull(String attributeType, Attribute attribute, String name) { + if ( attribute == null ) { + throw new IllegalArgumentException( attributeType + " named " + name + " is not present" ); + } + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public Set> getSingularAttributes() { + HashSet attributes = new HashSet>( declaredSingularAttributes.values() ); + if ( getSupertype() != null ) { + attributes.addAll( getSupertype().getSingularAttributes() ); + } + return attributes; + } + + /** + * {@inheritDoc} + */ + public Set> getDeclaredSingularAttributes() { + return new HashSet>( declaredSingularAttributes.values() ); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getSingularAttribute(String name) { + SingularAttribute attribute = declaredSingularAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getSingularAttribute( name ); + } + return attribute; + } + + /** + * {@inheritDoc} + */ + public SingularAttribute getDeclaredSingularAttribute(String name) { + final SingularAttribute attr = declaredSingularAttributes.get( name ); + checkNotNull( "SingularAttribute ", attr, name ); + return attr; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttribute getSingularAttribute(String name, Class type) { + SingularAttribute attribute = declaredSingularAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getSingularAttribute( name ); + } + checkTypeForSingleAttribute( "SingularAttribute ", attribute, name, type ); + return ( SingularAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings( "unchecked") + public SingularAttribute getDeclaredSingularAttribute(String name, Class javaType) { + final SingularAttribute attr = declaredSingularAttributes.get( name ); + checkTypeForSingleAttribute( "SingularAttribute ", attr, name, javaType ); + return ( SingularAttribute ) attr; + } + + private void checkTypeForSingleAttribute( + String attributeType, + SingularAttribute attribute, + String name, + Class javaType) { + if ( attribute == null || ( javaType != null && !attribute.getBindableJavaType().equals( javaType ) ) ) { + if ( isPrimitiveVariant( attribute, javaType ) ) { + return; + } + throw new IllegalArgumentException( + attributeType + " named " + name + + ( javaType != null ? " and of type " + javaType.getName() : "" ) + + " is not present" + ); + } + } + + @SuppressWarnings({ "SimplifiableIfStatement" }) + protected boolean isPrimitiveVariant(SingularAttribute attribute, Class javaType) { + if ( attribute == null ) { + return false; + } + Class declaredType = attribute.getBindableJavaType(); + + if ( declaredType.isPrimitive() ) { + return ( Boolean.class.equals( javaType ) && Boolean.TYPE.equals( declaredType ) ) + || ( Character.class.equals( javaType ) && Character.TYPE.equals( declaredType ) ) + || ( Byte.class.equals( javaType ) && Byte.TYPE.equals( declaredType ) ) + || ( Short.class.equals( javaType ) && Short.TYPE.equals( declaredType ) ) + || ( Integer.class.equals( javaType ) && Integer.TYPE.equals( declaredType ) ) + || ( Long.class.equals( javaType ) && Long.TYPE.equals( declaredType ) ) + || ( Float.class.equals( javaType ) && Float.TYPE.equals( declaredType ) ) + || ( Double.class.equals( javaType ) && Double.TYPE.equals( declaredType ) ); + } + + if ( javaType.isPrimitive() ) { + return ( Boolean.class.equals( declaredType ) && Boolean.TYPE.equals( javaType ) ) + || ( Character.class.equals( declaredType ) && Character.TYPE.equals( javaType ) ) + || ( Byte.class.equals( declaredType ) && Byte.TYPE.equals( javaType ) ) + || ( Short.class.equals( declaredType ) && Short.TYPE.equals( javaType ) ) + || ( Integer.class.equals( declaredType ) && Integer.TYPE.equals( javaType ) ) + || ( Long.class.equals( declaredType ) && Long.TYPE.equals( javaType ) ) + || ( Float.class.equals( declaredType ) && Float.TYPE.equals( javaType ) ) + || ( Double.class.equals( declaredType ) && Double.TYPE.equals( javaType ) ); + } + + return false; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public Set> getPluralAttributes() { + HashSet attributes = new HashSet>( declaredPluralAttributes.values() ); + if ( getSupertype() != null ) { + attributes.addAll( getSupertype().getPluralAttributes() ); + } + return attributes; + } + + /** + * {@inheritDoc} + */ + public Set> getDeclaredPluralAttributes() { + return new HashSet>( declaredPluralAttributes.values() ); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public CollectionAttribute getCollection(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicCollectionCheck( attribute, name ); + return ( CollectionAttribute ) attribute; + } + + private PluralAttribute getPluralAttribute(String name) { + return declaredPluralAttributes.get( name ); + } + + private void basicCollectionCheck(PluralAttribute attribute, String name) { + checkNotNull( "CollectionAttribute", attribute, name ); + if ( ! CollectionAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a CollectionAttribute: " + attribute.getClass() ); + } + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings( "unchecked") + public CollectionAttribute getDeclaredCollection(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicCollectionCheck( attribute, name ); + return ( CollectionAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SetAttribute getSet(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicSetCheck( attribute, name ); + return (SetAttribute) attribute; + } + + private void basicSetCheck(PluralAttribute attribute, String name) { + checkNotNull( "SetAttribute", attribute, name ); + if ( ! SetAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a SetAttribute: " + attribute.getClass() ); + } + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings( "unchecked") + public SetAttribute getDeclaredSet(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicSetCheck( attribute, name ); + return ( SetAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public ListAttribute getList(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicListCheck( attribute, name ); + return (ListAttribute) attribute; + } + + private void basicListCheck(PluralAttribute attribute, String name) { + checkNotNull( "ListAttribute", attribute, name ); + if ( ! ListAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a ListAttribute: " + attribute.getClass() ); + } + } + + /** + * {@inheritDoc} + */ + public ListAttribute getDeclaredList(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicListCheck( attribute, name ); + return ( ListAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public MapAttribute getMap(String name) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + basicMapCheck( attribute, name ); + return (MapAttribute) attribute; + } + + private void basicMapCheck(PluralAttribute attribute, String name) { + checkNotNull( "MapAttribute", attribute, name ); + if ( ! MapAttribute.class.isAssignableFrom( attribute.getClass() ) ) { + throw new IllegalArgumentException( name + " is not a MapAttribute: " + attribute.getClass() ); + } + } + + /** + * {@inheritDoc} + */ + public MapAttribute getDeclaredMap(String name) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + basicMapCheck( attribute, name ); + return ( MapAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public CollectionAttribute getCollection(String name, Class elementType) { + PluralAttribute attribute = declaredPluralAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkCollectionElementType( attribute, name, elementType ); + return ( CollectionAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + public CollectionAttribute getDeclaredCollection(String name, Class elementType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkCollectionElementType( attribute, name, elementType ); + return ( CollectionAttribute ) attribute; + } + + private void checkCollectionElementType(PluralAttribute attribute, String name, Class elementType) { + checkTypeForPluralAttributes( "CollectionAttribute", attribute, name, elementType, PluralAttribute.CollectionType.COLLECTION ); + } + + private void checkTypeForPluralAttributes( + String attributeType, + PluralAttribute attribute, + String name, + Class elementType, + PluralAttribute.CollectionType collectionType) { + if ( attribute == null + || ( elementType != null && !attribute.getBindableJavaType().equals( elementType ) ) + || attribute.getCollectionType() != collectionType ) { + throw new IllegalArgumentException( + attributeType + " named " + name + + ( elementType != null ? " and of element type " + elementType : "" ) + + " is not present" + ); + } + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public SetAttribute getSet(String name, Class elementType) { + PluralAttribute attribute = declaredPluralAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkSetElementType( attribute, name, elementType ); + return ( SetAttribute ) attribute; + } + + private void checkSetElementType(PluralAttribute attribute, String name, Class elementType) { + checkTypeForPluralAttributes( "SetAttribute", attribute, name, elementType, PluralAttribute.CollectionType.SET ); + } + + /** + * {@inheritDoc} + */ + public SetAttribute getDeclaredSet(String name, Class elementType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkSetElementType( attribute, name, elementType ); + return ( SetAttribute ) attribute; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public ListAttribute getList(String name, Class elementType) { + PluralAttribute attribute = declaredPluralAttributes.get( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkListElementType( attribute, name, elementType ); + return ( ListAttribute ) attribute; + } + + private void checkListElementType(PluralAttribute attribute, String name, Class elementType) { + checkTypeForPluralAttributes( "ListAttribute", attribute, name, elementType, PluralAttribute.CollectionType.LIST ); + } + + /** + * {@inheritDoc} + */ + public ListAttribute getDeclaredList(String name, Class elementType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkListElementType( attribute, name, elementType ); + return ( ListAttribute ) attribute; + } + + @SuppressWarnings({ "unchecked" }) + public MapAttribute getMap(String name, Class keyType, Class valueType) { + PluralAttribute attribute = getPluralAttribute( name ); + if ( attribute == null && getSupertype() != null ) { + attribute = getSupertype().getPluralAttribute( name ); + } + checkMapValueType( attribute, name, valueType ); + final MapAttribute mapAttribute = ( MapAttribute ) attribute; + checkMapKeyType( mapAttribute, name, keyType ); + return mapAttribute; + } + + private void checkMapValueType(PluralAttribute attribute, String name, Class valueType) { + checkTypeForPluralAttributes( "MapAttribute", attribute, name, valueType, PluralAttribute.CollectionType.MAP); + } + + private void checkMapKeyType(MapAttribute mapAttribute, String name, Class keyType) { + if ( mapAttribute.getKeyJavaType() != keyType ) { + throw new IllegalArgumentException( "MapAttribute named " + name + " does not support a key of type " + keyType ); + } + } + + public MapAttribute getDeclaredMap(String name, Class keyType, Class valueType) { + final PluralAttribute attribute = declaredPluralAttributes.get( name ); + checkMapValueType( attribute, name, valueType ); + final MapAttribute mapAttribute = ( MapAttribute ) attribute; + checkMapKeyType( mapAttribute, name, keyType ); + return mapAttribute; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractType.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractType.java new file mode 100644 index 0000000000..6ddf2500f8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AbstractType.java @@ -0,0 +1,44 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.Type; +import java.io.Serializable; + +/** + * Defines commonality for the JPA {@link javax.persistence.metamodel.Type} hierarchy of interfaces. + * + * @author Steve Ebersole + */ +public abstract class AbstractType implements Type, Serializable { + private final Class javaType; + + public AbstractType(Class javaType) { + this.javaType = javaType; + } + + public Class getJavaType() { + return javaType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeFactory.java new file mode 100644 index 0000000000..42180d540f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeFactory.java @@ -0,0 +1,979 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.legacy; + +import javax.persistence.ManyToMany; +import javax.persistence.OneToOne; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.IdentifiableType; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.Type; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; +import java.util.Iterator; + +import org.jboss.logging.Logger; + +import org.hibernate.annotations.common.AssertionFailure; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.mapping.Collection; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.Map; +import org.hibernate.mapping.OneToMany; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.Value; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.type.ComponentType; +import org.hibernate.type.EmbeddedComponentType; +import org.hibernate.type.EntityType; + +/** + * A factory for building {@link javax.persistence.metamodel.Attribute} instances. Exposes 3 main services for building

        + *
      1. {@link #buildAttribute normal attributes}
      2. + *
      3. {@link #buildIdAttribute id attributes}
      4. + *
      5. {@link #buildVersionAttribute version attributes}
      6. + *
          + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class AttributeFactory { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, + AttributeFactory.class.getName()); + + private final MetadataContext context; + + public AttributeFactory(MetadataContext context) { + this.context = context; + } + + /** + * Build a normal attribute. + * + * @param ownerType The descriptor of the attribute owner (aka declarer). + * @param property The Hibernate property descriptor for the attribute + * @param The type of the owner + * @param The attribute type + * @return The built attribute descriptor or null if the attribute is not part of the JPA 2 model (eg backrefs) + */ + @SuppressWarnings({ "unchecked" }) + public AttributeImplementor buildAttribute(AbstractManagedType ownerType, Property property) { + if ( property.isSynthetic() ) { + // hide synthetic/virtual properties (fabricated by Hibernate) from the JPA metamodel. + LOG.tracef( + "Skipping synthetic property %s(%s)", + ownerType.getJavaType().getName(), + property.getName() + ); + return null; + } + LOG.trace("Building attribute [" + ownerType.getJavaType().getName() + "." + property.getName() + "]"); + final AttributeContext attributeContext = wrap( ownerType, property ); + final AttributeMetadata attributeMetadata = + determineAttributeMetadata( attributeContext, NORMAL_MEMBER_RESOLVER ); + if (attributeMetadata == null) { + return null; + } + if (attributeMetadata.isPlural()) { + return buildPluralAttribute((PluralAttributeMetadata)attributeMetadata); + } + final SingularAttributeMetadata singularAttributeMetadata = (SingularAttributeMetadata)attributeMetadata; + final Type metaModelType = getMetaModelType(singularAttributeMetadata.getValueContext()); + return new SingularAttributeImpl( + attributeMetadata.getName(), + attributeMetadata.getJavaType(), + ownerType, + attributeMetadata.getMember(), + false, + false, + property.isOptional(), + metaModelType, + attributeMetadata.getPersistentAttributeType() + ); + } + + private AttributeContext wrap(final AbstractManagedType ownerType, final Property property) { + return new AttributeContext() { + public AbstractManagedType getOwnerType() { + return ownerType; + } + + public Property getPropertyMapping() { + return property; + } + }; + } + + /** + * Build the identifier attribute descriptor + * + * @param ownerType The descriptor of the attribute owner (aka declarer). + * @param property The Hibernate property descriptor for the identifier attribute + * @param The type of the owner + * @param The attribute type + * @return The built attribute descriptor + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttributeImpl buildIdAttribute(AbstractIdentifiableType ownerType, Property property) { + LOG.trace("Building identifier attribute [" + ownerType.getJavaType().getName() + "." + property.getName() + "]"); + final AttributeContext attributeContext = wrap( ownerType, property ); + final SingularAttributeMetadata attributeMetadata = + (SingularAttributeMetadata) determineAttributeMetadata( attributeContext, IDENTIFIER_MEMBER_RESOLVER ); + final Type metaModelType = getMetaModelType( attributeMetadata.getValueContext() ); + return new SingularAttributeImpl.Identifier( + property.getName(), + attributeMetadata.getJavaType(), + ownerType, + attributeMetadata.getMember(), + metaModelType, + attributeMetadata.getPersistentAttributeType() + ); + } + + /** + * Build the version attribute descriptor + * + * @param ownerType The descriptor of the attribute owner (aka declarer). + * @param property The Hibernate property descriptor for the version attribute + * @param The type of the owner + * @param The attribute type + * @return The built attribute descriptor + */ + @SuppressWarnings({ "unchecked" }) + public SingularAttributeImpl buildVersionAttribute(AbstractIdentifiableType ownerType, Property property) { + LOG.trace("Building version attribute [ownerType.getJavaType().getName()" + "." + "property.getName()]"); + final AttributeContext attributeContext = wrap( ownerType, property ); + final SingularAttributeMetadata attributeMetadata = + (SingularAttributeMetadata) determineAttributeMetadata( attributeContext, VERSION_MEMBER_RESOLVER ); + final Type metaModelType = getMetaModelType( attributeMetadata.getValueContext() ); + return new SingularAttributeImpl.Version( + property.getName(), + attributeMetadata.getJavaType(), + ownerType, + attributeMetadata.getMember(), + metaModelType, + attributeMetadata.getPersistentAttributeType() + ); + } + + @SuppressWarnings( "unchecked" ) + private AttributeImplementor buildPluralAttribute(PluralAttributeMetadata attributeMetadata) { + final Type elementType = getMetaModelType( attributeMetadata.getElementValueContext() ); + if ( java.util.Map.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) { + final Type keyType = getMetaModelType( attributeMetadata.getMapKeyValueContext() ); + return PluralAttributeImpl.create( attributeMetadata.getOwnerType(), elementType, attributeMetadata.getJavaType(), keyType ) + .member( attributeMetadata.getMember() ) + .property( attributeMetadata.getPropertyMapping() ) + .persistentAttributeType( attributeMetadata.getPersistentAttributeType() ) + .build(); + } + return PluralAttributeImpl.create(attributeMetadata.getOwnerType(), elementType, attributeMetadata.getJavaType(), null).member(attributeMetadata.getMember()).property(attributeMetadata.getPropertyMapping()).persistentAttributeType(attributeMetadata.getPersistentAttributeType()).build(); + } + + @SuppressWarnings( "unchecked" ) + private Type getMetaModelType(ValueContext typeContext) { + switch ( typeContext.getValueClassification() ) { + case BASIC: { + return new BasicTypeImpl( + typeContext.getBindableType(), + Type.PersistenceType.BASIC + ); + } + case ENTITY: { + final EntityType type = (EntityType) typeContext.getValue().getType(); + return (Type) context.locateEntityType( type.getAssociatedEntityName() ); + } + case EMBEDDABLE: { + final Component component = (Component) typeContext.getValue(); + final EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl( + typeContext.getBindableType(), + typeContext.getAttributeMetadata().getOwnerType(), + (ComponentType) typeContext.getValue().getType() + ); + context.registerEmbeddedableType( embeddableType ); + final Iterator subProperties = component.getPropertyIterator(); + while ( subProperties.hasNext() ) { + final Property property = subProperties.next(); + final AttributeImplementor attribute = buildAttribute( embeddableType, property ); + if ( attribute != null ) { + embeddableType.getBuilder().addAttribute( attribute ); + } + } + embeddableType.lock(); + return embeddableType; + } + default: { + throw new AssertionFailure( "Unknown type : " + typeContext.getValueClassification() ); + } + } + } + + private EntityMetamodel getDeclarerEntityMetamodel(IdentifiableType ownerType) { + final Type.PersistenceType persistenceType = ownerType.getPersistenceType(); + if ( persistenceType == Type.PersistenceType.ENTITY) { + return context.getSessionFactory() + .getEntityPersister( ownerType.getJavaType().getName() ) + .getEntityMetamodel(); + } + else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS) { + PersistentClass persistentClass = + context.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl) ownerType ); + return context.getSessionFactory() + .getEntityPersister( persistentClass.getClassName() ) + .getEntityMetamodel(); + } + else { + throw new AssertionFailure( "Cannot get the metamodel for PersistenceType: " + persistenceType ); + } + } + + /** + * A contract for defining the meta information about a {@link org.hibernate.mapping.Value} + */ + private interface ValueContext { + /** + * Enum of the simplified types a value might be. These relate more to the Hibernate classification + * then the JPA classification + */ + enum ValueClassification { + EMBEDDABLE, + ENTITY, + BASIC + } + + /** + * Retrieve the value itself + * + * @return The value + */ + public Value getValue(); + + public Class getBindableType(); + + /** + * Retrieve the simplified value classification + * + * @return The value type + */ + public ValueClassification getValueClassification(); + + /** + * Retrieve the metadata about the attribute from which this value comes + * + * @return The "containing" attribute metadata. + */ + public AttributeMetadata getAttributeMetadata(); + } + + /** + * Basic contract for describing an attribute. The "description" is partially in terms + * of JPA ({@link #getPersistentAttributeType} and {@link #getOwnerType}), partially in + * terms of Hibernate ({@link #getPropertyMapping}) and partially just in terms of the java + * model itself ({@link #getName}, {@link #getMember} and {@link #getJavaType}). + * + * @param The attribute owner type + * @param The attribute type. + */ + private interface AttributeMetadata { + /** + * Retrieve the name of the attribute + * + * @return The attribute name + */ + public String getName(); + + /** + * Retrieve the member defining the attribute + * + * @return The attribute member + */ + public Member getMember(); + + /** + * Retrieve the attribute java type. + * + * @return The java type of the attribute. + */ + public Class getJavaType(); + + /** + * Get the JPA attribute type classification for this attribute. + * + * @return The JPA attribute type classification + */ + public Attribute.PersistentAttributeType getPersistentAttributeType(); + + /** + * Retrieve the attribute owner's metamodel information + * + * @return The metamodel information for the attribute owner + */ + public AbstractManagedType getOwnerType(); + + /** + * Retrieve the Hibernate property mapping related to this attribute. + * + * @return The Hibernate property mapping + */ + public Property getPropertyMapping(); + + /** + * Is the attribute plural (a collection)? + * + * @return True if it is plural, false otherwise. + */ + public boolean isPlural(); + } + + /** + * Attribute metadata contract for a non-plural attribute. + * @param The owner type + * @param The attribute type + */ + private interface SingularAttributeMetadata extends AttributeMetadata { + /** + * Retrieve the value context for this attribute + * + * @return The attributes value context + */ + public ValueContext getValueContext(); + } + + /** + * Attribute metadata contract for a plural attribute. + * @param The owner type + * @param The attribute type (the collection type) + * @param The collection element type + */ + private interface PluralAttributeMetadata extends AttributeMetadata { + /** + * Retrieve the JPA collection type classification for this attribute + * + * @return The JPA collection type classification + */ + public PluralAttribute.CollectionType getAttributeCollectionType(); + + /** + * Retrieve the value context for the collection's elements. + * + * @return The value context for the collection's elements. + */ + public ValueContext getElementValueContext(); + + /** + * Retrieve the value context for the collection's keys (if a map, null otherwise). + * + * @return The value context for the collection's keys (if a map, null otherwise). + */ + public ValueContext getMapKeyValueContext(); + } + + /** + * Bundle's a Hibernate property mapping together with the JPA metamodel information + * of the attribute owner. + * + * @param The owner type. + */ + private interface AttributeContext { + /** + * Retrieve the attribute owner. + * + * @return The owner. + */ + public AbstractManagedType getOwnerType(); + + /** + * Retrieve the Hibernate property mapping. + * + * @return The Hibvernate property mapping. + */ + public Property getPropertyMapping(); + } + + /** + * Contract for how we resolve the {@link java.lang.reflect.Member} for a give attribute context. + */ + private interface MemberResolver { + public Member resolveMember(AttributeContext attributeContext); + } + + /** + * Here is most of the nuts and bolts of this factory, where we interpret the known JPA metadata + * against the known Hibernate metadata and build a descriptor for the attribute. + * + * @param attributeContext The attribute to be described + * @param memberResolver Strategy for how to resolve the member defining the attribute. + * @param The owner type + * @param The attribute type + * + * @return The attribute description + */ + @SuppressWarnings({ "unchecked" }) + private AttributeMetadata determineAttributeMetadata( + AttributeContext attributeContext, + MemberResolver memberResolver) { + LOG.trace("Starting attribute metadata determination [" + attributeContext.getPropertyMapping().getName() + "]"); + final Member member = memberResolver.resolveMember( attributeContext ); + LOG.trace(" Determined member [" + member + "]"); + + final Value value = attributeContext.getPropertyMapping().getValue(); + final org.hibernate.type.Type type = value.getType(); + LOG.trace(" Determined type [name=" + type.getName() + ", class=" + type.getClass().getName() + "]"); + + if ( type.isAnyType() ) { + // ANY mappings are currently not supported in the JPA metamodel; see HHH-6589 + if ( context.isIgnoreUnsupported() ) { + return null; + } + else { + throw new UnsupportedOperationException( "ANY not supported" ); + } + } + else if ( type.isAssociationType() ) { + // collection or entity + if ( type.isEntityType() ) { + // entity + return new SingularAttributeMetadataImpl( + attributeContext.getPropertyMapping(), + attributeContext.getOwnerType(), + member, + determineSingularAssociationAttributeType( member ) + ); + } + // collection + if (value instanceof Collection) { + final Collection collValue = (Collection)value; + final Value elementValue = collValue.getElement(); + final org.hibernate.type.Type elementType = elementValue.getType(); + + // First, determine the type of the elements and use that to help determine the + // collection type) + final Attribute.PersistentAttributeType elementPersistentAttributeType; + final Attribute.PersistentAttributeType persistentAttributeType; + if (elementType.isAnyType()) { + throw new UnsupportedOperationException("collection of any not supported yet"); + } + final boolean isManyToMany = isManyToMany(member); + if (elementValue instanceof Component) { + elementPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED; + persistentAttributeType = Attribute.PersistentAttributeType.ELEMENT_COLLECTION; + } else if (elementType.isAssociationType()) { + elementPersistentAttributeType = isManyToMany ? Attribute.PersistentAttributeType.MANY_TO_MANY : Attribute.PersistentAttributeType.ONE_TO_MANY; + persistentAttributeType = elementPersistentAttributeType; + } else { + elementPersistentAttributeType = Attribute.PersistentAttributeType.BASIC; + persistentAttributeType = Attribute.PersistentAttributeType.ELEMENT_COLLECTION; + } + + final Attribute.PersistentAttributeType keyPersistentAttributeType; + + // Finally, we determine the type of the map key (if needed) + if (value instanceof Map) { + final Value keyValue = ((Map)value).getIndex(); + final org.hibernate.type.Type keyType = keyValue.getType(); + + if (keyType.isAnyType()) throw new UnsupportedOperationException("collection of any not supported yet"); + if (keyValue instanceof Component) keyPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED; + else if (keyType.isAssociationType()) keyPersistentAttributeType = Attribute.PersistentAttributeType.MANY_TO_ONE; + else keyPersistentAttributeType = Attribute.PersistentAttributeType.BASIC; + } else keyPersistentAttributeType = null; + return new PluralAttributeMetadataImpl(attributeContext.getPropertyMapping(), attributeContext.getOwnerType(), + member, persistentAttributeType, elementPersistentAttributeType, + keyPersistentAttributeType); + } else if (value instanceof OneToMany) { + // TODO : is this even possible??? Really OneToMany should be describing the + // element value within a o.h.mapping.Collection (see logic branch above) + throw new IllegalArgumentException("HUH???"); +// final boolean isManyToMany = isManyToMany( member ); +// //one to many with FK => entity +// return new PluralAttributeMetadataImpl( +// attributeContext.getPropertyMapping(), +// attributeContext.getOwnerType(), +// member, +// isManyToMany +// ? Attribute.PersistentAttributeType.MANY_TO_MANY +// : Attribute.PersistentAttributeType.ONE_TO_MANY +// value, +// AttributeContext.TypeStatus.ENTITY, +// Attribute.PersistentAttributeType.ONE_TO_MANY, +// null, null, null +// ); + } + } + else if ( attributeContext.getPropertyMapping().isComposite() ) { + // component + return new SingularAttributeMetadataImpl( + attributeContext.getPropertyMapping(), + attributeContext.getOwnerType(), + member, + Attribute.PersistentAttributeType.EMBEDDED + ); + } + else { + // basic type + return new SingularAttributeMetadataImpl( + attributeContext.getPropertyMapping(), + attributeContext.getOwnerType(), + member, + Attribute.PersistentAttributeType.BASIC + ); + } + throw new UnsupportedOperationException( "oops, we are missing something: " + attributeContext.getPropertyMapping() ); + } + + public static Attribute.PersistentAttributeType determineSingularAssociationAttributeType(Member member) { + if ( Field.class.isInstance( member ) ) { + return ( (Field) member ).getAnnotation( OneToOne.class ) != null + ? Attribute.PersistentAttributeType.ONE_TO_ONE + : Attribute.PersistentAttributeType.MANY_TO_ONE; + } + else { + return ( (Method) member ).getAnnotation( OneToOne.class ) != null + ? Attribute.PersistentAttributeType.ONE_TO_ONE + : Attribute.PersistentAttributeType.MANY_TO_ONE; + } + } + + private abstract class BaseAttributeMetadata implements AttributeMetadata { + private final Property propertyMapping; + private final AbstractManagedType ownerType; + private final Member member; + private final Class javaType; + private final Attribute.PersistentAttributeType persistentAttributeType; + + @SuppressWarnings({ "unchecked" }) + protected BaseAttributeMetadata( + Property propertyMapping, + AbstractManagedType ownerType, + Member member, + Attribute.PersistentAttributeType persistentAttributeType) { + this.propertyMapping = propertyMapping; + this.ownerType = ownerType; + this.member = member; + this.persistentAttributeType = persistentAttributeType; + final Class declaredType; + // we can support method or field members here. Is there really any other valid type? + if ( Field.class.isInstance( member ) ) { + declaredType = ( (Field) member ).getType(); + } + else if ( Method.class.isInstance( member ) ) { + declaredType = ( (Method) member ).getReturnType(); + } + else { + throw new IllegalArgumentException( "Cannot determine java-type from given member [" + member + "]" ); + } + this.javaType = accountForPrimitiveTypes( declaredType ); + } + + public String getName() { + return propertyMapping.getName(); + } + + public Member getMember() { + return member; + } + + public String getMemberDescription() { + return determineMemberDescription( getMember() ); + } + + public String determineMemberDescription(Member member) { + return member.getDeclaringClass().getName() + '#' + member.getName(); + } + + public Class getJavaType() { + return javaType; + } + + public Attribute.PersistentAttributeType getPersistentAttributeType() { + return persistentAttributeType; + } + + public AbstractManagedType getOwnerType() { + return ownerType; + } + + public boolean isPlural() { + return propertyMapping.getType().isCollectionType(); + } + + public Property getPropertyMapping() { + return propertyMapping; + } + } + + @SuppressWarnings({ "unchecked" }) + protected Class accountForPrimitiveTypes(Class declaredType) { +// if ( !declaredType.isPrimitive() ) { +// return declaredType; +// } +// +// if ( Boolean.TYPE.equals( declaredType ) ) { +// return (Class) Boolean.class; +// } +// if ( Character.TYPE.equals( declaredType ) ) { +// return (Class) Character.class; +// } +// if( Byte.TYPE.equals( declaredType ) ) { +// return (Class) Byte.class; +// } +// if ( Short.TYPE.equals( declaredType ) ) { +// return (Class) Short.class; +// } +// if ( Integer.TYPE.equals( declaredType ) ) { +// return (Class) Integer.class; +// } +// if ( Long.TYPE.equals( declaredType ) ) { +// return (Class) Long.class; +// } +// if ( Float.TYPE.equals( declaredType ) ) { +// return (Class) Float.class; +// } +// if ( Double.TYPE.equals( declaredType ) ) { +// return (Class) Double.class; +// } +// +// throw new IllegalArgumentException( "Unexpected type [" + declaredType + "]" ); + // if the field is defined as int, return int not Integer... + return declaredType; + } + + private class SingularAttributeMetadataImpl + extends BaseAttributeMetadata + implements SingularAttributeMetadata { + private final ValueContext valueContext; + + private SingularAttributeMetadataImpl( + Property propertyMapping, + AbstractManagedType ownerType, + Member member, + Attribute.PersistentAttributeType persistentAttributeType) { + super( propertyMapping, ownerType, member, persistentAttributeType ); + valueContext = new ValueContext() { + public Value getValue() { + return getPropertyMapping().getValue(); + } + + public Class getBindableType() { + return getAttributeMetadata().getJavaType(); + } + + public ValueClassification getValueClassification() { + switch ( getPersistentAttributeType() ) { + case EMBEDDED: { + return ValueClassification.EMBEDDABLE; + } + case BASIC: { + return ValueClassification.BASIC; + } + default: { + return ValueClassification.ENTITY; + } + } + } + + public AttributeMetadata getAttributeMetadata() { + return SingularAttributeMetadataImpl.this; + } + }; + } + + public ValueContext getValueContext() { + return valueContext; + } + } + + private class PluralAttributeMetadataImpl + extends BaseAttributeMetadata + implements PluralAttributeMetadata { + private final PluralAttribute.CollectionType attributeCollectionType; + private final Attribute.PersistentAttributeType elementPersistentAttributeType; + private final Attribute.PersistentAttributeType keyPersistentAttributeType; + private final Class elementJavaType; + private final Class keyJavaType; + private final ValueContext elementValueContext; + private final ValueContext keyValueContext; + + private PluralAttributeMetadataImpl( + Property propertyMapping, + AbstractManagedType ownerType, + Member member, + Attribute.PersistentAttributeType persistentAttributeType, + Attribute.PersistentAttributeType elementPersistentAttributeType, + Attribute.PersistentAttributeType keyPersistentAttributeType) { + super( propertyMapping, ownerType, member, persistentAttributeType ); + this.attributeCollectionType = determineCollectionType( getJavaType() ); + this.elementPersistentAttributeType = elementPersistentAttributeType; + this.keyPersistentAttributeType = keyPersistentAttributeType; + + ParameterizedType signatureType = getSignatureType( member ); + if ( keyPersistentAttributeType == null ) { + elementJavaType = signatureType != null ? + getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : + Object.class; //FIXME and honor targetEntity? + keyJavaType = null; + } + else { + keyJavaType = signatureType != null ? + getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : + Object.class; //FIXME and honor targetEntity? + elementJavaType = signatureType != null ? + getClassFromGenericArgument( signatureType.getActualTypeArguments()[1] ) : + Object.class; //FIXME and honor targetEntity? + } + + this.elementValueContext = new ValueContext() { + public Value getValue() { + return ( (Collection) getPropertyMapping().getValue() ).getElement(); + } + + public Class getBindableType() { + return elementJavaType; + } + + public ValueClassification getValueClassification() { + switch ( PluralAttributeMetadataImpl.this.elementPersistentAttributeType ) { + case EMBEDDED: { + return ValueClassification.EMBEDDABLE; + } + case BASIC: { + return ValueClassification.BASIC; + } + default: { + return ValueClassification.ENTITY; + } + } + } + + public AttributeMetadata getAttributeMetadata() { + return PluralAttributeMetadataImpl.this; + } + }; + + // interpret the key, if one + if ( keyPersistentAttributeType != null ) { + this.keyValueContext = new ValueContext() { + public Value getValue() { + return ( (Map) getPropertyMapping().getValue() ).getIndex(); + } + + public Class getBindableType() { + return keyJavaType; + } + + public ValueClassification getValueClassification() { + switch ( PluralAttributeMetadataImpl.this.keyPersistentAttributeType ) { + case EMBEDDED: { + return ValueClassification.EMBEDDABLE; + } + case BASIC: { + return ValueClassification.BASIC; + } + default: { + return ValueClassification.ENTITY; + } + } + } + + public AttributeMetadata getAttributeMetadata() { + return PluralAttributeMetadataImpl.this; + } + }; + } + else { + keyValueContext = null; + } + } + + private Class getClassFromGenericArgument(java.lang.reflect.Type type) { + if ( type instanceof Class ) { + return (Class) type; + } + else if ( type instanceof TypeVariable ) { + final java.lang.reflect.Type upperBound = ( ( TypeVariable ) type ).getBounds()[0]; + return getClassFromGenericArgument( upperBound ); + } + else if ( type instanceof ParameterizedType ) { + final java.lang.reflect.Type rawType = ( (ParameterizedType) type ).getRawType(); + return getClassFromGenericArgument( rawType ); + } + else { + throw new AssertionFailure( + "Fail to process type argument in a generic declaration. Member : " + getMemberDescription() + + " Type: " + type.getClass() + ); + } + } + + public ValueContext getElementValueContext() { + return elementValueContext; + } + + public PluralAttribute.CollectionType getAttributeCollectionType() { + return attributeCollectionType; + } + + public ValueContext getMapKeyValueContext() { + return keyValueContext; + } + } + + public static ParameterizedType getSignatureType(Member member) { + final java.lang.reflect.Type type = Field.class.isInstance( member ) + ? ( ( Field ) member ).getGenericType() + : ( ( Method ) member ).getGenericReturnType(); + //this is a raw type + if ( type instanceof Class ) return null; + return (ParameterizedType) type; + } + + public static PluralAttribute.CollectionType determineCollectionType(Class javaType) { + if ( java.util.List.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.LIST; + } + else if ( java.util.Set.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.SET; + } + else if ( java.util.Map.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.MAP; + } + else if ( java.util.Collection.class.isAssignableFrom( javaType ) ) { + return PluralAttribute.CollectionType.COLLECTION; + } + else { + throw new IllegalArgumentException( "Expecting collection type [" + javaType.getName() + "]" ); + } + } + + public static boolean isManyToMany(Member member) { + return Field.class.isInstance( member ) + ? ( (Field) member ).getAnnotation( ManyToMany.class ) != null + : ( (Method) member ).getAnnotation( ManyToMany.class ) != null; + } + + private final MemberResolver EMBEDDED_MEMBER_RESOLVER = new MemberResolver() { + /** + * {@inheritDoc} + */ + public Member resolveMember(AttributeContext attributeContext) { + final EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl ) attributeContext.getOwnerType(); + final String attributeName = attributeContext.getPropertyMapping().getName(); + return embeddableType.getHibernateType() + .getComponentTuplizer() + .getGetter( embeddableType.getHibernateType().getPropertyIndex( attributeName ) ) + .getMember(); + } + }; + + + private final MemberResolver VIRTUAL_IDENTIFIER_MEMBER_RESOLVER = new MemberResolver() { + /** + * {@inheritDoc} + */ + public Member resolveMember(AttributeContext attributeContext) { + final IdentifiableType identifiableType = (IdentifiableType) attributeContext.getOwnerType(); + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + if ( ! entityMetamodel.getIdentifierProperty().isVirtual() ) { + throw new IllegalArgumentException( "expecting IdClass mapping" ); + } + org.hibernate.type.Type type = entityMetamodel.getIdentifierProperty().getType(); + if ( ! EmbeddedComponentType.class.isInstance( type ) ) { + throw new IllegalArgumentException( "expecting IdClass mapping" ); + } + + final EmbeddedComponentType componentType = (EmbeddedComponentType) type; + final String attributeName = attributeContext.getPropertyMapping().getName(); + return componentType.getComponentTuplizer() + .getGetter( componentType.getPropertyIndex( attributeName ) ) + .getMember(); + } + }; + + /** + * A {@link java.lang.reflect.Member} resolver for normal attributes. + */ + private final MemberResolver NORMAL_MEMBER_RESOLVER = new MemberResolver() { + /** + * {@inheritDoc} + */ + public Member resolveMember(AttributeContext attributeContext) { + final AbstractManagedType ownerType = attributeContext.getOwnerType(); + final Property property = attributeContext.getPropertyMapping(); + final Type.PersistenceType persistenceType = ownerType.getPersistenceType(); + if ( Type.PersistenceType.EMBEDDABLE == persistenceType ) { + return EMBEDDED_MEMBER_RESOLVER.resolveMember( attributeContext ); + } + else if ( Type.PersistenceType.ENTITY == persistenceType + || Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) { + final IdentifiableType identifiableType = (IdentifiableType) ownerType; + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final String propertyName = property.getName(); + final Integer index = entityMetamodel.getPropertyIndexOrNull( propertyName ); + if ( index == null ) { + // just like in #determineIdentifierJavaMember , this *should* indicate we have an IdClass mapping + return VIRTUAL_IDENTIFIER_MEMBER_RESOLVER.resolveMember( attributeContext ); + } + else { + return entityMetamodel.getTuplizer() + .getGetter( index ) + .getMember(); + } + } + else { + throw new IllegalArgumentException( "Unexpected owner type : " + persistenceType ); + } + } + }; + + private final MemberResolver IDENTIFIER_MEMBER_RESOLVER = new MemberResolver() { + public Member resolveMember(AttributeContext attributeContext) { + final IdentifiableType identifiableType = (IdentifiableType) attributeContext.getOwnerType(); + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + if ( ! attributeContext.getPropertyMapping().getName() + .equals( entityMetamodel.getIdentifierProperty().getName() ) ) { + // this *should* indicate processing part of an IdClass... + return VIRTUAL_IDENTIFIER_MEMBER_RESOLVER.resolveMember( attributeContext ); + } + return entityMetamodel.getTuplizer().getIdentifierGetter().getMember(); + } + }; + + private final MemberResolver VERSION_MEMBER_RESOLVER = new MemberResolver() { + public Member resolveMember(AttributeContext attributeContext) { + final IdentifiableType identifiableType = (IdentifiableType) attributeContext.getOwnerType(); + final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType ); + final String versionPropertyName = attributeContext.getPropertyMapping().getName(); + if ( ! versionPropertyName.equals( entityMetamodel.getVersionProperty().getName() ) ) { + // this should never happen, but to be safe... + throw new IllegalArgumentException( "Given property did not match declared version property" ); + } + return entityMetamodel.getTuplizer().getVersionGetter().getMember(); + } + }; +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeImplementor.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeImplementor.java new file mode 100644 index 0000000000..0feb57e302 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/AttributeImplementor.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by + * third-party contributors as indicated by either @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.jpa.metamodel.internal.legacy; +import javax.persistence.metamodel.Attribute; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public interface AttributeImplementor extends Attribute { +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/BasicTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/BasicTypeImpl.java new file mode 100644 index 0000000000..ae2f7cc0f8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/BasicTypeImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.BasicType; +import java.io.Serializable; + +/** + * @author Emmanuel Bernard + */ +public class BasicTypeImpl implements BasicType, Serializable { + private final Class clazz; + private PersistenceType persistenceType; + + public PersistenceType getPersistenceType() { + return persistenceType; + } + + public Class getJavaType() { + return clazz; + } + + public BasicTypeImpl(Class clazz, PersistenceType persistenceType) { + this.clazz = clazz; + this.persistenceType = persistenceType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EmbeddableTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EmbeddableTypeImpl.java new file mode 100644 index 0000000000..f62ead89b5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EmbeddableTypeImpl.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.EmbeddableType; +import java.io.Serializable; + +import org.hibernate.type.ComponentType; + +/** + * @author Emmanuel Bernard + */ +public class EmbeddableTypeImpl + extends AbstractManagedType + implements EmbeddableType, Serializable { + + private final AbstractManagedType parent; + private final ComponentType hibernateType; + + public EmbeddableTypeImpl(Class javaType, AbstractManagedType parent, ComponentType hibernateType) { + super( javaType, null ); + this.parent = parent; + this.hibernateType = hibernateType; + } + + public PersistenceType getPersistenceType() { + return PersistenceType.EMBEDDABLE; + } + + public AbstractManagedType getParent() { + return parent; + } + + public ComponentType getHibernateType() { + return hibernateType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EntityTypeImpl.java new file mode 100644 index 0000000000..72b7bcb1c7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/EntityTypeImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.EntityType; +import java.io.Serializable; + +/** + * Defines the Hibernate implementation of the JPA {@link javax.persistence.metamodel.EntityType} contract. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class EntityTypeImpl + extends AbstractIdentifiableType + implements EntityType, Serializable { + private final String jpaEntityName; + + public EntityTypeImpl( + Class javaType, + AbstractIdentifiableType superType, + String jpaEntityName, + boolean hasIdentifierProperty, + boolean isVersioned) { + super( javaType, superType, hasIdentifierProperty, isVersioned ); + this.jpaEntityName = jpaEntityName; + } + + public String getName() { + return jpaEntityName; + } + + public BindableType getBindableType() { + return BindableType.ENTITY_TYPE; + } + + public Class getBindableJavaType() { + return getJavaType(); + } + + public PersistenceType getPersistenceType() { + return PersistenceType.ENTITY; + } + + @Override + protected boolean requiresSupertypeForNonDeclaredIdentifier() { + return true; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MappedSuperclassTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MappedSuperclassTypeImpl.java new file mode 100644 index 0000000000..3f5aca31f1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MappedSuperclassTypeImpl.java @@ -0,0 +1,24 @@ +package org.hibernate.jpa.metamodel.internal.legacy; +import javax.persistence.metamodel.MappedSuperclassType; + +/** + * @author Emmanuel Bernard + */ +public class MappedSuperclassTypeImpl extends AbstractIdentifiableType implements MappedSuperclassType { + public MappedSuperclassTypeImpl( + Class javaType, + AbstractIdentifiableType superType, + boolean hasIdentifierProperty, + boolean versioned) { + super( javaType, superType, hasIdentifierProperty, versioned ); + } + + public PersistenceType getPersistenceType() { + return PersistenceType.MAPPED_SUPERCLASS; + } + + @Override + protected boolean requiresSupertypeForNonDeclaredIdentifier() { + return false; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetadataContext.java new file mode 100644 index 0000000000..63b4b6ac6c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetadataContext.java @@ -0,0 +1,485 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.IdentifiableType; +import javax.persistence.metamodel.MappedSuperclassType; +import javax.persistence.metamodel.SingularAttribute; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.jboss.logging.Logger; + +import org.hibernate.annotations.common.AssertionFailure; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.KeyValue; +import org.hibernate.mapping.MappedSuperclass; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; + +/** + * Defines a context for storing information during the building of the {@link MetamodelImpl}. + *

          + * This contextual information includes data needing to be processed in a second pass as well as + * cross-references into the built metamodel classes. + *

          + * At the end of the day, clients are interested in the {@link #getEntityTypeMap} and {@link #getEmbeddableTypeMap} + * results, which represent all the registered {@linkplain #registerEntityType entities} and + * {@linkplain #registerEmbeddedableType embeddables} respectively. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +class MetadataContext { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, + MetadataContext.class.getName()); + + private final SessionFactoryImplementor sessionFactory; + private final boolean ignoreUnsupported; + private final AttributeFactory attributeFactory = new AttributeFactory( this ); + + private Map,EntityTypeImpl> entityTypes + = new HashMap, EntityTypeImpl>(); + private Map> entityTypesByEntityName + = new HashMap>(); + private Map> entityTypesByPersistentClass + = new HashMap>(); + private Map, EmbeddableTypeImpl> embeddables + = new HashMap, EmbeddableTypeImpl>(); + private Map> mappedSuperclassByMappedSuperclassMapping + = new HashMap>(); + //this list contains MappedSuperclass and EntityTypes ordered by superclass first + private List orderedMappings = new ArrayList(); + /** + * Stack of PersistentClass being process. Last in the list is the highest in the stack. + * + */ + private List stackOfPersistentClassesBeingProcessed + = new ArrayList(); + private Map, PersistentClass> mappedSuperClassTypeToPersistentClass + = new HashMap, PersistentClass>(); + + public MetadataContext(SessionFactoryImplementor sessionFactory, boolean ignoreUnsupported) { + this.sessionFactory = sessionFactory; + this.ignoreUnsupported = ignoreUnsupported; + } + + /*package*/ SessionFactoryImplementor getSessionFactory() { + return sessionFactory; + } + + /*package*/ boolean isIgnoreUnsupported() { + return ignoreUnsupported; + } + + /** + * Retrieves the {@linkplain Class java type} to {@link EntityTypeImpl} map. + * + * @return The {@linkplain Class java type} to {@link EntityTypeImpl} map. + */ + public Map, EntityTypeImpl> getEntityTypeMap() { + return Collections.unmodifiableMap( entityTypes ); + } + + public Map, EmbeddableTypeImpl> getEmbeddableTypeMap() { + return Collections.unmodifiableMap( embeddables ); + } + + public Map,MappedSuperclassType> getMappedSuperclassTypeMap() { + // we need to actually build this map... + final Map,MappedSuperclassType> mappedSuperClassTypeMap = CollectionHelper.mapOfSize( + mappedSuperclassByMappedSuperclassMapping.size() + ); + + for ( MappedSuperclassTypeImpl mappedSuperclassType : mappedSuperclassByMappedSuperclassMapping.values() ) { + mappedSuperClassTypeMap.put( + mappedSuperclassType.getJavaType(), + mappedSuperclassType + ); + } + + return mappedSuperClassTypeMap; + } + + /*package*/ void registerEntityType(PersistentClass persistentClass, EntityTypeImpl entityType) { + entityTypes.put( entityType.getBindableJavaType(), entityType ); + entityTypesByEntityName.put( persistentClass.getEntityName(), entityType ); + entityTypesByPersistentClass.put( persistentClass, entityType ); + orderedMappings.add( persistentClass ); + } + + /*package*/ void registerEmbeddedableType(EmbeddableTypeImpl embeddableType) { + embeddables.put( embeddableType.getJavaType(), embeddableType ); + } + + /*package*/ void registerMappedSuperclassType(MappedSuperclass mappedSuperclass, + MappedSuperclassTypeImpl mappedSuperclassType) { + mappedSuperclassByMappedSuperclassMapping.put( mappedSuperclass, mappedSuperclassType ); + orderedMappings.add( mappedSuperclass ); + mappedSuperClassTypeToPersistentClass.put( mappedSuperclassType, getEntityWorkedOn() ); + } + + /** + * Given a Hibernate {@link org.hibernate.mapping.PersistentClass}, locate the corresponding JPA {@link org.hibernate.type.EntityType} + * implementation. May retur null if the given {@link org.hibernate.mapping.PersistentClass} has not yet been processed. + * + * @param persistentClass The Hibernate (config time) metamodel instance representing an entity. + * @return Tne corresponding JPA {@link org.hibernate.type.EntityType}, or null if not yet processed. + */ + public EntityTypeImpl locateEntityType(PersistentClass persistentClass) { + return entityTypesByPersistentClass.get( persistentClass ); + } + + /** + * Given a Java {@link Class}, locate the corresponding JPA {@link org.hibernate.type.EntityType}. May + * return null which could means that no such mapping exists at least at this time. + * + * @param javaType The java class. + * @return The corresponding JPA {@link org.hibernate.type.EntityType}, or null. + */ + public EntityTypeImpl locateEntityType(Class javaType) { + return entityTypes.get( javaType ); + } + + /** + * Given an entity-name, locate the corresponding JPA {@link org.hibernate.type.EntityType}. May + * return null which could means that no such mapping exists at least at this time. + * + * @param entityName The entity-name. + * @return The corresponding JPA {@link org.hibernate.type.EntityType}, or null. + */ + public EntityTypeImpl locateEntityType(String entityName) { + return entityTypesByEntityName.get( entityName ); + } + + @SuppressWarnings({ "unchecked" }) + public void wrapUp() { + LOG.trace("Wrapping up metadata context..."); + //we need to process types from superclasses to subclasses + for (Object mapping : orderedMappings) { + if ( PersistentClass.class.isAssignableFrom( mapping.getClass() ) ) { + @SuppressWarnings( "unchecked" ) + final PersistentClass safeMapping = (PersistentClass) mapping; + LOG.trace("Starting entity [" + safeMapping.getEntityName() + "]"); + try { + final EntityTypeImpl jpa2Mapping = entityTypesByPersistentClass.get( safeMapping ); + applyIdMetadata( safeMapping, jpa2Mapping ); + applyVersionAttribute( safeMapping, jpa2Mapping ); + Iterator properties = safeMapping.getDeclaredPropertyIterator(); + while ( properties.hasNext() ) { + final Property property = properties.next(); + if ( property.getValue() == safeMapping.getIdentifierMapper() ) { + // property represents special handling for id-class mappings but we have already + // accounted for the embedded property mappings in #applyIdMetadata && + // #buildIdClassAttributes + continue; + } + if ( safeMapping.isVersioned() && property == safeMapping.getVersion() ) { + // skip the version property, it was already handled previously. + continue; + } + final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property ); + if ( attribute != null ) { + jpa2Mapping.getBuilder().addAttribute( attribute ); + } + } + jpa2Mapping.lock(); + populateStaticMetamodel( jpa2Mapping ); + } + finally { + LOG.trace("Completed entity [" + safeMapping.getEntityName() + "]"); + } + } + else if ( MappedSuperclass.class.isAssignableFrom( mapping.getClass() ) ) { + @SuppressWarnings( "unchecked" ) + final MappedSuperclass safeMapping = (MappedSuperclass) mapping; + LOG.trace("Starting mapped superclass [" + safeMapping.getMappedClass().getName() + "]"); + try { + final MappedSuperclassTypeImpl jpa2Mapping = mappedSuperclassByMappedSuperclassMapping.get( + safeMapping + ); + applyIdMetadata( safeMapping, jpa2Mapping ); + applyVersionAttribute( safeMapping, jpa2Mapping ); + Iterator properties = safeMapping.getDeclaredPropertyIterator(); + while ( properties.hasNext() ) { + final Property property = properties.next(); + if ( safeMapping.isVersioned() && property == safeMapping.getVersion() ) { + // skip the version property, it was already handled previously. + continue; + } + final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property ); + if ( attribute != null ) { + jpa2Mapping.getBuilder().addAttribute( attribute ); + } + } + jpa2Mapping.lock(); + populateStaticMetamodel( jpa2Mapping ); + } + finally { + LOG.trace("Completed mapped superclass [" + safeMapping.getMappedClass().getName() + "]"); + } + } + else { + throw new AssertionFailure( "Unexpected mapping type: " + mapping.getClass() ); + } + } + + for ( EmbeddableTypeImpl embeddable : embeddables.values() ) { + populateStaticMetamodel( embeddable ); + } + } + + + private void applyIdMetadata(PersistentClass persistentClass, EntityTypeImpl jpaEntityType) { + if ( persistentClass.hasIdentifierProperty() ) { + final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty(); + if (declaredIdentifierProperty != null) { + jpaEntityType.getBuilder().applyIdAttribute( + attributeFactory.buildIdAttribute( jpaEntityType, declaredIdentifierProperty ) + ); + } + } + else if ( persistentClass.hasIdentifierMapper() ) { + @SuppressWarnings( "unchecked") + Iterator propertyIterator = persistentClass.getIdentifierMapper().getPropertyIterator(); + Set> attributes = buildIdClassAttributes( jpaEntityType, propertyIterator ); + jpaEntityType.getBuilder().applyIdClassAttributes( attributes ); + } + else { + final KeyValue value = persistentClass.getIdentifier(); + if (value instanceof Component ) { + final Component component = ( Component ) value; + if ( component.getPropertySpan() > 1 ) { + //FIXME we are an Hibernate embedded id (ie not type) + } + else { + //FIXME take care of declared vs non declared property + jpaEntityType.getBuilder().applyIdAttribute( + attributeFactory.buildIdAttribute( + jpaEntityType, + (Property) component.getPropertyIterator().next() ) + ); + } + } + } + } + + private void applyIdMetadata(MappedSuperclass mappingType, MappedSuperclassTypeImpl jpaMappingType) { + if ( mappingType.hasIdentifierProperty() ) { + final Property declaredIdentifierProperty = mappingType.getDeclaredIdentifierProperty(); + if (declaredIdentifierProperty != null) { + jpaMappingType.getBuilder().applyIdAttribute( + attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty ) + ); + } + } + //an MappedSuperclass can have no identifier if the id is set below in the hierarchy + else if ( mappingType.getIdentifierMapper() != null ){ + @SuppressWarnings( "unchecked") + Iterator propertyIterator = mappingType.getIdentifierMapper().getPropertyIterator(); + Set> attributes = buildIdClassAttributes( jpaMappingType, propertyIterator ); + jpaMappingType.getBuilder().applyIdClassAttributes( attributes ); + } + } + + private void applyVersionAttribute(PersistentClass persistentClass, EntityTypeImpl jpaEntityType) { + final Property declaredVersion = persistentClass.getDeclaredVersion(); + if (declaredVersion != null) { + jpaEntityType.getBuilder().applyVersionAttribute( + attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion ) + ); + } + } + + private void applyVersionAttribute(MappedSuperclass mappingType, MappedSuperclassTypeImpl jpaMappingType) { + final Property declaredVersion = mappingType.getDeclaredVersion(); + if ( declaredVersion != null ) { + jpaMappingType.getBuilder().applyVersionAttribute( + attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion ) + ); + } + } + + private Set> buildIdClassAttributes( + AbstractIdentifiableType ownerType, + Iterator propertyIterator) { + LOG.trace("Building old-school composite identifier [" + ownerType.getJavaType().getName() + "]"); + Set> attributes = new HashSet>(); + while ( propertyIterator.hasNext() ) { + attributes.add( attributeFactory.buildIdAttribute( ownerType, propertyIterator.next() ) ); + } + return attributes; + } + + private void populateStaticMetamodel(AbstractManagedType managedType) { + final Class managedTypeClass = managedType.getJavaType(); + final String metamodelClassName = managedTypeClass.getName() + "_"; + try { + final Class metamodelClass = Class.forName( metamodelClassName, true, managedTypeClass.getClassLoader() ); + // we found the class; so populate it... + registerAttributes( metamodelClass, managedType ); + } + catch ( ClassNotFoundException ignore ) { + // nothing to do... + } + + // todo : this does not account for @MappeSuperclass, mainly because this is not being tracked in our + // internal metamodel as populated from the annotatios properly + AbstractManagedType superType = managedType.getSupertype(); + if ( superType != null ) { + populateStaticMetamodel( superType ); + } + } + + private final Set processedMetamodelClasses = new HashSet(); + + private void registerAttributes(Class metamodelClass, AbstractManagedType managedType) { + if ( ! processedMetamodelClasses.add( metamodelClass ) ) { + return; + } + + // push the attributes on to the metamodel class... + for ( Attribute attribute : managedType.getDeclaredAttributes() ) { + registerAttribute( metamodelClass, attribute ); + } + + if ( IdentifiableType.class.isInstance( managedType ) ) { + final AbstractIdentifiableType entityType = ( AbstractIdentifiableType ) managedType; + + // handle version + if ( entityType.hasDeclaredVersionAttribute() ) { + registerAttribute( metamodelClass, entityType.getDeclaredVersion() ); + } + + // handle id-class mappings specially + if ( ! entityType.hasSingleIdAttribute() ) { + final Set> attributes = entityType.getIdClassAttributes(); + if ( attributes != null ) { + for ( SingularAttribute attribute : attributes ) { + registerAttribute( metamodelClass, attribute ); + } + } + } + } + } + + private void registerAttribute(Class metamodelClass, Attribute attribute) { + final String name = attribute.getName(); + try { + // there is a shortcoming in the existing Hibernate code in terms of the way MappedSuperclass + // support was bolted on which comes to bear right here when the attribute is an embeddable type + // defined on a MappedSuperclass. We do not have the correct information to determine the + // appropriate attribute declarer in such cases and so the incoming metamodelClass most likely + // does not represent the declarer in such cases. + // + // As a result, in the case of embeddable classes we simply use getField rather than get + // getDeclaredField + final Field field = attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED + ? metamodelClass.getField( name ) + : metamodelClass.getDeclaredField( name ); + try { + if ( ! field.isAccessible() ) { + // should be public anyway, but to be sure... + field.setAccessible( true ); + } + field.set( null, attribute ); + } + catch ( IllegalAccessException e ) { + // todo : exception type? + throw new AssertionFailure( + "Unable to inject static metamodel attribute : " + metamodelClass.getName() + '#' + name, + e + ); + } + catch ( IllegalArgumentException e ) { + // most likely a mismatch in the type we are injecting and the defined field; this represents a + // mismatch in how the annotation processor interpretted the attribute and how our metamodel + // and/or annotation binder did. + +// This is particularly the case as arrays are nto handled propery by the StaticMetamodel generator + +// throw new AssertionFailure( +// "Illegal argument on static metamodel field injection : " + metamodelClass.getName() + '#' + name +// + "; expected type : " + attribute.getClass().getName() +// + "; encountered type : " + field.getType().getName() +// ); + LOG.illegalArgumentOnStaticMetamodelFieldInjection(metamodelClass.getName(), + name, + attribute.getClass().getName(), + field.getType().getName()); + } + } + catch ( NoSuchFieldException e ) { + LOG.unableToLocateStaticMetamodelField(metamodelClass.getName(), name); +// throw new AssertionFailure( +// "Unable to locate static metamodel field : " + metamodelClass.getName() + '#' + name +// ); + } + } + + public MappedSuperclassTypeImpl locateMappedSuperclassType(MappedSuperclass mappedSuperclass) { + return mappedSuperclassByMappedSuperclassMapping.get(mappedSuperclass); + } + + public void pushEntityWorkedOn(PersistentClass persistentClass) { + stackOfPersistentClassesBeingProcessed.add(persistentClass); + } + + public void popEntityWorkedOn(PersistentClass persistentClass) { + final PersistentClass stackTop = stackOfPersistentClassesBeingProcessed.remove( + stackOfPersistentClassesBeingProcessed.size() - 1 + ); + if (stackTop != persistentClass) { + throw new AssertionFailure( "Inconsistent popping: " + + persistentClass.getEntityName() + " instead of " + stackTop.getEntityName() ); + } + } + + private PersistentClass getEntityWorkedOn() { + return stackOfPersistentClassesBeingProcessed.get( + stackOfPersistentClassesBeingProcessed.size() - 1 + ); + } + + public PersistentClass getPersistentClassHostingProperties(MappedSuperclassTypeImpl mappedSuperclassType) { + final PersistentClass persistentClass = mappedSuperClassTypeToPersistentClass.get( mappedSuperclassType ); + if (persistentClass == null) { + throw new AssertionFailure( "Could not find PersistentClass for MappedSuperclassType: " + + mappedSuperclassType.getJavaType() ); + } + return persistentClass; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetamodelImpl.java new file mode 100644 index 0000000000..6fdee63fdf --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/MetamodelImpl.java @@ -0,0 +1,238 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.MappedSuperclassType; +import javax.persistence.metamodel.Metamodel; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.mapping.MappedSuperclass; +import org.hibernate.mapping.PersistentClass; + +/** + * Hibernate implementation of the JPA {@link javax.persistence.metamodel.Metamodel} contract. + * + * @author Steve Ebersole + * @author Emmanuel Bernard + */ +public class MetamodelImpl implements Metamodel, Serializable { + private final Map,EntityTypeImpl> entities; + private final Map, EmbeddableTypeImpl> embeddables; + private final Map, MappedSuperclassType> mappedSuperclassTypeMap; + + /** + * Build the metamodel using the information from the collection of Hibernate + * {@link org.hibernate.mapping.PersistentClass} models as well as the Hibernate {@link org.hibernate.SessionFactory}. + * + * @param persistentClasses Iterator over the Hibernate (config-time) metamodel + * @param sessionFactory The Hibernate session factory. + * @return The built metamodel + * + * @deprecated use {@link #buildMetamodel(java.util.Iterator,org.hibernate.engine.spi.SessionFactoryImplementor,boolean)} instead + */ + @Deprecated + public static MetamodelImpl buildMetamodel( + Iterator persistentClasses, + SessionFactoryImplementor sessionFactory) { + return buildMetamodel(persistentClasses, sessionFactory, false); + } + + /** + * Build the metamodel using the information from the collection of Hibernate + * {@link org.hibernate.mapping.PersistentClass} models as well as the Hibernate {@link org.hibernate.SessionFactory}. + * + * @param persistentClasses Iterator over the Hibernate (config-time) metamodel + * @param sessionFactory The Hibernate session factory. + * @param ignoreUnsupported ignore unsupported/unknown annotations (like @Any) + * @return The built metamodel + */ + public static MetamodelImpl buildMetamodel( + Iterator persistentClasses, + SessionFactoryImplementor sessionFactory, + boolean ignoreUnsupported) { + MetadataContext context = new MetadataContext( sessionFactory, ignoreUnsupported ); + while ( persistentClasses.hasNext() ) { + PersistentClass pc = persistentClasses.next(); + if ( pc.getMappedClass() != null ) { + locateOrBuildEntityType( pc, context ); + } + } + context.wrapUp(); + return new MetamodelImpl( context.getEntityTypeMap(), context.getEmbeddableTypeMap(), context.getMappedSuperclassTypeMap() ); + } + + private static EntityTypeImpl locateOrBuildEntityType(PersistentClass persistentClass, MetadataContext context) { + EntityTypeImpl entityType = context.locateEntityType( persistentClass ); + if ( entityType == null ) { + entityType = buildEntityType( persistentClass, context ); + } + return entityType; + } + + //TODO remove / reduce @SW scope + @SuppressWarnings( "unchecked" ) + private static EntityTypeImpl buildEntityType(PersistentClass persistentClass, MetadataContext context) { + final Class javaType = persistentClass.getMappedClass(); + context.pushEntityWorkedOn(persistentClass); + final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass(); + AbstractIdentifiableType superType = superMappedSuperclass == null + ? null + : locateOrBuildMappedsuperclassType( superMappedSuperclass, context ); + //no mappedSuperclass, check for a super entity + if (superType == null) { + final PersistentClass superPersistentClass = persistentClass.getSuperclass(); + superType = superPersistentClass == null + ? null + : locateOrBuildEntityType( superPersistentClass, context ); + } + EntityTypeImpl entityType = new EntityTypeImpl( + javaType, + superType, + persistentClass.getJpaEntityName(), + persistentClass.hasIdentifierProperty(), + persistentClass.isVersioned() + ); + context.registerEntityType( persistentClass, entityType ); + context.popEntityWorkedOn(persistentClass); + return entityType; + } + + private static MappedSuperclassTypeImpl locateOrBuildMappedsuperclassType( + MappedSuperclass mappedSuperclass, MetadataContext context) { + MappedSuperclassTypeImpl mappedSuperclassType = context.locateMappedSuperclassType( mappedSuperclass ); + if ( mappedSuperclassType == null ) { + mappedSuperclassType = buildMappedSuperclassType(mappedSuperclass, context); + } + return mappedSuperclassType; + } + + //TODO remove / reduce @SW scope + @SuppressWarnings( "unchecked" ) + private static MappedSuperclassTypeImpl buildMappedSuperclassType(MappedSuperclass mappedSuperclass, + MetadataContext context) { + final MappedSuperclass superMappedSuperclass = mappedSuperclass.getSuperMappedSuperclass(); + AbstractIdentifiableType superType = superMappedSuperclass == null + ? null + : locateOrBuildMappedsuperclassType( superMappedSuperclass, context ); + //no mappedSuperclass, check for a super entity + if (superType == null) { + final PersistentClass superPersistentClass = mappedSuperclass.getSuperPersistentClass(); + superType = superPersistentClass == null + ? null + : locateOrBuildEntityType( superPersistentClass, context ); + } + final Class javaType = mappedSuperclass.getMappedClass(); + MappedSuperclassTypeImpl mappedSuperclassType = new MappedSuperclassTypeImpl( + javaType, + superType, + mappedSuperclass.hasIdentifierProperty(), + mappedSuperclass.isVersioned() + ); + context.registerMappedSuperclassType( mappedSuperclass, mappedSuperclassType ); + return mappedSuperclassType; + } + + /** + * Instantiate the metamodel. + * + * @param entities The entity mappings. + * @param embeddables The embeddable (component) mappings. + * @param mappedSuperclassTypeMap The {@link javax.persistence.MappedSuperclass} mappings + */ + private MetamodelImpl( + Map, EntityTypeImpl> entities, + Map, EmbeddableTypeImpl> embeddables, + Map, MappedSuperclassType> mappedSuperclassTypeMap) { + this.entities = entities; + this.embeddables = embeddables; + this.mappedSuperclassTypeMap = mappedSuperclassTypeMap; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public EntityType entity(Class cls) { + final EntityType entityType = entities.get( cls ); + if ( entityType == null ) { + throw new IllegalArgumentException( "Not an entity: " + cls ); + } + return (EntityType) entityType; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public ManagedType managedType(Class cls) { + ManagedType type = entities.get( cls ); + if ( type == null ) { + type = mappedSuperclassTypeMap.get( cls ); + } + if ( type == null ) { + type = embeddables.get( cls ); + } + if ( type == null ) { + throw new IllegalArgumentException( "Not an managed type: " + cls ); + } + return (ManagedType) type; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public EmbeddableType embeddable(Class cls) { + final EmbeddableType embeddableType = embeddables.get( cls ); + if ( embeddableType == null ) { + throw new IllegalArgumentException( "Not an embeddable: " + cls ); + } + return (EmbeddableType) embeddableType; + } + + @Override + public Set> getManagedTypes() { + final int setSize = CollectionHelper.determineProperSizing( + entities.size() + mappedSuperclassTypeMap.size() + embeddables.size() + ); + final Set> managedTypes = new HashSet>( setSize ); + managedTypes.addAll( entities.values() ); + managedTypes.addAll( mappedSuperclassTypeMap.values() ); + managedTypes.addAll( embeddables.values() ); + return managedTypes; + } + + @Override + public Set> getEntities() { + return new HashSet>( entities.values() ); + } + + @Override + public Set> getEmbeddables() { + return new HashSet>( embeddables.values() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/PluralAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/PluralAttributeImpl.java new file mode 100644 index 0000000000..688317b450 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/PluralAttributeImpl.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.CollectionAttribute; +import javax.persistence.metamodel.ListAttribute; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SetAttribute; +import javax.persistence.metamodel.Type; +import java.io.Serializable; +import java.lang.reflect.Member; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hibernate.mapping.Property; + +/** + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public abstract class PluralAttributeImpl + extends AbstractAttribute + implements PluralAttribute, Serializable { + + private final Type elementType; + + private PluralAttributeImpl(Builder builder) { + super( + builder.property.getName(), + builder.collectionClass, + builder.type, + builder.member, + builder.persistentAttributeType + ); + this.elementType = builder.attributeType; + } + + public static class Builder { + private final Type attributeType; + private final AbstractManagedType type; + private Member member; + private PersistentAttributeType persistentAttributeType; + private Property property; + private Class collectionClass; + private Type keyType; + + + private Builder(AbstractManagedType ownerType, Type attrType, Class collectionClass, Type keyType) { + this.type = ownerType; + this.attributeType = attrType; + this.collectionClass = collectionClass; + this.keyType = keyType; + } + + public Builder member(Member member) { + this.member = member; + return this; + } + + public Builder property(Property property) { + this.property = property; + return this; + } + + public Builder persistentAttributeType(PersistentAttributeType attrType) { + this.persistentAttributeType = attrType; + return this; + } + + @SuppressWarnings( "unchecked" ) + public PluralAttributeImpl build() { + //apply strict spec rules first + if ( Map.class.equals( collectionClass ) ) { + final Builder,E,K> builder = (Builder,E,K>) this; + return ( PluralAttributeImpl ) new MapAttributeImpl( + builder + ); + } + else if ( Set.class.equals( collectionClass ) ) { + final Builder, E,?> builder = (Builder, E,?>) this; + return ( PluralAttributeImpl ) new SetAttributeImpl( + builder + ); + } + else if ( List.class.equals( collectionClass ) ) { + final Builder, E,?> builder = (Builder, E,?>) this; + return ( PluralAttributeImpl ) new ListAttributeImpl( + builder + ); + } + else if ( Collection.class.equals( collectionClass ) ) { + final Builder,E,?> builder = (Builder, E,?>) this; + return ( PluralAttributeImpl ) new CollectionAttributeImpl( + builder + ); + } + + //apply loose rules + if ( Map.class.isAssignableFrom( collectionClass ) ) { + final Builder,E,K> builder = (Builder,E,K>) this; + return ( PluralAttributeImpl ) new MapAttributeImpl( + builder + ); + } + else if ( Set.class.isAssignableFrom( collectionClass ) ) { + final Builder, E,?> builder = (Builder, E,?>) this; + return ( PluralAttributeImpl ) new SetAttributeImpl( + builder + ); + } + else if ( List.class.isAssignableFrom( collectionClass ) ) { + final Builder, E,?> builder = (Builder, E,?>) this; + return ( PluralAttributeImpl ) new ListAttributeImpl( + builder + ); + } + else if ( Collection.class.isAssignableFrom( collectionClass ) ) { + final Builder,E,?> builder = (Builder, E,?>) this; + return ( PluralAttributeImpl ) new CollectionAttributeImpl( + builder + ); + } + throw new UnsupportedOperationException( "Unkown collection: " + collectionClass ); + } + } + + public static Builder create( + AbstractManagedType ownerType, + Type attrType, + Class collectionClass, + Type keyType) { + return new Builder(ownerType, attrType, collectionClass, keyType); + } + + /** + * {@inheritDoc} + */ + public Type getElementType() { + return elementType; + } + + /** + * {@inheritDoc} + */ + public boolean isAssociation() { + return true; + } + + /** + * {@inheritDoc} + */ + public boolean isCollection() { + return true; + } + + /** + * {@inheritDoc} + */ + public BindableType getBindableType() { + return BindableType.PLURAL_ATTRIBUTE; + } + + /** + * {@inheritDoc} + */ + public Class getBindableJavaType() { + return elementType.getJavaType(); + } + + static class SetAttributeImpl extends PluralAttributeImpl,E> implements SetAttribute { + SetAttributeImpl(Builder,E,?> xceBuilder) { + super( xceBuilder ); + } + + /** + * {@inheritDoc} + */ + public CollectionType getCollectionType() { + return CollectionType.SET; + } + } + + static class CollectionAttributeImpl extends PluralAttributeImpl,E> implements CollectionAttribute { + CollectionAttributeImpl(Builder,E,?> xceBuilder) { + super( xceBuilder ); + } + + /** + * {@inheritDoc} + */ + public CollectionType getCollectionType() { + return CollectionType.COLLECTION; + } + } + + static class ListAttributeImpl extends PluralAttributeImpl,E> implements ListAttribute { + ListAttributeImpl(Builder,E,?> xceBuilder) { + super( xceBuilder ); + } + + /** + * {@inheritDoc} + */ + public CollectionType getCollectionType() { + return CollectionType.LIST; + } + } + + static class MapAttributeImpl extends PluralAttributeImpl,V> implements MapAttribute { + private final Type keyType; + + MapAttributeImpl(Builder,V,K> xceBuilder) { + super( xceBuilder ); + this.keyType = xceBuilder.keyType; + } + + /** + * {@inheritDoc} + */ + public CollectionType getCollectionType() { + return CollectionType.MAP; + } + + /** + * {@inheritDoc} + */ + public Class getKeyJavaType() { + return keyType.getJavaType(); + } + + /** + * {@inheritDoc} + */ + public Type getKeyType() { + return keyType; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/SingularAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/SingularAttributeImpl.java new file mode 100644 index 0000000000..229d9214b9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/internal/legacy/SingularAttributeImpl.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.jpa.metamodel.internal.legacy; + +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type; +import java.io.Serializable; +import java.lang.reflect.Member; + +/** + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public class SingularAttributeImpl + extends AbstractAttribute + implements SingularAttribute, Serializable { + private final boolean isIdentifier; + private final boolean isVersion; + private final boolean isOptional; + private final Type attributeType; + + public SingularAttributeImpl( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + boolean isIdentifier, + boolean isVersion, + boolean isOptional, + Type attributeType, + PersistentAttributeType persistentAttributeType) { + super( name, javaType, declaringType, member, persistentAttributeType ); + this.isIdentifier = isIdentifier; + this.isVersion = isVersion; + this.isOptional = isOptional; + this.attributeType = attributeType; + } + + /** + * Subclass used to simply instantiation of singular attributes representing an entity's + * identifier. + */ + public static class Identifier extends SingularAttributeImpl { + public Identifier( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + Type attributeType, + PersistentAttributeType persistentAttributeType) { + super( name, javaType, declaringType, member, true, false, false, attributeType, persistentAttributeType ); + } + } + + /** + * Subclass used to simply instantiation of singular attributes representing an entity's + * version. + */ + public static class Version extends SingularAttributeImpl { + public Version( + String name, + Class javaType, + AbstractManagedType declaringType, + Member member, + Type attributeType, + PersistentAttributeType persistentAttributeType) { + super( name, javaType, declaringType, member, false, true, false, attributeType, persistentAttributeType ); + } + } + + /** + * {@inheritDoc} + */ + public boolean isId() { + return isIdentifier; + } + + /** + * {@inheritDoc} + */ + public boolean isVersion() { + return isVersion; + } + + /** + * {@inheritDoc} + */ + public boolean isOptional() { + return isOptional; + } + + /** + * {@inheritDoc} + */ + public Type getType() { + return attributeType; + } + + /** + * {@inheritDoc} + */ + public boolean isAssociation() { + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isCollection() { + return false; + } + + /** + * {@inheritDoc} + */ + public BindableType getBindableType() { + return BindableType.SINGULAR_ATTRIBUTE; + } + + /** + * {@inheritDoc} + */ + public Class getBindableJavaType() { + return attributeType.getJavaType(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/package-info.java b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/package-info.java new file mode 100644 index 0000000000..d08fb682df --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/metamodel/package-info.java @@ -0,0 +1 @@ +package org.hibernate.jpa.metamodel; \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/package-info.java b/hibernate-core/src/main/java/org/hibernate/jpa/package-info.java new file mode 100644 index 0000000000..a5f1d30e7e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/package-info.java @@ -0,0 +1 @@ +package org.hibernate.jpa; \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java b/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java index ff65032bbe..fbbf47b4f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/MetadataSources.java @@ -39,6 +39,7 @@ import org.jboss.logging.Logger; import org.w3c.dom.Document; +import org.hibernate.boot.spi.CacheRegionDefinition; import org.hibernate.internal.jaxb.JaxbRoot; import org.hibernate.internal.jaxb.Origin; import org.hibernate.internal.jaxb.SourceType; @@ -60,8 +61,11 @@ public class MetadataSources { private List jaxbRootList = new ArrayList(); private LinkedHashSet> annotatedClasses = new LinkedHashSet>(); + private LinkedHashSet annotatedClassNames = new LinkedHashSet(); private LinkedHashSet annotatedPackages = new LinkedHashSet(); + private final List externalCacheRegionDefinitions = new ArrayList(); + private final JaxbHelper jaxbHelper; private final ServiceRegistry serviceRegistry; @@ -92,6 +96,14 @@ public Iterable> getAnnotatedClasses() { return annotatedClasses; } + public Iterable getAnnotatedClassNames() { + return annotatedClassNames; + } + + public List getExternalCacheRegionDefinitions() { + return externalCacheRegionDefinitions; + } + public ServiceRegistry getServiceRegistry() { return serviceRegistry; } @@ -128,6 +140,18 @@ public MetadataSources addAnnotatedClass(Class annotatedClass) { return this; } + /** + * Read metadata from the annotations attached to the given class. + * + * @param annotatedClassName The name of a class containing annotations + * + * @return this (for method chaining) + */ + public MetadataSources addAnnotatedClassName(String annotatedClassName) { + annotatedClassNames.add( annotatedClassName ); + return this; + } + /** * Read package-level metadata. * @@ -383,4 +407,9 @@ else if ( file.getName().endsWith( ".hbm.xml" ) ) { } return this; } + + public MetadataSources addCacheRegionDefinitions(List cacheRegionDefinitions) { + externalCacheRegionDefinitions.addAll( cacheRegionDefinitions ); + return this; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java index 7c344e3630..33634d9db1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java @@ -79,6 +79,7 @@ import org.hibernate.metamodel.spi.binding.PluralAttributeBinding; import org.hibernate.metamodel.spi.binding.PluralAttributeElementNature; import org.hibernate.metamodel.spi.binding.PluralAttributeIndexBinding; +import org.hibernate.metamodel.spi.binding.PluralAttributeIndexNature; import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding; import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.SecondaryTable; @@ -183,6 +184,8 @@ public class Binder { private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class + // todo : apply org.hibernate.metamodel.MetadataSources.getExternalCacheRegionDefinitions() + public Binder( final MetadataImplementor metadata, final IdentifierGeneratorFactory identifierGeneratorFactory ) { this.metadata = metadata; this.identifierGeneratorFactory = identifierGeneratorFactory; @@ -648,6 +651,7 @@ private AbstractPluralAttributeBinding bindMapAttribute( return attributeBindingContainer.makeMapAttributeBinding( attribute, pluralAttributeElementNature( attributeSource ), + pluralAttributeIndexNature( attributeSource ), determinePluralAttributeKeyReferencedBinding( attributeBindingContainer, attributeSource ), propertyAccessorName( attributeSource ), attributeSource.isIncludedInOptimisticLocking(), @@ -2022,10 +2026,19 @@ private void mapSourcesByName( final EntitySource entitySource ) { } } - private PluralAttributeElementNature pluralAttributeElementNature( final PluralAttributeSource attributeSource ) { + private PluralAttributeElementNature pluralAttributeElementNature(PluralAttributeSource attributeSource) { return PluralAttributeElementNature.valueOf( attributeSource.getElementSource().getNature().name() ); } + private PluralAttributeIndexNature pluralAttributeIndexNature(PluralAttributeSource attributeSource) { + if ( ! IndexedPluralAttributeSource.class.isInstance( attributeSource ) ) { + return null; + } + return PluralAttributeIndexNature.valueOf( + ( (IndexedPluralAttributeSource) attributeSource ).getIndexSource().getNature().name() + ); + } + private SingularAttributeBinding determinePluralAttributeKeyReferencedBinding( final AttributeBindingContainer attributeBindingContainer, final PluralAttributeSource attributeSource ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/AnnotationMetadataSourceProcessorImpl.java index cf4e5d8c93..c726947aa1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -72,12 +72,19 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc public AnnotationMetadataSourceProcessorImpl(MetadataImpl metadata, MetadataSources metadataSources) { this.metadata = metadata; + // todo : use the Jandex from JBoss/JPA if available... + // todo : cache the built index if no inputs have changed (look at gradle-style hashing for up-to-date checking) + // create a jandex index from the annotated classes Indexer indexer = new Indexer(); for ( Class clazz : metadataSources.getAnnotatedClasses() ) { indexClass( indexer, clazz.getName().replace( '.', '/' ) + ".class" ); } + for ( String className : metadataSources.getAnnotatedClassNames() ) { + indexClass( indexer, className.replace( '.', '/' ) + ".class" ); + } + // add package-info from the configured packages for ( String packageName : metadataSources.getAnnotatedPackages() ) { indexClass( indexer, packageName.replace( '.', '/' ) + "/package-info.class" ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/ListAttributeIndexSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/ListAttributeIndexSource.java index 218d6885bf..a45ed861e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/ListAttributeIndexSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/ListAttributeIndexSource.java @@ -31,6 +31,7 @@ import org.hibernate.internal.jaxb.mapping.hbm.JaxbIndexElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbListIndexElement; import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource; +import org.hibernate.metamodel.spi.source.PluralAttributeIndexNature; import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource; import org.hibernate.metamodel.spi.source.RelationalValueSource; @@ -38,7 +39,6 @@ * */ public class ListAttributeIndexSource extends AbstractHbmSourceNode implements PluralAttributeIndexSource { - private final List< RelationalValueSource > valueSources; private final ExplicitHibernateTypeSource typeSource; private final int base; @@ -123,31 +123,16 @@ public Map< String, String > getParameters() { base = 0; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesIncludedInInsertByDefault() - */ @Override public boolean areValuesIncludedInInsertByDefault() { return true; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesIncludedInUpdateByDefault() - */ @Override public boolean areValuesIncludedInUpdateByDefault() { return true; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesNullableByDefault() - */ @Override public boolean areValuesNullableByDefault() { return false; @@ -157,21 +142,16 @@ public int base() { return base; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.PluralAttributeIndexSource#explicitHibernateTypeSource() - */ + @Override + public PluralAttributeIndexNature getNature() { + return PluralAttributeIndexNature.BASIC; + } + @Override public ExplicitHibernateTypeSource explicitHibernateTypeSource() { return typeSource; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.RelationalValueSourceContainer#relationalValueSources() - */ @Override public List< RelationalValueSource > relationalValueSources() { return valueSources; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeIndexSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeIndexSource.java index f886d573c8..e078cb1fbf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeIndexSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeIndexSource.java @@ -30,6 +30,7 @@ import org.hibernate.internal.jaxb.mapping.hbm.JaxbIndexElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbMapKeyElement; import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource; +import org.hibernate.metamodel.spi.source.PluralAttributeIndexNature; import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource; import org.hibernate.metamodel.spi.source.RelationalValueSource; @@ -37,49 +38,48 @@ * */ public class MapAttributeIndexSource extends AbstractHbmSourceNode implements PluralAttributeIndexSource { - - private final List< RelationalValueSource > valueSources; + private final PluralAttributeIndexNature nature; + private final List valueSources; private final ExplicitHibernateTypeSource typeSource; - /** - * @param sourceMappingDocument - */ - public MapAttributeIndexSource( MappingDocument sourceMappingDocument, final JaxbMapKeyElement mapKey ) { + public MapAttributeIndexSource(MappingDocument sourceMappingDocument, final JaxbMapKeyElement mapKey) { super( sourceMappingDocument ); - valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() { + valueSources = Helper.buildValueSources( + sourceMappingDocument(), + new Helper.ValueSourcesAdapter() { - @Override - public String getColumnAttribute() { - return mapKey.getColumnAttribute(); - } + @Override + public String getColumnAttribute() { + return mapKey.getColumnAttribute(); + } - @Override - public List getColumn() { - return mapKey.getColumn(); - } + @Override + public List getColumn() { + return mapKey.getColumn(); + } - @Override - public List getFormula() { - return mapKey.getFormula(); - } + @Override + public List getFormula() { + return mapKey.getFormula(); + } - @Override - public String getFormulaAttribute() { - return mapKey.getFormulaAttribute(); - } + @Override + public String getFormulaAttribute() { + return mapKey.getFormulaAttribute(); + } - @Override - public boolean isIncludedInInsertByDefault() { - return areValuesIncludedInInsertByDefault(); - } + @Override + public boolean isIncludedInInsertByDefault() { + return areValuesIncludedInInsertByDefault(); + } - @Override - public boolean isIncludedInUpdateByDefault() { - return areValuesIncludedInUpdateByDefault(); - } - } ); + @Override + public boolean isIncludedInUpdateByDefault() { + return areValuesIncludedInUpdateByDefault(); + } + } + ); this.typeSource = new ExplicitHibernateTypeSource() { - @Override public String getName() { if ( mapKey.getTypeAttribute() != null ) { @@ -92,99 +92,84 @@ public String getName() { } @Override - public Map< String, String > getParameters() { + public Map getParameters() { return mapKey.getType() != null ? Helper.extractParameters( mapKey.getType().getParam() ) - : java.util.Collections.< String, String >emptyMap(); + : java.util.Collections.emptyMap(); } }; + this.nature = PluralAttributeIndexNature.BASIC; } - public MapAttributeIndexSource( MappingDocument sourceMappingDocument, final JaxbIndexElement indexElement ) { + public MapAttributeIndexSource(MappingDocument sourceMappingDocument, final JaxbIndexElement indexElement) { super( sourceMappingDocument ); - valueSources = Helper.buildValueSources( sourceMappingDocument, new Helper.ValueSourcesAdapter() { + valueSources = Helper.buildValueSources( + sourceMappingDocument, + new Helper.ValueSourcesAdapter() { - @Override - public String getColumnAttribute() { - return indexElement.getColumnAttribute(); - } + @Override + public String getColumnAttribute() { + return indexElement.getColumnAttribute(); + } - @Override - public List getColumn() { - return indexElement.getColumn(); - } + @Override + public List getColumn() { + return indexElement.getColumn(); + } - @Override - public boolean isIncludedInInsertByDefault() { - return areValuesIncludedInInsertByDefault(); - } + @Override + public boolean isIncludedInInsertByDefault() { + return areValuesIncludedInInsertByDefault(); + } - @Override - public boolean isIncludedInUpdateByDefault() { - return areValuesIncludedInUpdateByDefault(); - } - } ); + @Override + public boolean isIncludedInUpdateByDefault() { + return areValuesIncludedInUpdateByDefault(); + } + } + ); typeSource = new ExplicitHibernateTypeSource() { - @Override public String getName() { return indexElement.getType(); } @Override - public Map< String, String > getParameters() { - return java.util.Collections.< String, String >emptyMap(); + public Map getParameters() { + return java.util.Collections.emptyMap(); } }; + + this.nature = PluralAttributeIndexNature.BASIC; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesIncludedInInsertByDefault() - */ @Override public boolean areValuesIncludedInInsertByDefault() { return true; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesIncludedInUpdateByDefault() - */ @Override public boolean areValuesIncludedInUpdateByDefault() { return true; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesNullableByDefault() - */ @Override public boolean areValuesNullableByDefault() { return false; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.PluralAttributeIndexSource#explicitHibernateTypeSource() - */ + @Override + public PluralAttributeIndexNature getNature() { + return nature; + } + @Override public ExplicitHibernateTypeSource explicitHibernateTypeSource() { return typeSource; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.RelationalValueSourceContainer#relationalValueSources() - */ @Override - public List< RelationalValueSource > relationalValueSources() { + public List relationalValueSources() { return valueSources; } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeSource.java index 5fdef9ecef..41f584b76b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MapAttributeSource.java @@ -51,7 +51,8 @@ public MapAttributeSource( JaxbMapKeyElement mapKey = mapElement.getMapKey(); if ( mapKey != null ) { this.indexSource = new MapAttributeIndexSource( sourceMappingDocument, mapKey ); - } else { + } + else { JaxbIndexElement indexElement = mapElement.getIndex(); if ( indexElement != null ) { this.indexSource = new MapAttributeIndexSource( sourceMappingDocument, indexElement ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java index 86e36e8ae9..4526334daf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import org.hibernate.AssertionFailure; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java index 5ae26c5f5c..d0f4ce1f8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AttributeBindingContainer.java @@ -195,7 +195,8 @@ public ListBinding makeListAttributeBinding( * * * @param attribute The attribute for which to make a binding. - * @param nature The nature of the collection elements. + * @param elementNature The nature of the collection elements. + * @param indexNature The nature of the collection indexes. * @param referencedAttributeBinding * @param propertyAccessorName * @param includedInOptimisticLocking @@ -205,7 +206,8 @@ public ListBinding makeListAttributeBinding( */ public MapBinding makeMapAttributeBinding( PluralAttribute attribute, - PluralAttributeElementNature nature, + PluralAttributeElementNature elementNature, + PluralAttributeIndexNature indexNature, SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeIndexBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeIndexBinding.java index 4c8ff5ef33..871912efc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeIndexBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeIndexBinding.java @@ -23,6 +23,8 @@ */ package org.hibernate.metamodel.spi.binding; +import org.hibernate.metamodel.spi.domain.IndexedPluralAttribute; +import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.metamodel.spi.relational.Value; /** @@ -30,48 +32,44 @@ */ public class BasicPluralAttributeIndexBinding implements PluralAttributeIndexBinding { - private final AbstractPluralAttributeBinding pluralAttributeBinding; + private final IndexedPluralAttributeBinding pluralAttributeBinding; + private final PluralAttributeIndexNature pluralAttributeIndexNature; private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); private Value value; - /** - * @param pluralAttributeBinding - */ - public BasicPluralAttributeIndexBinding( final AbstractPluralAttributeBinding pluralAttributeBinding ) { + public BasicPluralAttributeIndexBinding( + IndexedPluralAttributeBinding pluralAttributeBinding, + PluralAttributeIndexNature pluralAttributeIndexNature) { this.pluralAttributeBinding = pluralAttributeBinding; + this.pluralAttributeIndexNature = pluralAttributeIndexNature; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.binding.PluralAttributeIndexBinding#getHibernateTypeDescriptor() - */ @Override public HibernateTypeDescriptor getHibernateTypeDescriptor() { return hibernateTypeDescriptor; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.binding.PluralAttributeIndexBinding#getIndexRelationalValue() - */ @Override public Value getIndexRelationalValue() { return value; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.binding.PluralAttributeIndexBinding#getPluralAttributeBinding() - */ @Override - public PluralAttributeBinding getPluralAttributeBinding() { + public IndexedPluralAttributeBinding getPluralAttributeBinding() { return pluralAttributeBinding; } public void setIndexRelationalValue( Value value ) { this.value = value; } + + @Override + public Type getPluralAttributeIndexType() { + return ( (IndexedPluralAttribute) getPluralAttributeBinding().getAttribute() ).getIndexType(); + } + + @Override + public PluralAttributeIndexNature getPluralAttributeIndexNature() { + return pluralAttributeIndexNature; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java index 2e8ae2754e..1e548979b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java @@ -348,7 +348,8 @@ public ListBinding makeListAttributeBinding( @Override public MapBinding makeMapAttributeBinding( PluralAttribute attribute, - PluralAttributeElementNature nature, + PluralAttributeElementNature elementNature, + PluralAttributeIndexNature indexNature, SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, @@ -357,7 +358,8 @@ public MapBinding makeMapAttributeBinding( final MapBinding binding = new MapBinding( this, attribute, - nature, + elementNature, + indexNature, referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java index 09e478209a..51750b2fc4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/EntityBinding.java @@ -643,7 +643,8 @@ public ListBinding makeListAttributeBinding( @Override public MapBinding makeMapAttributeBinding( PluralAttribute attribute, - PluralAttributeElementNature nature, + PluralAttributeElementNature elementNature, + PluralAttributeIndexNature indexNature, SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, @@ -652,7 +653,8 @@ public MapBinding makeMapAttributeBinding( final MapBinding binding = new MapBinding( this, attribute, - nature, + elementNature, + indexNature, referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ListBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ListBinding.java index 685cb09e62..b633d35954 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ListBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ListBinding.java @@ -51,7 +51,7 @@ public ListBinding( propertyAccessorName, includedInOptimisticLocking, metaAttributeContext ); - pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this ); + pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this, PluralAttributeIndexNature.BASIC ); this.base = base; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/MapBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/MapBinding.java index ca789b8b0c..df5d0688be 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/MapBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/MapBinding.java @@ -37,6 +37,7 @@ public MapBinding( AttributeBindingContainer container, PluralAttribute attribute, PluralAttributeElementNature pluralAttributeElementNature, + PluralAttributeIndexNature pluralAttributeIndexNature, SingularAttributeBinding referencedAttributeBinding, String propertyAccessorName, boolean includedInOptimisticLocking, @@ -48,8 +49,9 @@ public MapBinding( referencedAttributeBinding, propertyAccessorName, includedInOptimisticLocking, - metaAttributeContext ); - pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this ); + metaAttributeContext + ); + pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this, pluralAttributeIndexNature ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeBinding.java index 8fcd3b9a6b..eb67b1bdef 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeBinding.java @@ -28,7 +28,6 @@ import org.hibernate.internal.FilterConfiguration; import org.hibernate.metamodel.spi.domain.PluralAttribute; -import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.persister.collection.CollectionPersister; /** diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexBinding.java index 54afb67d40..25dbf27d9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexBinding.java @@ -23,16 +23,20 @@ */ package org.hibernate.metamodel.spi.binding; +import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.metamodel.spi.relational.Value; /** * @author Steve Ebersole */ public interface PluralAttributeIndexBinding { + IndexedPluralAttributeBinding getPluralAttributeBinding(); - PluralAttributeBinding getPluralAttributeBinding(); + PluralAttributeIndexNature getPluralAttributeIndexNature(); Value getIndexRelationalValue(); HibernateTypeDescriptor getHibernateTypeDescriptor(); + + Type getPluralAttributeIndexType(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexNature.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexNature.java new file mode 100644 index 0000000000..b0f09153b4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeIndexNature.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.binding; + +/** + * Describes the nature of plural attribute indexes in terms of relational implications. + * + * @author Steve Ebersole + */ +public enum PluralAttributeIndexNature { + /** + * The collection indexes are basic, simple values. This is the only valid nature for lists + */ + BASIC, + /** + * The map key is a composite + */ + COMPOSITE, + /** + * The map key is an association identified by a column(s) on the collection table. + */ + MANY_TO_MANY, + /** + * The map key is represented by a Hibernate ANY mapping + */ + MANY_TO_ANY +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java index ef1c59283a..565645e00b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java @@ -24,6 +24,7 @@ package org.hibernate.metamodel.spi.binding; import org.hibernate.AssertionFailure; +import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.ForeignKey; import org.hibernate.metamodel.spi.relational.TableSpecification; @@ -67,6 +68,7 @@ public AbstractPluralAttributeBinding getPluralAttributeBinding() { public SingularAttributeBinding getReferencedAttributeBinding() { return referencedAttributeBinding; } + /** * The foreign key that defines the scope of this relationship. * diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexNature.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexNature.java new file mode 100644 index 0000000000..ffec8940bd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexNature.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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; + +/** + * Describes the nature of the collection indexes as declared by the sources. + * + * @author Steve Ebersole + * + * @see {@link org.hibernate.metamodel.spi.binding.PluralAttributeIndexNature} + */ +public enum PluralAttributeIndexNature { + BASIC, + COMPOSITE, + MANY_TO_MANY, + MANY_TO_ANY +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexSource.java index 2a570240ed..6ac7925a18 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeIndexSource.java @@ -27,6 +27,6 @@ * */ public interface PluralAttributeIndexSource extends RelationalValueSourceContainer { - + PluralAttributeIndexNature getNature(); ExplicitHibernateTypeSource explicitHibernateTypeSource(); } diff --git a/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java index 3395938948..dabc58915c 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistryBuilder.java @@ -76,6 +76,15 @@ public ServiceRegistryBuilder(BootstrapServiceRegistry bootstrapServiceRegistry) this.configLoader = new ConfigLoader( bootstrapServiceRegistry ); } + /** + * Allows access to the underlying boot-strap registry. + * + * @return The boot-strap registry + */ + public BootstrapServiceRegistry getBootstrapServiceRegistry() { + return bootstrapServiceRegistry; + } + /** * Used from the {@link #initiators} variable initializer * diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java index fad73cf6df..83790b6aa8 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java @@ -31,7 +31,7 @@ * * @author Steve Ebersole */ -public interface AvailableSettings { +public interface AvailableSettings extends org.hibernate.cfg.AvailableSettings { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JPA defined settings @@ -192,6 +192,17 @@ public interface AvailableSettings { // Hibernate specific settings // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /** + * Names a {@link org.hibernate.jpa.boot.spi.IntegratorProvider} to supply custom Integrator instances to + * the underlying SessionFactory when built. + */ + public static final String INTEGRATOR_PROVIDER = "hibernate.integrator_provider"; + + /** + * Names a Jandex {@link org.jboss.jandex.Index} instance to use, as opposed to Hibernate using its own. + */ + public static final String JANDEX_INDEX = "hibernate.jandex_index"; + /** * Query hint (aka {@link javax.persistence.Query#setHint}) for applying * an alias specific lock mode (aka {@link org.hibernate.Query#setLockMode}). @@ -292,7 +303,7 @@ public interface AvailableSettings { public static final String FLUSH_MODE = "org.hibernate.flushMode"; /** - * Pass an implementation of {@link org.hibernate.ejb.packaging.Scanner}: + * Pass an implementation of {@link org.hibernate.jpa.packaging.spi.Scanner}: * - preferably an actual instance * - or a class name with a no-arg constructor */ @@ -315,30 +326,6 @@ public interface AvailableSettings { */ public static final String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name"; - /** - * @deprecated use {@link #JPA_METAMODEL_POPULATION} instead. - */ - @Deprecated - public static final String JPA_METAMODEL_GENERATION = "hibernate.ejb.metamodel.generation"; - - /** - * Setting that controls whether we seek out JPA "static metamodel" classes and populate them. Accepts - * 3 values:
            - *
          • - * enabled - Do the population - *
          • - *
          • - * disabled - Do not do the population - *
          • - *
          • - * ignoreUnsupported - Do the population, but ignore any non-JPA features that would otherwise - * result in the population failing. - *
          • - *
          - * - */ - public static final String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population"; - /** * List of classes names diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index aa4d514b12..fc62d17a29 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -42,9 +42,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; @@ -66,25 +64,24 @@ import org.hibernate.MappingNotFoundException; import org.hibernate.SessionFactory; import org.hibernate.SessionFactoryObserver; +import org.hibernate.boot.spi.CacheRegionDefinition; +import org.hibernate.boot.spi.JaccDefinition; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; -import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory; import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory; -import org.hibernate.integrator.spi.Integrator; -import org.hibernate.internal.jaxb.cfg.JaxbHibernateConfiguration; +import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; import org.hibernate.internal.util.StringHelper; -import org.hibernate.internal.util.ValueHolder; +import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; import org.hibernate.jpa.boot.spi.IntegratorProvider; +import org.hibernate.jpa.boot.spi.JpaUnifiedSettingsBuilder; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; import org.hibernate.jpa.internal.EntityManagerFactoryImpl; import org.hibernate.jpa.internal.EntityManagerMessageLogger; -import org.hibernate.jpa.internal.event.JpaIntegrator; import org.hibernate.jpa.internal.util.LogHelper; import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper; import org.hibernate.jpa.packaging.internal.NativeScanner; @@ -96,13 +93,14 @@ import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.secure.internal.JACCConfiguration; import org.hibernate.service.BootstrapServiceRegistry; -import org.hibernate.service.BootstrapServiceRegistryBuilder; -import org.hibernate.service.ConfigLoader; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.classloading.spi.ClassLoaderService; import org.hibernate.service.spi.ServiceRegistryImplementor; +import static org.hibernate.internal.jaxb.cfg.JaxbHibernateConfiguration.JaxbSessionFactory.JaxbMapping; +import static org.hibernate.jpa.boot.spi.JpaBootstrapServiceRegistryBuilder.buildBootstrapServiceRegistry; + /** * @author Steve Ebersole */ @@ -137,7 +135,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil private final List jaccDefinitions = new ArrayList(); private final List cacheRegionDefinitions = new ArrayList(); // todo : would much prefer this as a local variable... - private final List cfgXmlNamedMappings = new ArrayList(); + private final List cfgXmlNamedMappings = new ArrayList(); private Interceptor sessionFactoryInterceptor; private NamingStrategy namingStrategy; private SessionFactoryObserver suppliedSessionFactoryObserver; @@ -164,7 +162,7 @@ public EntityManagerFactoryBuilderImpl(PersistenceUnitDescriptor persistenceUnit // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // First we build the boot-strap service registry, which mainly handles class loader interactions - final BootstrapServiceRegistry bootstrapServiceRegistry = buildBootstrapServiceRegistry( integrationSettings ); + final BootstrapServiceRegistry bootstrapServiceRegistry = buildBootstrapServiceRegistry( persistenceUnit, integrationSettings ); // And the main service registry. This is needed to start adding configuration values, etc this.serviceRegistryBuilder = new ServiceRegistryBuilder( bootstrapServiceRegistry ); @@ -195,6 +193,25 @@ public EntityManagerFactoryBuilderImpl(PersistenceUnitDescriptor persistenceUnit } } + @SuppressWarnings("unchecked") + private Map mergePropertySources( + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettings, + final BootstrapServiceRegistry bootstrapServiceRegistry) { + + JpaUnifiedSettingsBuilder.Result mergedResult = JpaUnifiedSettingsBuilder.mergePropertySources( + persistenceUnit, + integrationSettings, + bootstrapServiceRegistry + ); + + cfgXmlNamedMappings.addAll( mergedResult.getCfgXmlMappingArtifacts().getMappings() ); + cacheRegionDefinitions.addAll( mergedResult.getCfgXmlMappingArtifacts().getCacheRegionDefinitions() ); + jaccDefinitions.addAll( mergedResult.getCfgXmlMappingArtifacts().getJaccDefinitions() ); + + return mergedResult.getSettings(); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // temporary! public Map getConfigurationValues() { @@ -306,7 +323,9 @@ private IndexResult buildJandexIndex(Set classNamesSource, List } private void indexResource(String resourceName, Indexer indexer, BootstrapServiceRegistry bootstrapServiceRegistry) { - InputStream stream = bootstrapServiceRegistry.getService( ClassLoaderService.class ).locateResourceStream( resourceName ); + InputStream stream = bootstrapServiceRegistry.getService( ClassLoaderService.class ).locateResourceStream( + resourceName + ); try { indexer.index( stream ); } @@ -315,174 +334,6 @@ private void indexResource(String resourceName, Indexer indexer, BootstrapServic } } - /** - * Builds the {@link BootstrapServiceRegistry} used to eventually build the {@link ServiceRegistryBuilder}; mainly - * used here during instantiation to define class-loading behavior. - * - * @param integrationSettings Any integration settings passed by the EE container or SE application - * - * @return The built BootstrapServiceRegistry - */ - private BootstrapServiceRegistry buildBootstrapServiceRegistry(Map integrationSettings) { - final BootstrapServiceRegistryBuilder bootstrapServiceRegistryBuilder = new BootstrapServiceRegistryBuilder(); - bootstrapServiceRegistryBuilder.with( new JpaIntegrator() ); - - final IntegratorProvider integratorProvider = (IntegratorProvider) integrationSettings.get( INTEGRATOR_PROVIDER ); - if ( integratorProvider != null ) { - integrationSettings.remove( INTEGRATOR_PROVIDER ); - for ( Integrator integrator : integratorProvider.getIntegrators() ) { - bootstrapServiceRegistryBuilder.with( integrator ); - } - } - - ClassLoader classLoader = (ClassLoader) integrationSettings.get( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER ); - if ( classLoader != null ) { - integrationSettings.remove( org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER ); - } - else { - classLoader = persistenceUnit.getClassLoader(); - } - bootstrapServiceRegistryBuilder.withApplicationClassLoader( classLoader ); - - return bootstrapServiceRegistryBuilder.build(); - } - - @SuppressWarnings("unchecked") - private Map mergePropertySources( - PersistenceUnitDescriptor persistenceUnit, - Map integrationSettings, - final BootstrapServiceRegistry bootstrapServiceRegistry) { - final Map merged = new HashMap(); - // first, apply persistence.xml-defined settings - if ( persistenceUnit.getProperties() != null ) { - merged.putAll( persistenceUnit.getProperties() ); - } - - merged.put( AvailableSettings.PERSISTENCE_UNIT_NAME, persistenceUnit.getName() ); - - // see if the persistence.xml settings named a Hibernate config file.... - final ValueHolder configLoaderHolder = new ValueHolder( - new ValueHolder.DeferredInitializer() { - @Override - public ConfigLoader initialize() { - return new ConfigLoader( bootstrapServiceRegistry ); - } - } - ); - - { - final String cfgXmlResourceName = (String) merged.remove( AvailableSettings.CFG_FILE ); - if ( StringHelper.isNotEmpty( cfgXmlResourceName ) ) { - // it does, so load those properties - JaxbHibernateConfiguration configurationElement = configLoaderHolder.getValue() - .loadConfigXmlResource( cfgXmlResourceName ); - processHibernateConfigurationElement( configurationElement, merged ); - } - } - - // see if integration settings named a Hibernate config file.... - { - final String cfgXmlResourceName = (String) integrationSettings.get( AvailableSettings.CFG_FILE ); - if ( StringHelper.isNotEmpty( cfgXmlResourceName ) ) { - integrationSettings.remove( AvailableSettings.CFG_FILE ); - // it does, so load those properties - JaxbHibernateConfiguration configurationElement = configLoaderHolder.getValue().loadConfigXmlResource( - cfgXmlResourceName - ); - processHibernateConfigurationElement( configurationElement, merged ); - } - } - - // finally, apply integration-supplied settings (per JPA spec, integration settings should override other sources) - merged.putAll( integrationSettings ); - - if ( ! merged.containsKey( AvailableSettings.VALIDATION_MODE ) ) { - if ( persistenceUnit.getValidationMode() != null ) { - merged.put( AvailableSettings.VALIDATION_MODE, persistenceUnit.getValidationMode() ); - } - } - - if ( ! merged.containsKey( AvailableSettings.SHARED_CACHE_MODE ) ) { - if ( persistenceUnit.getSharedCacheMode() != null ) { - merged.put( AvailableSettings.SHARED_CACHE_MODE, persistenceUnit.getSharedCacheMode() ); - } - } - - // was getting NPE exceptions from the underlying map when just using #putAll, so going this safer route... - Iterator itr = merged.entrySet().iterator(); - while ( itr.hasNext() ) { - final Map.Entry entry = (Map.Entry) itr.next(); - if ( entry.getValue() == null ) { - itr.remove(); - } - } - - return merged; - } - - @SuppressWarnings("unchecked") - private void processHibernateConfigurationElement( - JaxbHibernateConfiguration configurationElement, - Map mergeMap) { - if ( ! mergeMap.containsKey( org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME ) ) { - String cfgName = configurationElement.getSessionFactory().getName(); - if ( cfgName != null ) { - mergeMap.put( org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME, cfgName ); - } - } - - for ( JaxbHibernateConfiguration.JaxbSessionFactory.JaxbProperty jaxbProperty : configurationElement.getSessionFactory().getProperty() ) { - mergeMap.put( jaxbProperty.getName(), jaxbProperty.getValue() ); - } - - for ( JaxbHibernateConfiguration.JaxbSessionFactory.JaxbMapping jaxbMapping : configurationElement.getSessionFactory().getMapping() ) { - cfgXmlNamedMappings.add( jaxbMapping ); - } - - for ( Object cacheDeclaration : configurationElement.getSessionFactory().getClassCacheOrCollectionCache() ) { - if ( JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache.class.isInstance( cacheDeclaration ) ) { - final JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache jaxbClassCache - = (JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache) cacheDeclaration; - cacheRegionDefinitions.add( - new CacheRegionDefinition( - CacheRegionDefinition.CacheType.ENTITY, - jaxbClassCache.getClazz(), - jaxbClassCache.getUsage().value(), - jaxbClassCache.getRegion(), - "all".equals( jaxbClassCache.getInclude() ) - ) - ); - } - else { - final JaxbHibernateConfiguration.JaxbSessionFactory.JaxbCollectionCache jaxbCollectionCache - = (JaxbHibernateConfiguration.JaxbSessionFactory.JaxbCollectionCache) cacheDeclaration; - cacheRegionDefinitions.add( - new CacheRegionDefinition( - CacheRegionDefinition.CacheType.COLLECTION, - jaxbCollectionCache.getCollection(), - jaxbCollectionCache.getUsage().value(), - jaxbCollectionCache.getRegion(), - false - ) - ); - } - } - - if ( configurationElement.getSecurity() != null ) { - final String contextId = configurationElement.getSecurity().getContext(); - for ( JaxbHibernateConfiguration.JaxbSecurity.JaxbGrant grant : configurationElement.getSecurity().getGrant() ) { - jaccDefinitions.add( - new JaccDefinition( - contextId, - grant.getRole(), - grant.getEntityName(), - grant.getActions() - ) - ); - } - } - } - private void processProperties(BootstrapServiceRegistry bootstrapServiceRegistry) { applyJdbcConnectionProperties(); applyTransactionProperties(); @@ -535,14 +386,14 @@ else if ( keyString.startsWith( AvailableSettings.CLASS_CACHE_PREFIX ) ) { addCacheRegionDefinition( keyString.substring( AvailableSettings.CLASS_CACHE_PREFIX.length() + 1 ), (String) entry.getValue(), - CacheRegionDefinition.CacheType.ENTITY + CacheRegionDefinition.CacheRegionType.ENTITY ); } else if ( keyString.startsWith( AvailableSettings.COLLECTION_CACHE_PREFIX ) ) { addCacheRegionDefinition( keyString.substring( AvailableSettings.COLLECTION_CACHE_PREFIX.length() + 1 ), (String) entry.getValue(), - CacheRegionDefinition.CacheType.COLLECTION + CacheRegionDefinition.CacheRegionType.COLLECTION ); } else if ( keyString.startsWith( AvailableSettings.JACC_PREFIX ) @@ -665,11 +516,11 @@ private Class loadSessionInterceptorClass( } } - private void addCacheRegionDefinition(String role, String value, CacheRegionDefinition.CacheType cacheType) { + private void addCacheRegionDefinition(String role, String value, CacheRegionDefinition.CacheRegionType cacheType) { final StringTokenizer params = new StringTokenizer( value, ";, " ); if ( !params.hasMoreTokens() ) { StringBuilder error = new StringBuilder( "Illegal usage of " ); - if ( cacheType == CacheRegionDefinition.CacheType.ENTITY ) { + if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) { error.append( AvailableSettings.CLASS_CACHE_PREFIX ) .append( ": " ) .append( AvailableSettings.CLASS_CACHE_PREFIX ); @@ -693,7 +544,7 @@ private void addCacheRegionDefinition(String role, String value, CacheRegionDefi region = params.nextToken(); } boolean lazyProperty = true; - if ( cacheType == CacheRegionDefinition.CacheType.ENTITY ) { + if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) { if ( params.hasMoreTokens() ) { lazyProperty = "all".equalsIgnoreCase( params.nextToken() ); } @@ -973,26 +824,30 @@ public Configuration buildHibernateConfiguration(ServiceRegistry serviceRegistry if ( jaccDefinitions != null ) { for ( JaccDefinition jaccDefinition : jaccDefinitions ) { - JACCConfiguration jaccCfg = new JACCConfiguration( jaccDefinition.contextId ); - jaccCfg.addPermission( jaccDefinition.role, jaccDefinition.clazz, jaccDefinition.actions ); + JACCConfiguration jaccCfg = new JACCConfiguration( jaccDefinition.getContextId() ); + jaccCfg.addPermission( + jaccDefinition.getRole(), + jaccDefinition.getClazz(), + jaccDefinition.getActions() + ); } } if ( cacheRegionDefinitions != null ) { for ( CacheRegionDefinition cacheRegionDefinition : cacheRegionDefinitions ) { - if ( cacheRegionDefinition.cacheType == CacheRegionDefinition.CacheType.ENTITY ) { + if ( cacheRegionDefinition.getRegionType() == CacheRegionDefinition.CacheRegionType.ENTITY ) { cfg.setCacheConcurrencyStrategy( - cacheRegionDefinition.role, - cacheRegionDefinition.usage, - cacheRegionDefinition.region, - cacheRegionDefinition.cacheLazy + cacheRegionDefinition.getRole(), + cacheRegionDefinition.getUsage(), + cacheRegionDefinition.getRegion(), + cacheRegionDefinition.isCacheLazy() ); } else { cfg.setCollectionCacheConcurrencyStrategy( - cacheRegionDefinition.role, - cacheRegionDefinition.usage, - cacheRegionDefinition.region + cacheRegionDefinition.getRole(), + cacheRegionDefinition.getUsage(), + cacheRegionDefinition.getRegion() ); } } @@ -1001,7 +856,7 @@ public Configuration buildHibernateConfiguration(ServiceRegistry serviceRegistry // todo : need to have this use the metamodel codebase eventually... - for ( JaxbHibernateConfiguration.JaxbSessionFactory.JaxbMapping jaxbMapping : cfgXmlNamedMappings ) { + for ( JaxbMapping jaxbMapping : cfgXmlNamedMappings ) { if ( jaxbMapping.getClazz() != null ) { cfg.addAnnotatedClass( serviceRegistry.getService( ClassLoaderService.class ).classForName( jaxbMapping.getClazz() ) @@ -1125,42 +980,6 @@ private String getExceptionHeader() { return "[PersistenceUnit: " + persistenceUnit.getName() + "] "; } - public static class CacheRegionDefinition { - public static enum CacheType { ENTITY, COLLECTION } - - public final CacheType cacheType; - public final String role; - public final String usage; - public final String region; - public final boolean cacheLazy; - - public CacheRegionDefinition( - CacheType cacheType, - String role, - String usage, - String region, boolean cacheLazy) { - this.cacheType = cacheType; - this.role = role; - this.usage = usage; - this.region = region; - this.cacheLazy = cacheLazy; - } - } - - public static class JaccDefinition { - public final String contextId; - public final String role; - public final String clazz; - public final String actions; - - public JaccDefinition(String contextId, String role, String clazz, String actions) { - this.contextId = contextId; - this.role = role; - this.clazz = clazz; - this.actions = actions; - } - } - public static class ScanningContext { private URL url; private boolean detectClasses; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderUsingMetamodelImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderUsingMetamodelImpl.java new file mode 100644 index 0000000000..5e1a7a1f6a --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderUsingMetamodelImpl.java @@ -0,0 +1,661 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.boot.internal; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityNotFoundException; +import javax.persistence.PersistenceException; +import javax.persistence.SharedCacheMode; +import javax.persistence.spi.PersistenceUnitTransactionType; +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.jboss.logging.Logger; + +import org.hibernate.CustomEntityDirtinessStrategy; +import org.hibernate.EntityNameResolver; +import org.hibernate.Interceptor; +import org.hibernate.SessionFactory; +import org.hibernate.SessionFactoryObserver; +import org.hibernate.boot.spi.CacheRegionDefinition; +import org.hibernate.boot.spi.JaccDefinition; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cfg.Environment; +import org.hibernate.cfg.MetadataSourceType; +import org.hibernate.cfg.NamingStrategy; +import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; +import org.hibernate.context.spi.CurrentTenantIdentifierResolver; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory; +import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.jpa.AvailableSettings; +import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; +import org.hibernate.jpa.boot.spi.JpaUnifiedSettingsBuilder; +import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; +import org.hibernate.jpa.boot.spi.Settings; +import org.hibernate.jpa.internal.EntityManagerFactoryImpl; +import org.hibernate.jpa.internal.EntityManagerMessageLogger; +import org.hibernate.jpa.internal.util.LogHelper; +import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper; +import org.hibernate.jpa.internal.util.SharedCacheModeHelper; +import org.hibernate.metamodel.Metadata; +import org.hibernate.metamodel.MetadataBuilder; +import org.hibernate.metamodel.MetadataSourceProcessingOrder; +import org.hibernate.metamodel.MetadataSources; +import org.hibernate.metamodel.SessionFactoryBuilder; +import org.hibernate.proxy.EntityNotFoundDelegate; +import org.hibernate.service.BootstrapServiceRegistry; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.service.ServiceRegistryBuilder; +import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.service.spi.ServiceRegistryImplementor; + +import static org.hibernate.internal.jaxb.cfg.JaxbHibernateConfiguration.JaxbSessionFactory.JaxbMapping; +import static org.hibernate.jpa.boot.spi.JpaBootstrapServiceRegistryBuilder.buildBootstrapServiceRegistry; +import static org.hibernate.jpa.boot.spi.JpaUnifiedSettingsBuilder.CfgXmlMappingArtifacts; + +/** + * This will eventually replace {@link EntityManagerFactoryBuilderImpl} + * + * @author Steve Ebersole + * + * @deprecated This class will go away before 5.0 even goes alpha and its functionality will replace that in + * {@link EntityManagerFactoryBuilderImpl}. + */ +@Deprecated +public class EntityManagerFactoryBuilderUsingMetamodelImpl implements EntityManagerFactoryBuilder { + private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger( + EntityManagerMessageLogger.class, + EntityManagerFactoryBuilderImpl.class.getName() + ); + + private final PersistenceUnitDescriptor persistenceUnit; + private final Map configurationValues; + + private final BootstrapServiceRegistry bootstrapServiceRegistry; + private final MetadataSources metadataSources; + + private final List jaccDefinitions = new ArrayList(); // todo : see HHH-7462 + private final List cacheRegionDefinitions = new ArrayList(); + + public EntityManagerFactoryBuilderUsingMetamodelImpl( + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettings) { + LogHelper.logPersistenceUnitInformation( persistenceUnit ); + + this.persistenceUnit = persistenceUnit; + if ( integrationSettings == null ) { + integrationSettings = Collections.emptyMap(); + } + + // build the boot-strap service registry, which mainly handles class loader interactions + this.bootstrapServiceRegistry = buildBootstrapServiceRegistry( + persistenceUnit, + integrationSettings + ); + + final JpaUnifiedSettingsBuilder.Result mergedResult = JpaUnifiedSettingsBuilder.mergePropertySources( + persistenceUnit, + integrationSettings, + bootstrapServiceRegistry + ); + + final CfgXmlMappingArtifacts cfgXmlMappingArtifacts = mergedResult.getCfgXmlMappingArtifacts(); + this.configurationValues = mergedResult.getSettings(); + + // todo : add scanning... + + this.metadataSources = new MetadataSources( bootstrapServiceRegistry ); + for ( JaxbMapping jaxbMapping : cfgXmlMappingArtifacts.getMappings() ) { + if ( jaxbMapping.getClazz() != null ) { + metadataSources.addAnnotatedClassName( jaxbMapping.getClazz() ); + } + else if ( jaxbMapping.getResource() != null ) { + metadataSources.addResource( jaxbMapping.getResource() ); + } + else if ( jaxbMapping.getJar() != null ) { + metadataSources.addJar( new File( jaxbMapping.getJar() ) ); + } + else if ( jaxbMapping.getPackage() != null ) { + metadataSources.addPackage( jaxbMapping.getPackage() ); + } + } + + // todo : add results of scanning to the MetadataSources + + metadataSources.addCacheRegionDefinitions( cacheRegionDefinitions ); + } + + @Override + public void cancel() { + // currently nothing to do... + } + + @Override + public EntityManagerFactory buildEntityManagerFactory() { + final ServiceRegistryBuilder serviceRegistryBuilder = new ServiceRegistryBuilder( bootstrapServiceRegistry ); + final SpecialProperties specialProperties = processProperties( serviceRegistryBuilder ); + + final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder(); + prepareMetadataBuilder( metadataBuilder, specialProperties ); + final Metadata metadata = metadataBuilder.buildMetadata(); + + final SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder(); + prepareSessionFactoryBuilder( sessionFactoryBuilder, specialProperties ); + sessionFactoryBuilder.add( new ServiceRegistryCloser() ); + SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) sessionFactoryBuilder.buildSessionFactory(); + + final Settings emfCreationSettings = prepareEntitytManagerFactoryCreationSettings( specialProperties ); + + // IMPL NOTE : the last param (passed as null) is the Configuration which we pass in at the moment solely to + // get access to the mapping information in order to build the JPA javax.persistence.metamodel.Metamodel + // We need to change that to leverage the new Hibernate Metadata metamodel package anyway.. + + return new EntityManagerFactoryImpl( + persistenceUnit.getName(), + sessionFactory, + (SettingsImpl) emfCreationSettings, + configurationValues, + null + ); + } + + private SpecialProperties processProperties(ServiceRegistryBuilder serviceRegistryBuilder) { + final SpecialProperties specialProperties = new SpecialProperties(); + + applyJdbcConnectionProperties( serviceRegistryBuilder ); + applyTransactionProperties( serviceRegistryBuilder, specialProperties ); + + final Object validationFactory = configurationValues.get( AvailableSettings.VALIDATION_FACTORY ); + if ( validationFactory != null ) { + BeanValidationIntegrator.validateFactory( validationFactory ); + } + + // flush before completion validation + if ( "true".equals( configurationValues.get( Environment.FLUSH_BEFORE_COMPLETION ) ) ) { + serviceRegistryBuilder.applySetting( Environment.FLUSH_BEFORE_COMPLETION, "false" ); + LOG.definingFlushBeforeCompletionIgnoredInHem( Environment.FLUSH_BEFORE_COMPLETION ); + } + + for ( Map.Entry entry : configurationValues.entrySet() ) { + if ( entry.getKey() instanceof String ) { + final String keyString = (String) entry.getKey(); + + //noinspection deprecation + if ( AvailableSettings.INTERCEPTOR.equals( keyString ) + || org.hibernate.cfg.AvailableSettings.INTERCEPTOR.equals( keyString ) ) { + specialProperties.sessionFactoryInterceptor = instantiateCustomClassFromConfiguration( + entry.getValue(), + Interceptor.class, + bootstrapServiceRegistry + ); + } + else if ( AvailableSettings.SESSION_INTERCEPTOR.equals( keyString ) ) { + specialProperties.sessionInterceptorClass = loadSessionInterceptorClass( + entry.getValue(), + bootstrapServiceRegistry + ); + } + else if ( AvailableSettings.NAMING_STRATEGY.equals( keyString ) ) { + specialProperties.namingStrategy = instantiateCustomClassFromConfiguration( + entry.getValue(), + NamingStrategy.class, + bootstrapServiceRegistry + ); + } + else if ( AvailableSettings.SESSION_FACTORY_OBSERVER.equals( keyString ) ) { + specialProperties.sessionFactoryObserver = instantiateCustomClassFromConfiguration( + entry.getValue(), + SessionFactoryObserver.class, + bootstrapServiceRegistry + ); + } + else if ( org.hibernate.cfg.AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY.equals( keyString ) ) { + specialProperties.customEntityDirtinessStrategy = instantiateCustomClassFromConfiguration( + entry.getValue(), + CustomEntityDirtinessStrategy.class, + bootstrapServiceRegistry + ); + } + else if ( org.hibernate.cfg.AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER.equals( keyString ) ) { + specialProperties.currentTenantIdentifierResolver = instantiateCustomClassFromConfiguration( + entry.getValue(), + CurrentTenantIdentifierResolver.class, + bootstrapServiceRegistry + ); + } + else if ( AvailableSettings.DISCARD_PC_ON_CLOSE.equals( keyString ) ) { + specialProperties.releaseResourcesOnClose = ( "true".equals( entry.getValue() ) ); + } + else if ( AvailableSettings.SHARED_CACHE_MODE.equals( keyString ) ) { + specialProperties.sharedCacheMode = SharedCacheModeHelper.asSharedCacheMode( entry.getValue() ); + } + else if ( org.hibernate.cfg.AvailableSettings.METADATA_PROCESSING_ORDER.equals( keyString ) ) { + specialProperties.sourceProcessingOrder = interpretSourceProcessingOrder( entry.getValue() ); + } + else if ( org.hibernate.cfg.AvailableSettings.DEFAULT_CACHE_CONCURRENCY_STRATEGY.equals( keyString ) ) { + specialProperties.defaultCacheAccessType = interpretCacheAccessStrategy( entry.getValue() ); + } + else if ( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS.equals( keyString ) ) { + specialProperties.useEnhancedGenerators = ConfigurationHelper.asBoolean( entry.getValue() ); + } + else if ( keyString.startsWith( AvailableSettings.CLASS_CACHE_PREFIX ) ) { + addCacheRegionDefinition( + keyString.substring( AvailableSettings.CLASS_CACHE_PREFIX.length() + 1 ), + (String) entry.getValue(), + CacheRegionDefinition.CacheRegionType.ENTITY + ); + } + else if ( keyString.startsWith( AvailableSettings.COLLECTION_CACHE_PREFIX ) ) { + addCacheRegionDefinition( + keyString.substring( AvailableSettings.COLLECTION_CACHE_PREFIX.length() + 1 ), + (String) entry.getValue(), + CacheRegionDefinition.CacheRegionType.COLLECTION + ); + } + else if ( keyString.startsWith( AvailableSettings.JACC_PREFIX ) + && ! ( keyString.equals( AvailableSettings.JACC_CONTEXT_ID ) + || keyString.equals( AvailableSettings.JACC_ENABLED ) ) ) { + addJaccDefinition( (String) entry.getKey(), entry.getValue() ); + } + } + + } + + return specialProperties; + } + + private void applyJdbcConnectionProperties(ServiceRegistryBuilder serviceRegistryBuilder) { + if ( persistenceUnit.getJtaDataSource() != null ) { + serviceRegistryBuilder.applySetting( Environment.DATASOURCE, persistenceUnit.getJtaDataSource() ); + } + else if ( persistenceUnit.getNonJtaDataSource() != null ) { + serviceRegistryBuilder.applySetting( Environment.DATASOURCE, persistenceUnit.getNonJtaDataSource() ); + } + else { + final String driver = (String) configurationValues.get( AvailableSettings.JDBC_DRIVER ); + if ( StringHelper.isNotEmpty( driver ) ) { + serviceRegistryBuilder.applySetting( org.hibernate.cfg.AvailableSettings.DRIVER, driver ); + } + final String url = (String) configurationValues.get( AvailableSettings.JDBC_URL ); + if ( StringHelper.isNotEmpty( url ) ) { + serviceRegistryBuilder.applySetting( org.hibernate.cfg.AvailableSettings.URL, url ); + } + final String user = (String) configurationValues.get( AvailableSettings.JDBC_USER ); + if ( StringHelper.isNotEmpty( user ) ) { + serviceRegistryBuilder.applySetting( org.hibernate.cfg.AvailableSettings.USER, user ); + } + final String pass = (String) configurationValues.get( AvailableSettings.JDBC_PASSWORD ); + if ( StringHelper.isNotEmpty( pass ) ) { + serviceRegistryBuilder.applySetting( org.hibernate.cfg.AvailableSettings.PASS, pass ); + } + } + } + + private void applyTransactionProperties(ServiceRegistryBuilder serviceRegistryBuilder, SpecialProperties specialProperties) { + PersistenceUnitTransactionType txnType = PersistenceUnitTransactionTypeHelper.interpretTransactionType( + configurationValues.get( AvailableSettings.TRANSACTION_TYPE ) + ); + if ( txnType == null ) { + txnType = persistenceUnit.getTransactionType(); + } + if ( txnType == null ) { + // is it more appropriate to have this be based on bootstrap entry point (EE vs SE)? + txnType = PersistenceUnitTransactionType.RESOURCE_LOCAL; + } + specialProperties.jpaTransactionType = txnType; + boolean hasTxStrategy = configurationValues.containsKey( Environment.TRANSACTION_STRATEGY ); + if ( hasTxStrategy ) { + LOG.overridingTransactionStrategyDangerous( Environment.TRANSACTION_STRATEGY ); + } + else { + if ( txnType == PersistenceUnitTransactionType.JTA ) { + serviceRegistryBuilder.applySetting( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class ); + } + else if ( txnType == PersistenceUnitTransactionType.RESOURCE_LOCAL ) { + serviceRegistryBuilder.applySetting( Environment.TRANSACTION_STRATEGY, JdbcTransactionFactory.class ); + } + } + } + + @SuppressWarnings("unchecked") + private T instantiateCustomClassFromConfiguration( + Object value, + Class type, + ServiceRegistry bootstrapServiceRegistry) { + if ( value == null ) { + return null; + } + + if ( type.isInstance( value ) ) { + return (T) value; + } + + final Class implementationClass; + + if ( Class.class.isInstance( value ) ) { + try { + implementationClass = (Class) value; + } + catch (ClassCastException e) { + throw persistenceException( + String.format( + "Specified implementation class [%s] was not of expected type [%s]", + ((Class) value).getName(), + type.getName() + ) + ); + } + } + else { + final String implementationClassName = value.toString(); + try { + implementationClass = bootstrapServiceRegistry.getService( ClassLoaderService.class ) + .classForName( implementationClassName ); + } + catch (ClassCastException e) { + throw persistenceException( + String.format( + "Specified implementation class [%s] was not of expected type [%s]", + implementationClassName, + type.getName() + ) + ); + } + } + + try { + return implementationClass.newInstance(); + } + catch (Exception e) { + throw persistenceException( + String.format( + "Unable to instantiate specified implementation class [%s]", + implementationClass.getName() + ), + e + ); + } + } + + @SuppressWarnings("unchecked") + private Class loadSessionInterceptorClass( + Object value, + BootstrapServiceRegistry bootstrapServiceRegistry) { + if ( value == null ) { + return null; + } + + Class theClass; + if ( Class.class.isInstance( value ) ) { + theClass = (Class) value; + } + else { + theClass = bootstrapServiceRegistry.getService( ClassLoaderService.class ).classForName( value.toString() ); + } + + try { + return (Class) theClass; + } + catch (ClassCastException e) { + throw persistenceException( + String.format( + "Specified Interceptor implementation class [%s] was not castable to Interceptor", + theClass.getName() + ) + ); + } + } + + private MetadataSourceProcessingOrder interpretSourceProcessingOrder(Object value) { + if ( value == null ) { + return null; + } + + if ( MetadataSourceProcessingOrder.class.isInstance( value ) ) { + return (MetadataSourceProcessingOrder) value; + } + else { + final String s = value.toString(); + final StringTokenizer tokenizer = new StringTokenizer( s, ",; ", false ); + final MetadataSourceType metadataSourceType = MetadataSourceType.parsePrecedence( tokenizer.nextToken() ); + return metadataSourceType == MetadataSourceType.CLASS + ? MetadataSourceProcessingOrder.ANNOTATIONS_FIRST + : MetadataSourceProcessingOrder.HBM_FIRST; + } + } + + private AccessType interpretCacheAccessStrategy(Object value) { + if ( value == null ) { + return null; + } + + if ( AccessType.class.isInstance( value ) ) { + return (AccessType) value; + } + else { + return AccessType.fromExternalName( value.toString() ); + } + } + + private String jaccContextId; + + private void addJaccDefinition(String key, Object value) { + if ( jaccContextId == null ) { + jaccContextId = (String) configurationValues.get( AvailableSettings.JACC_CONTEXT_ID ); + if ( jaccContextId == null ) { + throw persistenceException( + "Entities have been configured for JACC, but " + + AvailableSettings.JACC_CONTEXT_ID + " has not been set" + ); + } + } + + try { + final int roleStart = AvailableSettings.JACC_PREFIX.length() + 1; + final String role = key.substring( roleStart, key.indexOf( '.', roleStart ) ); + final int classStart = roleStart + role.length() + 1; + final String clazz = key.substring( classStart, key.length() ); + + final JaccDefinition def = new JaccDefinition( jaccContextId, role, clazz, (String) value ); + + jaccDefinitions.add( def ); + + } + catch ( IndexOutOfBoundsException e ) { + throw persistenceException( "Illegal usage of " + AvailableSettings.JACC_PREFIX + ": " + key ); + } + } + + private void addCacheRegionDefinition(String role, String value, CacheRegionDefinition.CacheRegionType cacheType) { + final StringTokenizer params = new StringTokenizer( value, ";, " ); + if ( !params.hasMoreTokens() ) { + StringBuilder error = new StringBuilder( "Illegal usage of " ); + if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) { + error.append( AvailableSettings.CLASS_CACHE_PREFIX ) + .append( ": " ) + .append( AvailableSettings.CLASS_CACHE_PREFIX ); + } + else { + error.append( AvailableSettings.COLLECTION_CACHE_PREFIX ) + .append( ": " ) + .append( AvailableSettings.COLLECTION_CACHE_PREFIX ); + } + error.append( '.' ) + .append( role ) + .append( ' ' ) + .append( value ) + .append( ". Was expecting configuration, but found none" ); + throw persistenceException( error.toString() ); + } + + String usage = params.nextToken(); + String region = null; + if ( params.hasMoreTokens() ) { + region = params.nextToken(); + } + boolean lazyProperty = true; + if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) { + if ( params.hasMoreTokens() ) { + lazyProperty = "all".equalsIgnoreCase( params.nextToken() ); + } + } + else { + lazyProperty = false; + } + + final CacheRegionDefinition def = new CacheRegionDefinition( cacheType, role, usage, region, lazyProperty ); + cacheRegionDefinitions.add( def ); + } + + @SuppressWarnings("UnnecessaryUnboxing") + private void prepareMetadataBuilder( + MetadataBuilder metadataBuilder, + SpecialProperties specialProperties) { + if ( specialProperties.namingStrategy != null ) { + metadataBuilder.with( specialProperties.namingStrategy ); + } + + if ( specialProperties.sourceProcessingOrder != null ) { + metadataBuilder.with( specialProperties.sourceProcessingOrder ); + } + + if ( specialProperties.useEnhancedGenerators != null ) { + metadataBuilder.withNewIdentifierGeneratorsEnabled( specialProperties.useEnhancedGenerators.booleanValue() ); + } + + if ( specialProperties.sharedCacheMode != null ) { + metadataBuilder.with( specialProperties.sharedCacheMode ); + } + + if ( specialProperties.defaultCacheAccessType != null ) { + metadataBuilder.with( specialProperties.defaultCacheAccessType ); + } + } + + private void prepareSessionFactoryBuilder(SessionFactoryBuilder builder, SpecialProperties specialProperties) { + if ( specialProperties.sessionFactoryInterceptor != null ) { + builder.with( specialProperties.sessionFactoryInterceptor ); + } + if ( specialProperties.entityNameResolver != null ) { + builder.add( specialProperties.entityNameResolver ); + } + if ( specialProperties.entityNotFoundDelegate != null ) { + builder.with( specialProperties.entityNotFoundDelegate ); + } + if ( specialProperties.sessionFactoryObserver != null ) { + builder.add( specialProperties.sessionFactoryObserver ); + } + if ( specialProperties.customEntityDirtinessStrategy != null ) { + builder.with( specialProperties.customEntityDirtinessStrategy ); + } + if ( specialProperties.currentTenantIdentifierResolver != null ) { + builder.with( specialProperties.currentTenantIdentifierResolver ); + } + } + + @SuppressWarnings("UnnecessaryUnboxing") + private Settings prepareEntitytManagerFactoryCreationSettings(SpecialProperties specialProperties) { + final SettingsImpl settings = new SettingsImpl(); + if ( specialProperties.releaseResourcesOnClose != null ) { + settings.setReleaseResourcesOnCloseEnabled( specialProperties.releaseResourcesOnClose.booleanValue() ); + } + if ( specialProperties.sessionInterceptorClass != null ) { + settings.setSessionInterceptorClass( specialProperties.sessionInterceptorClass ); + } + if ( specialProperties.jpaTransactionType != null ) { + settings.setTransactionType( specialProperties.jpaTransactionType ); + } + return settings; + } + + + private PersistenceException persistenceException(String message) { + return persistenceException( message, null ); + } + + private PersistenceException persistenceException(String message, Exception cause) { + return new PersistenceException( + getExceptionHeader() + message, + cause + ); + } + + private String getExceptionHeader() { + return "[PersistenceUnit: " + persistenceUnit.getName() + "] "; + } + + /** + * Aggregated return structure + */ + private static class SpecialProperties { + // affecting MetadataBuilder... + private NamingStrategy namingStrategy; + private MetadataSourceProcessingOrder sourceProcessingOrder; + private SharedCacheMode sharedCacheMode; + private AccessType defaultCacheAccessType; + private Boolean useEnhancedGenerators; + + // affecting SessionFactoryBuilder... + private Interceptor sessionFactoryInterceptor; + private SessionFactoryObserver sessionFactoryObserver; + private EntityNameResolver entityNameResolver; + private EntityNotFoundDelegate entityNotFoundDelegate = new JpaEntityNotFoundDelegate(); + private CustomEntityDirtinessStrategy customEntityDirtinessStrategy; + private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; + + // affecting EntityManagerFactory building + private Boolean releaseResourcesOnClose; + private Class sessionInterceptorClass; + private PersistenceUnitTransactionType jpaTransactionType; + } + + private static class JpaEntityNotFoundDelegate implements EntityNotFoundDelegate, Serializable { + public void handleEntityNotFound(String entityName, Serializable id) { + throw new EntityNotFoundException( "Unable to find " + entityName + " with id " + id ); + } + } + + private static class ServiceRegistryCloser implements SessionFactoryObserver { + @Override + public void sessionFactoryCreated(SessionFactory sessionFactory) { + // nothing to do + } + + @Override + public void sessionFactoryClosed(SessionFactory sessionFactory) { + SessionFactoryImplementor sfi = ( (SessionFactoryImplementor) sessionFactory ); + sfi.getServiceRegistry().destroy(); + ServiceRegistry basicRegistry = sfi.getServiceRegistry().getParentServiceRegistry(); + ( (ServiceRegistryImplementor) basicRegistry ).destroy(); + } + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java index 67e6ae38cd..068f029a3d 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java @@ -27,6 +27,7 @@ import java.util.Map; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; +import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderUsingMetamodelImpl; import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor; /** @@ -35,15 +36,57 @@ * @author Steve Ebersole */ public final class Bootstrap { + /** + * Builds and returns an EntityManagerFactoryBuilder that can be used to then create an + * {@link javax.persistence.EntityManagerFactory}. Essentially this represents phase 1 of a 2 phase + * {@link javax.persistence.EntityManagerFactory} building process. + * + * @param persistenceUnitDescriptor The persistence-unit description. Note that this is the Hibernate abstraction + * hiding where this info comes from. + * @param integration The map of integration settings. Generally speaking, integration settings take precedence + * over persistence-unit settings. + * + * @return The {@link javax.persistence.EntityManagerFactory} builder. + */ public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration) { return new EntityManagerFactoryBuilderImpl( persistenceUnitDescriptor, integration ); } + /** + * Builds and returns an EntityManagerFactoryBuilder that can be used to then create an + * {@link javax.persistence.EntityManagerFactory}. Essentially this represents phase 1 of a 2 phase + * {@link javax.persistence.EntityManagerFactory} building process. + * + * This form accepts the JPA container bootstrap persistence-unit descriptor representation + * ({@link PersistenceUnitInfo}) and wraps it in our {@link PersistenceUnitDescriptor} abstraction. It then + * just delegates the call to {@link #getEntityManagerFactoryBuilder(PersistenceUnitDescriptor, Map)} + * + * @param persistenceUnitInfo The persistence-unit description as defined by the JPA PersistenceUnitInfo contract + * @param integration The map of integration settings. Generally speaking, integration settings take precedence + * over persistence-unit settings. + * + * @return The {@link javax.persistence.EntityManagerFactory} builder. + */ public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( PersistenceUnitInfo persistenceUnitInfo, Map integration) { return getEntityManagerFactoryBuilder( new PersistenceUnitInfoDescriptor( persistenceUnitInfo ), integration ); } + + /** + * Specifically builds and returns a EntityManagerFactoryBuilder that leverages the new metamodel codebase. + * Eventually this will be the normal operation of {@link #getEntityManagerFactoryBuilder(PersistenceUnitDescriptor, Map)}, + * but for now due to the incompleteness of the metamodel codebase, this is not integrated as the main way to + * build the EntityManagerFactoryBuilder. This allows tests in the nor-core modules to keep running. + * + * @deprecated This is a temporary method until metamodel codebase is more complete + */ + @Deprecated + public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilderUsingMetamodel( + PersistenceUnitDescriptor persistenceUnitDescriptor, + Map integration) { + return new EntityManagerFactoryBuilderUsingMetamodelImpl( persistenceUnitDescriptor, integration ); + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaBootstrapServiceRegistryBuilder.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaBootstrapServiceRegistryBuilder.java new file mode 100644 index 0000000000..bbb23f5ccf --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaBootstrapServiceRegistryBuilder.java @@ -0,0 +1,76 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.boot.spi; + +import java.util.Map; + +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.jpa.internal.event.JpaIntegrator; +import org.hibernate.service.BootstrapServiceRegistry; +import org.hibernate.service.BootstrapServiceRegistryBuilder; + +import static org.hibernate.cfg.AvailableSettings.APP_CLASSLOADER; +import static org.hibernate.jpa.AvailableSettings.INTEGRATOR_PROVIDER; + +/** + * Helper class for building a BootstrapServiceRegistry for JPA use. Extracted to separate class so others can + * leverage. + */ +public class JpaBootstrapServiceRegistryBuilder { + /** + * Builds the {@link org.hibernate.service.BootstrapServiceRegistry} used by used as part of JPA boot-strapping. + * + * Mainly accounts for class-loading behavior and reading a (potentially) explicitly defined + * {@link IntegratorProvider} + * + * @param integrationSettings Any integration settings passed by the EE container or SE application + * + * @return The built BootstrapServiceRegistry + */ + public static BootstrapServiceRegistry buildBootstrapServiceRegistry( + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettings) { + final BootstrapServiceRegistryBuilder bootstrapServiceRegistryBuilder = new BootstrapServiceRegistryBuilder(); + bootstrapServiceRegistryBuilder.with( new JpaIntegrator() ); + + final IntegratorProvider integratorProvider = (IntegratorProvider) integrationSettings.get( INTEGRATOR_PROVIDER ); + if ( integratorProvider != null ) { + integrationSettings.remove( INTEGRATOR_PROVIDER ); + for ( Integrator integrator : integratorProvider.getIntegrators() ) { + bootstrapServiceRegistryBuilder.with( integrator ); + } + } + + ClassLoader classLoader = (ClassLoader) integrationSettings.get( APP_CLASSLOADER ); + if ( classLoader != null ) { + integrationSettings.remove( APP_CLASSLOADER ); + } + else { + classLoader = persistenceUnit.getClassLoader(); + } + bootstrapServiceRegistryBuilder.withApplicationClassLoader( classLoader ); + + return bootstrapServiceRegistryBuilder.build(); + } +} \ No newline at end of file diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaUnifiedSettingsBuilder.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaUnifiedSettingsBuilder.java new file mode 100644 index 0000000000..818bb82ea1 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/JpaUnifiedSettingsBuilder.java @@ -0,0 +1,251 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.boot.spi; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.hibernate.boot.spi.CacheRegionDefinition; +import org.hibernate.boot.spi.JaccDefinition; +import org.hibernate.internal.jaxb.cfg.JaxbHibernateConfiguration; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.ValueHolder; +import org.hibernate.jpa.AvailableSettings; +import org.hibernate.service.BootstrapServiceRegistry; +import org.hibernate.service.ConfigLoader; + +import static org.hibernate.internal.jaxb.cfg.JaxbHibernateConfiguration.JaxbSessionFactory.JaxbMapping; + +/** + * Helper class for handling building a unified map of "JPA settings". Extracted to separate class so others can + * leverage. + * + * @author Steve Ebersole + */ +public class JpaUnifiedSettingsBuilder { + /** + * JPA settings can name one or more {@code cfg.xml} file to read for setting information. {@code cfg.xml} + * files, however, can name things other than just settings (properties). If can name metadata mappings, + * cache configurations, etc. This interface collects those "other" artifacts for use by the caller of this + * helper so that the {@code cfg.xml} does not need to be parsed a second time to get that information later. + */ + public static interface CfgXmlMappingArtifacts { + public List getMappings(); + public List getCacheRegionDefinitions(); + public List getJaccDefinitions(); + } + + /** + * Aggregated result of processing all pertinent JPA setting sources. + */ + public static interface Result { + public Map getSettings(); + public CfgXmlMappingArtifacts getCfgXmlMappingArtifacts(); + } + + public static Result mergePropertySources( + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettings, + final BootstrapServiceRegistry bootstrapServiceRegistry) { + ResultImpl result = new ResultImpl(); + result.consume( persistenceUnit, integrationSettings, bootstrapServiceRegistry ); + return result; + } + + private static class CfgXmlMappingArtifactsImpl implements CfgXmlMappingArtifacts { + private final List mappings = new ArrayList(); + private final List cacheRegionDefinitions = new ArrayList(); + private final List jaccDefinitions = new ArrayList(); + + @Override + public List getMappings() { + return mappings; + } + + @Override + public List getCacheRegionDefinitions() { + return cacheRegionDefinitions; + } + + @Override + public List getJaccDefinitions() { + return jaccDefinitions; + } + } + + private static class ResultImpl implements Result { + private final Map settings = new ConcurrentHashMap(); + private final CfgXmlMappingArtifactsImpl cfgXmlMappingArtifacts = new CfgXmlMappingArtifactsImpl(); + + @Override + public Map getSettings() { + return settings; + } + + @Override + public CfgXmlMappingArtifacts getCfgXmlMappingArtifacts() { + return cfgXmlMappingArtifacts; + } + + + @SuppressWarnings("unchecked") + public void consume( + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettings, + final BootstrapServiceRegistry bootstrapServiceRegistry) { + final Map merged = new HashMap(); + // first, apply persistence.xml-defined settings + if ( persistenceUnit.getProperties() != null ) { + merged.putAll( persistenceUnit.getProperties() ); + } + + merged.put( AvailableSettings.PERSISTENCE_UNIT_NAME, persistenceUnit.getName() ); + + // see if the persistence.xml settings named a Hibernate config file.... + final ValueHolder configLoaderHolder = new ValueHolder( + new ValueHolder.DeferredInitializer() { + @Override + public ConfigLoader initialize() { + return new ConfigLoader( bootstrapServiceRegistry ); + } + } + ); + + { + final String cfgXmlResourceName = (String) merged.remove( AvailableSettings.CFG_FILE ); + if ( StringHelper.isNotEmpty( cfgXmlResourceName ) ) { + // it does, so load those properties + JaxbHibernateConfiguration configurationElement = configLoaderHolder.getValue() + .loadConfigXmlResource( cfgXmlResourceName ); + processHibernateConfigurationElement( configurationElement, merged ); + } + } + + // see if integration settings named a Hibernate config file.... + { + final String cfgXmlResourceName = (String) integrationSettings.get( AvailableSettings.CFG_FILE ); + if ( StringHelper.isNotEmpty( cfgXmlResourceName ) ) { + integrationSettings.remove( AvailableSettings.CFG_FILE ); + // it does, so load those properties + JaxbHibernateConfiguration configurationElement = configLoaderHolder.getValue().loadConfigXmlResource( + cfgXmlResourceName + ); + processHibernateConfigurationElement( configurationElement, merged ); + } + } + + // finally, apply integration-supplied settings (per JPA spec, integration settings should override other sources) + merged.putAll( integrationSettings ); + + if ( ! merged.containsKey( AvailableSettings.VALIDATION_MODE ) ) { + if ( persistenceUnit.getValidationMode() != null ) { + merged.put( AvailableSettings.VALIDATION_MODE, persistenceUnit.getValidationMode() ); + } + } + + if ( ! merged.containsKey( AvailableSettings.SHARED_CACHE_MODE ) ) { + if ( persistenceUnit.getSharedCacheMode() != null ) { + merged.put( AvailableSettings.SHARED_CACHE_MODE, persistenceUnit.getSharedCacheMode() ); + } + } + + // was getting NPE exceptions from the underlying map when just using #putAll, so going this safer route... + Iterator itr = merged.entrySet().iterator(); + while ( itr.hasNext() ) { + final Map.Entry entry = (Map.Entry) itr.next(); + if ( entry.getValue() == null ) { + itr.remove(); + } + } + } + + @SuppressWarnings("unchecked") + private void processHibernateConfigurationElement( + JaxbHibernateConfiguration configurationElement, + Map mergeMap) { + if ( ! mergeMap.containsKey( org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME ) ) { + String cfgName = configurationElement.getSessionFactory().getName(); + if ( cfgName != null ) { + mergeMap.put( org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME, cfgName ); + } + } + + for ( JaxbHibernateConfiguration.JaxbSessionFactory.JaxbProperty jaxbProperty : configurationElement.getSessionFactory().getProperty() ) { + mergeMap.put( jaxbProperty.getName(), jaxbProperty.getValue() ); + } + + for ( JaxbMapping jaxbMapping : configurationElement.getSessionFactory().getMapping() ) { + cfgXmlMappingArtifacts.mappings.add( jaxbMapping ); + } + + for ( Object cacheDeclaration : configurationElement.getSessionFactory().getClassCacheOrCollectionCache() ) { + if ( JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache.class.isInstance( cacheDeclaration ) ) { + final JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache jaxbClassCache + = (JaxbHibernateConfiguration.JaxbSessionFactory.JaxbClassCache) cacheDeclaration; + cfgXmlMappingArtifacts.cacheRegionDefinitions.add( + new CacheRegionDefinition( + CacheRegionDefinition.CacheRegionType.ENTITY, + jaxbClassCache.getClazz(), + jaxbClassCache.getUsage().value(), + jaxbClassCache.getRegion(), + "all".equals( jaxbClassCache.getInclude() ) + ) + ); + } + else { + final JaxbHibernateConfiguration.JaxbSessionFactory.JaxbCollectionCache jaxbCollectionCache + = (JaxbHibernateConfiguration.JaxbSessionFactory.JaxbCollectionCache) cacheDeclaration; + cfgXmlMappingArtifacts.cacheRegionDefinitions.add( + new CacheRegionDefinition( + CacheRegionDefinition.CacheRegionType.COLLECTION, + jaxbCollectionCache.getCollection(), + jaxbCollectionCache.getUsage().value(), + jaxbCollectionCache.getRegion(), + false + ) + ); + } + } + + if ( configurationElement.getSecurity() != null ) { + final String contextId = configurationElement.getSecurity().getContext(); + for ( JaxbHibernateConfiguration.JaxbSecurity.JaxbGrant grant : configurationElement.getSecurity().getGrant() ) { + cfgXmlMappingArtifacts.jaccDefinitions.add( + new JaccDefinition( + contextId, + grant.getRole(), + grant.getEntityName(), + grant.getActions() + ) + ); + } + } + } + } + +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerFactoryImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerFactoryImpl.java index a900cf812f..a817a231e5 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerFactoryImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerFactoryImpl.java @@ -64,7 +64,8 @@ import org.hibernate.jpa.HibernateQuery; import org.hibernate.jpa.boot.internal.SettingsImpl; import org.hibernate.jpa.criteria.CriteriaBuilderImpl; -import org.hibernate.jpa.internal.metamodel.MetamodelImpl; +import org.hibernate.jpa.metamodel.internal.JpaMetaModelPopulationSetting; +import org.hibernate.jpa.metamodel.internal.legacy.MetamodelImpl; import org.hibernate.jpa.internal.util.PersistenceUtilHelper; import org.hibernate.mapping.PersistentClass; import org.hibernate.metadata.ClassMetadata; @@ -122,19 +123,7 @@ public EntityManagerFactoryImpl( this.transactionType = settings.getTransactionType(); this.discardOnClose = settings.isReleaseResourcesOnCloseEnabled(); this.sessionInterceptorClass = settings.getSessionInterceptorClass(); - - final Iterator classes = cfg.getClassMappings(); - final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting = determineJpaMetaModelPopulationSetting( cfg ); - if ( JpaMetaModelPopulationSetting.DISABLED == jpaMetaModelPopulationSetting ) { - this.metamodel = null; - } - else { - this.metamodel = MetamodelImpl.buildMetamodel( - classes, - sessionFactory, - JpaMetaModelPopulationSetting.IGNORE_UNSUPPORTED == jpaMetaModelPopulationSetting - ); - } + this.metamodel = sessionFactory.getJpaMetamodel(); this.criteriaBuilder = new CriteriaBuilderImpl( this ); this.util = new HibernatePersistenceUnitUtil( this ); @@ -154,43 +143,6 @@ public EntityManagerFactoryImpl( EntityManagerFactoryRegistry.INSTANCE.addEntityManagerFactory(entityManagerFactoryName, this); } - private enum JpaMetaModelPopulationSetting { - ENABLED, - DISABLED, - IGNORE_UNSUPPORTED; - - private static JpaMetaModelPopulationSetting parse(String setting) { - if ( "enabled".equalsIgnoreCase( setting ) ) { - return ENABLED; - } - else if ( "disabled".equalsIgnoreCase( setting ) ) { - return DISABLED; - } - else { - return IGNORE_UNSUPPORTED; - } - } - } - - protected JpaMetaModelPopulationSetting determineJpaMetaModelPopulationSetting(Configuration cfg) { - String setting = ConfigurationHelper.getString( - AvailableSettings.JPA_METAMODEL_POPULATION, - cfg.getProperties(), - null - ); - if ( setting == null ) { - setting = ConfigurationHelper.getString( AvailableSettings.JPA_METAMODEL_GENERATION, cfg.getProperties(), null ); - if ( setting != null ) { - log.infof( - "Encountered deprecated setting [%s], use [%s] instead", - AvailableSettings.JPA_METAMODEL_GENERATION, - AvailableSettings.JPA_METAMODEL_POPULATION - ); - } - } - return JpaMetaModelPopulationSetting.parse( setting ); - } - private static void addAll(HashMap destination, Map source) { for ( Map.Entry entry : source.entrySet() ) { if ( String.class.isInstance( entry.getKey() ) ) { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerMessageLogger.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerMessageLogger.java index 95748174c4..099ae9bcd1 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerMessageLogger.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/EntityManagerMessageLogger.java @@ -70,12 +70,19 @@ public interface EntityManagerMessageLogger extends CoreMessageLogger { @Message( value = "Exploded jar file not a directory (ignored): %s", id = 15006 ) void explodedJarNotDirectory( URL jarUrl ); - @LogMessage( level = ERROR ) - @Message( value = "Illegal argument on static metamodel field injection : %s#%s; expected type : %s; encountered type : %s", id = 15007 ) - void illegalArgumentOnStaticMetamodelFieldInjection( String name, - String name2, - String name3, - String name4 ); + /** + * Simply deprecated for now to show the fact that id 15007 is still in use... + * + * @deprecated Moved to hibernate-core in conjunction with moving JPA metamodel generation to SessionFactory + */ + @Override + @Deprecated + @LogMessage( level = ERROR ) + @Message( value = "Illegal argument on static metamodel field injection : %s#%s; expected type : %s; encountered type : %s", id = 15007 ) + void illegalArgumentOnStaticMetamodelFieldInjection( String metamodelClassName, + String attributeName, + String attributeJavaType, + String metamodelFieldJavaType ); @LogMessage( level = ERROR ) @Message( value = "Malformed URL: %s", id = 15008 ) @@ -92,10 +99,17 @@ void malformedUrlWarning( URL jarUrl, void unableToFindFile( URL jarUrl, @Cause Exception e ); - @LogMessage( level = ERROR ) - @Message( value = "Unable to locate static metamodel field : %s#%s", id = 15011 ) - void unableToLocateStaticMetamodelField( String name, - String name2 ); + /** + * Simply deprecated for now to show the fact that id 15011 is still in use... + * + * @deprecated Moved to hibernate-core in conjunction with moving JPA metamodel generation to SessionFactory + */ + @Override + @Deprecated + @LogMessage( level = ERROR ) + @Message( value = "Unable to locate static metamodel field : %s#%s", id = 15011 ) + void unableToLocateStaticMetamodelField( String metamodelClassName, + String attributeName ); @LogMessage( level = INFO ) @Message( value = "Using provided datasource", id = 15012 ) diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/util/SharedCacheModeHelper.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/util/SharedCacheModeHelper.java new file mode 100644 index 0000000000..dd1eba6b76 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/util/SharedCacheModeHelper.java @@ -0,0 +1,46 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.jpa.internal.util; + +import javax.persistence.SharedCacheMode; + +/** + * Helper for dealing with SharedCacheMode references as either {@link SharedCacheMode} or String. + * + * @author Steve Ebersole + */ +public class SharedCacheModeHelper { + public static SharedCacheMode asSharedCacheMode(Object value) { + if ( value == null ) { + return null; + } + + if ( SharedCacheMode.class.isInstance( value ) ) { + return (SharedCacheMode) value; + } + else { + return SharedCacheMode.valueOf( value.toString() ); + } + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java index 88049a4d07..3986768b8a 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java @@ -44,7 +44,7 @@ import org.hibernate.jpa.test.metamodel.Customer_; import org.hibernate.jpa.test.metamodel.Info; import org.hibernate.jpa.test.metamodel.LineItem; -import org.hibernate.jpa.internal.metamodel.MetamodelImpl; +import org.hibernate.jpa.metamodel.internal.legacy.MetamodelImpl; import org.hibernate.jpa.test.metamodel.Order; import org.hibernate.jpa.test.metamodel.Phone; import org.hibernate.jpa.test.metamodel.Product; diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java index e710624f5c..b98b6e07d8 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metadata/MetadataTest.java @@ -41,7 +41,7 @@ import org.junit.Test; import org.hibernate.cfg.Configuration; -import org.hibernate.jpa.internal.metamodel.MetamodelImpl; +import org.hibernate.jpa.metamodel.internal.legacy.MetamodelImpl; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.engine.spi.SessionFactoryImplementor;