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:
+ * - {@code cfg.xml}
+ * - {@code hbm.xml}
+ * - annotation
+ *
+ * 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:
+ * - {@code hbm}
+ * - {@code class}
+ * - both {@code hbm} and {@code class} separated by comma
+ *
+ *
+ * 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:
+ * -
+ * 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";
+
}
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 super X> superType,
+ boolean hasIdentifierProperty,
+ boolean versioned) {
+ super( javaType, superType );
+ this.hasIdentifierProperty = hasIdentifierProperty;
+ isVersioned = versioned;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public AbstractIdentifiableType super X> getSupertype() {
+ return ( AbstractIdentifiableType super X> ) 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 super X> requireSupertype() {
+ if ( getSupertype() == null ) {
+ throw new IllegalStateException( "No supertype found" );
+ }
+ return getSupertype();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasSingleIdAttribute() {
+ return hasIdentifierProperty;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings({ "unchecked" })
+ public SingularAttribute super X, Y> getId(Class javaType) {
+ final SingularAttribute super X, Y> id_;
+ if ( id != null ) {
+ checkSimpleId();
+ id_ = ( SingularAttribute super X, Y> ) 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 super X> 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 super X, Y> getVersion(Class javaType) {
+ if ( ! hasVersionAttribute() ) {
+ return null;
+ }
+ final SingularAttribute super X, Y> version_;
+ if ( version != null ) {
+ version_ = ( SingularAttribute super X, Y> ) 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 super X,?> 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 super X> superType;
+
+ private final Map> declaredAttributes
+ = new HashMap>();
+ private final Map> declaredSingularAttributes
+ = new HashMap>();
+ private final Map> declaredPluralAttributes
+ = new HashMap>();
+
+ protected AbstractManagedType(Class javaType, AbstractManagedType super X> superType) {
+ super( javaType );
+ this.superType = superType;
+ }
+
+ public AbstractManagedType super X> 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 super X, ?> getAttribute(String name) {
+ Attribute super X, ?> 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 super X, ?> getSingularAttribute(String name) {
+ SingularAttribute super X, ?> 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 super X, Y> getSingularAttribute(String name, Class type) {
+ SingularAttribute super X, ?> attribute = declaredSingularAttributes.get( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getSingularAttribute( name );
+ }
+ checkTypeForSingleAttribute( "SingularAttribute ", attribute, name, type );
+ return ( SingularAttribute super X, Y> ) 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 super X, ?> getCollection(String name) {
+ PluralAttribute super X, ?, ?> attribute = getPluralAttribute( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ basicCollectionCheck( attribute, name );
+ return ( CollectionAttribute ) attribute;
+ }
+
+ private PluralAttribute super X, ?, ?> getPluralAttribute(String name) {
+ return declaredPluralAttributes.get( name );
+ }
+
+ private void basicCollectionCheck(PluralAttribute super X, ?, ?> 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 super X, ?> getSet(String name) {
+ PluralAttribute super X, ?, ?> attribute = getPluralAttribute( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ basicSetCheck( attribute, name );
+ return (SetAttribute super X, ?>) attribute;
+ }
+
+ private void basicSetCheck(PluralAttribute super X, ?, ?> 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 super X, ?> getList(String name) {
+ PluralAttribute super X, ?, ?> attribute = getPluralAttribute( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ basicListCheck( attribute, name );
+ return (ListAttribute super X, ?>) attribute;
+ }
+
+ private void basicListCheck(PluralAttribute super X, ?, ?> 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 super X, ?, ?> getMap(String name) {
+ PluralAttribute super X, ?, ?> attribute = getPluralAttribute( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ basicMapCheck( attribute, name );
+ return (MapAttribute super X, ?, ?>) attribute;
+ }
+
+ private void basicMapCheck(PluralAttribute super X, ?, ?> 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 super X, E> getCollection(String name, Class elementType) {
+ PluralAttribute super X, ?, ?> attribute = declaredPluralAttributes.get( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ checkCollectionElementType( attribute, name, elementType );
+ return ( CollectionAttribute super X, E> ) 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 super X, E> getSet(String name, Class elementType) {
+ PluralAttribute super X, ?, ?> attribute = declaredPluralAttributes.get( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ checkSetElementType( attribute, name, elementType );
+ return ( SetAttribute super X, E> ) attribute;
+ }
+
+ private void checkSetElementType(PluralAttribute super X, ?, ?> 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 super X, E> getList(String name, Class elementType) {
+ PluralAttribute super X, ?, ?> attribute = declaredPluralAttributes.get( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ checkListElementType( attribute, name, elementType );
+ return ( ListAttribute super X, E> ) attribute;
+ }
+
+ private void checkListElementType(PluralAttribute super X, ?, ?> 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 super X, K, V> getMap(String name, Class keyType, Class valueType) {
+ PluralAttribute super X, ?, ?> attribute = getPluralAttribute( name );
+ if ( attribute == null && getSupertype() != null ) {
+ attribute = getSupertype().getPluralAttribute( name );
+ }
+ checkMapValueType( attribute, name, valueType );
+ final MapAttribute super X, K, V> mapAttribute = ( MapAttribute super X, K, V> ) attribute;
+ checkMapKeyType( mapAttribute, name, keyType );
+ return mapAttribute;
+ }
+
+ private void checkMapValueType(PluralAttribute super X, ?, ?> attribute, String name, Class valueType) {
+ checkTypeForPluralAttributes( "MapAttribute", attribute, name, valueType, PluralAttribute.CollectionType.MAP);
+ }
+
+ private void checkMapKeyType(MapAttribute super X, K, V> 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 super X> 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 super X> 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: