[hibernate-commits] Hibernate SVN: r17879 - in core/trunk: core/src/main/java/org/hibernate/mapping and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Oct 29 14:57:24 EDT 2009


Author: epbernard
Date: 2009-10-29 14:57:24 -0400 (Thu, 29 Oct 2009)
New Revision: 17879

Added:
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MappedSuperclassTypeImpl.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/SubThing.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java
Modified:
   core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java
   core/trunk/core/src/main/java/org/hibernate/mapping/MappedSuperclass.java
   core/trunk/core/src/main/java/org/hibernate/mapping/PersistentClass.java
   core/trunk/core/src/main/java/org/hibernate/mapping/RootClass.java
   core/trunk/core/src/main/java/org/hibernate/mapping/Subclass.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java
Log:
HHH-4533 Populate the JPA 2 metamodel with the new mapping.MappedSuperclass metadata

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -775,6 +775,21 @@
 			);
 			entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations );
 			persistentClass.setIdentifierMapper( mapper );
+
+			//If id definition is on a mapped superclass, update the mapping
+			final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(
+					inferredData.getDeclaringClass(),
+					inheritanceStatePerClass,
+					mappings
+			);
+			if (superclass != null) {
+				superclass.setDeclaredIdentifierMapper(mapper);
+			}
+			else {
+				//we are for sure on the entity
+				persistentClass.setDeclaredIdentifierMapper( mapper );
+			}
+
 			Property property = new Property();
 			property.setName( "_identifierMapper" );
 			property.setNodeName( "id" );
@@ -1462,6 +1477,20 @@
 			Property prop = propBinder.bind();
 			propBinder.getSimpleValueBinder().setVersion(true);
 			rootClass.setVersion( prop );
+
+			//If version is on a mapped superclass, update the mapping
+			final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(
+					inferredData.getDeclaringClass(),
+					inheritanceStatePerClass,
+					mappings
+			);
+			if (superclass != null) {
+				superclass.setDeclaredVersion(prop);
+			}
+			else {
+				//we know the property is on the actual entity
+				rootClass.setDeclaredVersion( prop );
+			}
 			
 			SimpleValue simpleValue = (SimpleValue) prop.getValue();
 			simpleValue.setNullValue( "undefined" );
@@ -2202,6 +2231,19 @@
 			binder.setProperty( inferredData.getProperty() );
 			Property prop = binder.make();
 			rootClass.setIdentifierProperty( prop );
+			//if the id property is on a superclass, update the metamodel
+			final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(
+					inferredData.getDeclaringClass(),
+					inheritanceStatePerClass,
+					mappings
+			);
+			if (superclass != null) {
+				superclass.setDeclaredIdentifierProperty(prop);
+			}
+			else {
+				//we know the property is on the actual entity
+				rootClass.setDeclaredIdentifierProperty( prop );
+			}
 		}
 	}
 

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -60,6 +60,7 @@
 import org.hibernate.mapping.Table;
 import org.hibernate.mapping.ToOne;
 import org.hibernate.mapping.Value;
+import org.hibernate.mapping.MappedSuperclass;
 import org.hibernate.type.TypeFactory;
 import org.hibernate.util.StringHelper;
 import org.slf4j.Logger;
@@ -575,4 +576,24 @@
 		log.info( "Binding Any Meta definition: {}", defAnn.name() );
 		mappings.addAnyMetaDef( defAnn );
 	}
+
+	public static MappedSuperclass getMappedSuperclassOrNull(XClass declaringClass, 
+															 Map<XClass, InheritanceState> inheritanceStatePerClass,
+															 ExtendedMappings mappings) {
+		boolean retrieve = false;
+		if ( declaringClass != null ) {
+			final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass );
+			if ( inheritanceState == null ) {
+				throw new org.hibernate.annotations.common.AssertionFailure(
+						"Declaring class is not found in the inheritance state hierarchy: " + declaringClass
+				);
+			}
+			if ( inheritanceState.isEmbeddableSuperclass ) {
+				retrieve = true;
+			}
+		}
+		return retrieve ?
+				mappings.getMappedSuperclass( mappings.getReflectionManager().toClass( declaringClass ) ) :
+		        null;
+	}
 }

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -130,7 +130,7 @@
 		final ExtendedMappings mappings = getMappings();
 		final Class type = mappings.getReflectionManager().toClass( declaringClass );
 		MappedSuperclass superclass = mappings.getMappedSuperclass( type );
-		superclass.addProperty( prop );
+		superclass.addDeclaredProperty( prop );
 	}
 
 	private void addPropertyToJoin(Property prop, XClass declaringClass, Join join) {

Modified: core/trunk/core/src/main/java/org/hibernate/mapping/MappedSuperclass.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/MappedSuperclass.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/MappedSuperclass.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -12,20 +12,27 @@
  *
  * Do not use outside this use case.
  *
- * A proper redesign will be evluated in Hibernate 4
+ * 
+ * A proper redesign will be evaluated in Hibernate 4
  *
+ * Implementation details:
+ * properties are copies of their closest sub-persistentClass versions
+ *
  * @author Emmanuel Bernard
  */
 public class MappedSuperclass {
 	private final MappedSuperclass superMappedSuperclass;
 	private final PersistentClass superPersistentClass;
-	private final List properties;
+	private final List declaredProperties;
 	private Class mappedClass;
+	private Property identifierProperty;
+	private Property version;
+	private Component identifierMapper;
 
 	public MappedSuperclass(MappedSuperclass superMappedSuperclass, PersistentClass superPersistentClass) {
 		this.superMappedSuperclass = superMappedSuperclass;
 		this.superPersistentClass = superPersistentClass;
-		this.properties = new ArrayList();
+		this.declaredProperties = new ArrayList();
 	}
 
 	/**
@@ -39,6 +46,14 @@
 		return superMappedSuperclass;
 	}
 
+	public boolean hasIdentifierProperty() {
+		return getIdentifierProperty() != null;
+	}
+
+	public boolean isVersioned() {
+		return getVersion() != null;
+	}
+
 	/**
 	 * Returns the PersistentClass of the first superclass marked as @Entity
 	 * or null if none exists
@@ -49,21 +64,21 @@
 		return superPersistentClass;
 	}
 
-	public Iterator getPropertyIterator() {
-		return properties.iterator();
+	public Iterator getDeclaredPropertyIterator() {
+		return declaredProperties.iterator();
 	}
 
-	public void addProperty(Property p) {
+	public void addDeclaredProperty(Property p) {
 		//Do not add duplicate properties
 		//TODO is it efficient enough?
 		String name = p.getName();
-		Iterator it = properties.iterator();
+		Iterator it = declaredProperties.iterator();
 		while (it.hasNext()) {
 			if ( name.equals( ((Property)it.next()).getName() ) ) {
 				return;
 			}
 		}
-		properties.add(p);
+		declaredProperties.add(p);
 	}
 
 	public Class getMappedClass() {
@@ -73,4 +88,73 @@
 	public void setMappedClass(Class mappedClass) {
 		this.mappedClass = mappedClass;
 	}
+
+	public Property getIdentifierProperty() {
+		//get direct identifiermapper or the one from the super mappedSuperclass
+		// or the one from the super persistentClass
+		Property propagatedIdentifierProp = identifierProperty;
+		if ( propagatedIdentifierProp == null ) {
+			if ( superMappedSuperclass != null ) {
+				propagatedIdentifierProp = superMappedSuperclass.getIdentifierProperty();
+			}
+			if (propagatedIdentifierProp == null && superPersistentClass != null){
+				propagatedIdentifierProp = superPersistentClass.getIdentifierProperty();
+			}
+		}
+		return propagatedIdentifierProp;
+	}
+
+	public Property getDeclaredIdentifierProperty() {
+		return identifierProperty;
+	}
+
+	public void setDeclaredIdentifierProperty(Property prop) {
+		this.identifierProperty = prop;
+	}
+
+	public Property getVersion() {
+		//get direct version or the one from the super mappedSuperclass
+		// or the one from the super persistentClass
+		Property propagatedVersion = version;
+		if (propagatedVersion == null) {
+			if ( superMappedSuperclass != null ) {
+				propagatedVersion = superMappedSuperclass.getVersion();
+			}
+			if (propagatedVersion == null && superPersistentClass != null){
+				propagatedVersion = superPersistentClass.getVersion();
+			}
+		}
+		return propagatedVersion;
+	}
+
+	public Property getDeclaredVersion() {
+		return version;
+	}
+
+	public void setDeclaredVersion(Property prop) {
+		this.version = prop;
+	}
+
+	public Component getIdentifierMapper() {
+		//get direct identifiermapper or the one from the super mappedSuperclass
+		// or the one from the super persistentClass
+		Component propagatedMapper = identifierMapper;
+		if ( propagatedMapper == null ) {
+			if ( superMappedSuperclass != null ) {
+				propagatedMapper = superMappedSuperclass.getIdentifierMapper();
+			}
+			if (propagatedMapper == null && superPersistentClass != null){
+				propagatedMapper = superPersistentClass.getIdentifierMapper();
+			}
+		}
+		return propagatedMapper;
+	}
+
+	public Component getDeclaredIdentifierMapper() {
+		return identifierMapper;
+	}
+
+	public void setDeclaredIdentifierMapper(Component identifierMapper) {
+		this.identifierMapper = identifierMapper;
+	}
 }

Modified: core/trunk/core/src/main/java/org/hibernate/mapping/PersistentClass.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/PersistentClass.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/PersistentClass.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -98,6 +98,7 @@
 
 	protected int optimisticLockMode;
 	private MappedSuperclass superMappedSuperclass;
+	private Component declaredIdentifierMapper;
 
 	public String getClassName() {
 		return className;
@@ -236,8 +237,10 @@
 	public abstract boolean isMutable();
 	public abstract boolean hasIdentifierProperty();
 	public abstract Property getIdentifierProperty();
+	public abstract Property getDeclaredIdentifierProperty();
 	public abstract KeyValue getIdentifier();
 	public abstract Property getVersion();
+	public abstract Property getDeclaredVersion();
 	public abstract Value getDiscriminator();
 	public abstract boolean isInherited();
 	public abstract boolean isPolymorphic();
@@ -776,6 +779,14 @@
 		return identifierMapper;
 	}
 
+	public Component getDeclaredIdentifierMapper() {
+		return declaredIdentifierMapper;
+	}
+
+	public void setDeclaredIdentifierMapper(Component declaredIdentifierMapper) {
+		this.declaredIdentifierMapper = declaredIdentifierMapper;
+	}
+
 	public boolean hasIdentifierMapper() {
 		return identifierMapper != null;
 	}

Modified: core/trunk/core/src/main/java/org/hibernate/mapping/RootClass.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/RootClass.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/RootClass.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -61,7 +61,9 @@
 	private Table table;
 	private boolean discriminatorInsertable = true;
 	private int nextSubclassId = 0;
-		
+	private Property declaredIdentifierProperty;
+	private Property declaredVersion;
+
 	int nextSubclassId() {
 		return ++nextSubclassId;
 	}
@@ -80,6 +82,15 @@
 	public Property getIdentifierProperty() {
 		return identifierProperty;
 	}
+
+	public Property getDeclaredIdentifierProperty() {
+		return declaredIdentifierProperty;
+	}
+
+	public void setDeclaredIdentifierProperty(Property declaredIdentifierProperty) {
+		this.declaredIdentifierProperty = declaredIdentifierProperty;
+	}
+
 	public KeyValue getIdentifier() {
 		return identifier;
 	}
@@ -128,6 +139,15 @@
 	public Property getVersion() {
 		return version;
 	}
+
+	public Property getDeclaredVersion() {
+		return declaredVersion;
+	}
+
+	public void setDeclaredVersion(Property declaredVersion) {
+		this.declaredVersion = declaredVersion;
+	}
+
 	public void setVersion(Property version) {
 		this.version = version;
 	}
@@ -181,6 +201,7 @@
 	public void setIdentifierProperty(Property identifierProperty) {
 		this.identifierProperty = identifierProperty;
 		identifierProperty.setPersistentClass(this);
+
 	}
 
 	public void setMutable(boolean mutable) {

Modified: core/trunk/core/src/main/java/org/hibernate/mapping/Subclass.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/Subclass.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/Subclass.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -70,6 +70,11 @@
 	public Property getIdentifierProperty() {
 		return getSuperclass().getIdentifierProperty();
 	}
+
+	public Property getDeclaredIdentifierProperty() {
+		return null;
+	}
+
 	public KeyValue getIdentifier() {
 		return getSuperclass().getIdentifier();
 	}
@@ -143,6 +148,10 @@
 		return getSuperclass().getVersion();
 	}
 
+	public Property getDeclaredVersion() {
+		return null;
+	}
+
 	public boolean hasEmbeddedIdentifier() {
 		return getSuperclass().hasEmbeddedIdentifier();
 	}

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractIdentifiableType.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -97,7 +97,19 @@
 			}
 		}
 		else {
-			id_ = requireSupertype().getId( javaType );
+			//yuk yuk bad me
+			if (this instanceof MappedSuperclassTypeImpl) {
+				final AbstractIdentifiableType<? super X> supertype = getSupertype();
+				if (supertype != null) {
+					id_ = supertype.getId( javaType );
+				}
+				else {
+					id_ = null;
+				}
+			}
+			else {
+				id_ = requireSupertype().getId( javaType );
+			}
 		}
 		return id_;
 	}
@@ -227,6 +239,7 @@
 		return new Builder<X>() {
 			public void applyIdAttribute(SingularAttributeImpl<X, ?> idAttribute) {
 				AbstractIdentifiableType.this.id = idAttribute;
+				managedBuilder.addAttribute( idAttribute );
 			}
 
 			public void applyIdClassAttributes(Set<SingularAttribute<? super X,?>> idClassAttributes) {

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -54,19 +54,19 @@
 	}
 
 	@SuppressWarnings({ "unchecked" })
-	public <X, Y> AttributeImplementor<X, Y> buildAttribute(AbstractManagedType<X> ownerType, Property property) {
+	public <X, Y> AttributeImplementor<X, Y> buildAttribute(AbstractManagedType<X> ownerType, Property property, boolean getMember) {
 		AttributeContext attrContext = getAttributeContext( property );
 		final AttributeImplementor<X, Y> attribute;
 		if ( attrContext.isCollection() ) {
-			attribute = buildPluralAttribute( ownerType, property, attrContext );
+			attribute = buildPluralAttribute( ownerType, property, attrContext, getMember );
 		}
 		else {
-			final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue() );
+			final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember );
 			attribute = new SingularAttributeImpl<X,Y>(
 					property.getName(),
 					property.getType().getReturnedClass(),
 					ownerType,
-					determineStandardJavaMember( ownerType, property ),
+					getMember ? determineStandardJavaMember( ownerType, property ) : null,
 					false,
 					false,
 					property.isOptional(),
@@ -78,21 +78,21 @@
 	}
 
 	@SuppressWarnings( "unchecked" )
-	private <X, Y, V, K> AttributeImplementor<X, Y> buildPluralAttribute(AbstractManagedType<X> ownerType, Property property, AttributeContext attrContext) {
+	private <X, Y, V, K> AttributeImplementor<X, Y> buildPluralAttribute(AbstractManagedType<X> ownerType, Property property, AttributeContext attrContext, boolean getMember) {
 		AttributeImplementor<X, Y> attribute;
-		final Type<V> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue() );
+		final Type<V> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember );
 		final Class<Y> collectionClass = (Class<Y>) attrContext.getCollectionClass();
 		if ( java.util.Map.class.isAssignableFrom( collectionClass ) ) {
-			final Type<K> keyType = getType( ownerType, attrContext.getKeyTypeStatus(), attrContext.getKeyValue() );
+			final Type<K> keyType = getType( ownerType, attrContext.getKeyTypeStatus(), attrContext.getKeyValue(), getMember );
 			attribute = PluralAttributeImpl.create( ownerType, attrType, collectionClass, keyType )
-					.member( determineStandardJavaMember( ownerType, property ) )
+					.member( getMember ? determineStandardJavaMember( ownerType, property ) : null )
 					.property( property )
 					.persistentAttributeType( attrContext.getElementAttributeType() )
 					.build();
 		}
 		else {
 			attribute =  PluralAttributeImpl.create( ownerType, attrType, collectionClass, null )
-					.member( determineStandardJavaMember( ownerType, property ) )
+					.member( getMember ? determineStandardJavaMember( ownerType, property ) : null )
 					.property( property )
 					.persistentAttributeType( attrContext.getElementAttributeType() )
 					.build();
@@ -100,13 +100,13 @@
 		return attribute;
 	}
 
-	private <X> Type<X> getType(AbstractManagedType owner, AttributeContext.TypeStatus elementTypeStatus, Value value) {
+	private <X> Type<X> getType(AbstractManagedType owner, AttributeContext.TypeStatus elementTypeStatus, Value value, boolean getMember) {
 		final org.hibernate.type.Type type = value.getType();
 		switch ( elementTypeStatus ) {
 			case BASIC:
 				return buildBasicType( type );
 			case EMBEDDABLE:
-				return buildEmbeddableType( owner, value, type );
+				return buildEmbeddableType( owner, value, type, getMember );
 			case ENTITY:
 				return buildEntityType( type );
 			default:
@@ -128,7 +128,7 @@
 	}
 
 	@SuppressWarnings( "unchecked" )
-	private <X> Type<X> buildEmbeddableType(AbstractManagedType owner, Value value, org.hibernate.type.Type type) {
+	private <X> Type<X> buildEmbeddableType(AbstractManagedType owner, Value value, org.hibernate.type.Type type, boolean getMember) {
 		//build embedable type
 		final Class<X> clazz = type.getReturnedClass();
 		final EmbeddableTypeImpl<X> embeddableType = new EmbeddableTypeImpl<X>( clazz, owner, (ComponentType) type );
@@ -137,22 +137,22 @@
 		final Iterator<Property> subProperties = component.getPropertyIterator();
 		while ( subProperties.hasNext() ) {
 			final Property property = subProperties.next();
-			embeddableType.getBuilder().addAttribute( buildAttribute( embeddableType, property ) );
+			embeddableType.getBuilder().addAttribute( buildAttribute( embeddableType, property, getMember ) );
 		}
 		embeddableType.lock();
 		return embeddableType;
 	}
 
 	@SuppressWarnings({ "unchecked" })
-	public <X, Y> SingularAttributeImpl<X, Y> buildIdAttribute(AbstractManagedType<X> ownerType, Property property) {
+	public <X, Y> SingularAttributeImpl<X, Y> buildIdAttribute(AbstractManagedType<X> ownerType, Property property, boolean getMember) {
 		final AttributeContext attrContext = getAttributeContext( property );
-		final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue() );
+		final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember );
 		final Class<Y> idJavaType = property.getType().getReturnedClass();
 		return new SingularAttributeImpl.Identifier(
 				property.getName(),
 				idJavaType,
 				ownerType,
-				determineIdentifierJavaMember( ownerType, property ),
+				getMember ? determineIdentifierJavaMember( ownerType, property ) : null,
 				attrType,
 				attrContext.getElementAttributeType()
 		);
@@ -232,15 +232,15 @@
 	}
 
 	@SuppressWarnings({ "unchecked" })
-	public <X, Y> SingularAttributeImpl<X, Y> buildVerisonAttribute(AbstractManagedType<X> ownerType, Property property) {
+	public <X, Y> SingularAttributeImpl<X, Y> buildVersionAttribute(AbstractManagedType<X> ownerType, Property property, boolean getMember) {
 		final AttributeContext attrContext = getAttributeContext( property );
 		final Class<Y> javaType = property.getType().getReturnedClass();
-		final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue() );
+		final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember );
 		return new SingularAttributeImpl.Version(
 				property.getName(),
 				javaType,
 				ownerType,
-				determineVersionJavaMember( ownerType, property ),
+				getMember ? determineVersionJavaMember( ownerType, property ) : null,
 				attrType,
 				attrContext.getElementAttributeType()
 		);
@@ -252,7 +252,7 @@
 			// this should never happen, but to be safe...
 			throw new IllegalArgumentException( "Given property did not match declared version property" );
 		}
-		return entityMetamodel.getTuplizer( EntityMode.POJO ).getIdentifierGetter().getMember();
+		return entityMetamodel.getTuplizer( EntityMode.POJO ).getVersionGetter().getMember();
 	}
 
 	private static class AttributeContext {

Added: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MappedSuperclassTypeImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MappedSuperclassTypeImpl.java	                        (rev 0)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MappedSuperclassTypeImpl.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,21 @@
+package org.hibernate.ejb.metamodel;
+
+import javax.persistence.metamodel.MappedSuperclassType;
+import javax.persistence.metamodel.Type;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class MappedSuperclassTypeImpl<X> extends AbstractIdentifiableType<X> implements MappedSuperclassType<X> {
+	public MappedSuperclassTypeImpl(
+			Class<X> javaType,
+			AbstractIdentifiableType<? super X> superType,
+			boolean hasIdentifierProperty,
+			boolean versioned) {
+		super( javaType, superType, hasIdentifierProperty, versioned );
+	}
+
+	public PersistenceType getPersistenceType() {
+		return PersistenceType.MAPPED_SUPERCLASS;
+	}
+}

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -25,16 +25,18 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
 import javax.persistence.metamodel.Attribute;
 import javax.persistence.metamodel.SingularAttribute;
-import javax.persistence.MappedSuperclass;
 
+import org.hibernate.mapping.MappedSuperclass;
 import org.hibernate.mapping.PersistentClass;
 import org.hibernate.mapping.Property;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.annotations.common.AssertionFailure;
 
 /**
  * Defines a context for storing information during the building of the {@link MetamodelImpl}.
@@ -53,14 +55,18 @@
 	private final SessionFactoryImplementor sessionFactory;
 	private final AttributeFactory attributeFactory = new AttributeFactory( this );
 
-	private HashMap<Class<?>,EntityTypeImpl<?>> entityTypes
+	private Map<Class<?>,EntityTypeImpl<?>> entityTypes
 			= new HashMap<Class<?>, EntityTypeImpl<?>>();
-	private HashMap<String,EntityTypeImpl<?>> entityTypesByEntityName
+	private Map<String,EntityTypeImpl<?>> entityTypesByEntityName
 			= new HashMap<String, EntityTypeImpl<?>>();
-	private LinkedHashMap<PersistentClass,EntityTypeImpl<?>> entityTypesByPersistentClass
-			= new LinkedHashMap<PersistentClass,EntityTypeImpl<?>>();
-	private HashMap<Class<?>, EmbeddableTypeImpl<?>> embeddables
+	private Map<PersistentClass,EntityTypeImpl<?>> entityTypesByPersistentClass
+			= new HashMap<PersistentClass,EntityTypeImpl<?>>();
+	private Map<Class<?>, EmbeddableTypeImpl<?>> embeddables
 			= new HashMap<Class<?>, EmbeddableTypeImpl<?>>();
+	private Map<MappedSuperclass, MappedSuperclassTypeImpl<?>> mappedSuperclassByMappedSuperclassMapping
+			= new HashMap<MappedSuperclass,MappedSuperclassTypeImpl<?>>();
+	//this list contains MappedSuperclass and EntityTypes ordered by superclass first
+	private List<Object> orderedMappings = new ArrayList<Object>();
 
 	public MetadataContext(SessionFactoryImplementor sessionFactory) {
 		this.sessionFactory = sessionFactory;
@@ -87,12 +93,19 @@
 		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 );
+	}
+
 	/**
 	 * Given a Hibernate {@link PersistentClass}, locate the corresponding JPA {@link org.hibernate.type.EntityType}
 	 * implementation.  May retur null if the given {@link PersistentClass} has not yet been processed.
@@ -128,54 +141,120 @@
 
 	@SuppressWarnings({ "unchecked" })
 	public void wrapUp() {
-		// IMPL NOTE : entityTypesByPersistentClass is a insertion-ordered map, where the insertion order
-		//		ensures that a type's super type is already processed...
-		for ( Map.Entry<PersistentClass,EntityTypeImpl<?>> entry : entityTypesByPersistentClass.entrySet() ) {
-			applyIdMetadata( entry.getKey(), entry.getValue() );
-			applyVersionAttribute( entry.getKey(), entry.getValue() );
-			Iterator<Property> properties = ( Iterator<Property> ) entry.getKey().getPropertyIterator();
-			while ( properties.hasNext() ) {
-				final Property property = properties.next();
-				final Attribute attribute = attributeFactory.buildAttribute( entry.getValue(), property );
-				entry.getValue().getBuilder().addAttribute( attribute );
+		//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;
+				final EntityTypeImpl<?> jpa2Mapping = entityTypesByPersistentClass.get( safeMapping );
+				applyIdMetadata( safeMapping, jpa2Mapping );
+				applyVersionAttribute( safeMapping, jpa2Mapping );
+				Iterator<Property> properties = ( Iterator<Property> ) safeMapping.getDeclaredPropertyIterator();
+				while ( properties.hasNext() ) {
+					final Property property = properties.next();
+					final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property, true );
+					jpa2Mapping.getBuilder().addAttribute( attribute );
+				}
+				jpa2Mapping.lock();
+				populateStaticMetamodel( jpa2Mapping );
 			}
-			entry.getValue().lock();
-			populateStaticMetamodel( entry.getValue() );
+			else if ( MappedSuperclass.class.isAssignableFrom( mapping.getClass() ) ) {
+				@SuppressWarnings( "unchecked" )
+				final MappedSuperclass safeMapping = (MappedSuperclass) mapping;
+				final MappedSuperclassTypeImpl<?> jpa2Mapping = mappedSuperclassByMappedSuperclassMapping.get(
+						safeMapping
+				);
+				applyIdMetadata( safeMapping, jpa2Mapping );
+				applyVersionAttribute( safeMapping, jpa2Mapping );
+				Iterator<Property> properties = ( Iterator<Property> ) safeMapping.getDeclaredPropertyIterator();
+				while ( properties.hasNext() ) {
+					final Property property = properties.next();
+					final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property, false );
+					jpa2Mapping.getBuilder().addAttribute( attribute );
+				}
+				jpa2Mapping.lock();
+				populateStaticMetamodel( jpa2Mapping );
+			}
+			else {
+				throw new AssertionFailure( "Unexpected mapping type: " + mapping.getClass() );
+			}
 		}
 	}
 
 	private <X> void applyIdMetadata(PersistentClass persistentClass, EntityTypeImpl<X> jpaEntityType) {
 		if ( persistentClass.hasIdentifierProperty() ) {
-			jpaEntityType.getBuilder().applyIdAttribute(
-					attributeFactory.buildIdAttribute( jpaEntityType, persistentClass.getIdentifierProperty() ) 
-			);
+			final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty();
+			if (declaredIdentifierProperty != null) {
+				jpaEntityType.getBuilder().applyIdAttribute(
+						attributeFactory.buildIdAttribute( jpaEntityType, declaredIdentifierProperty, true )
+				);
+			}
 		}
 		else {
 			jpaEntityType.getBuilder().applyIdClassAttributes( buildIdClassAttributes( jpaEntityType, persistentClass ) );
 		}
 	}
 
+	private <X> void applyIdMetadata(MappedSuperclass mappingType, MappedSuperclassTypeImpl<X> jpaMappingType) {
+		if ( mappingType.hasIdentifierProperty() ) {
+			final Property declaredIdentifierProperty = mappingType.getDeclaredIdentifierProperty();
+			if (declaredIdentifierProperty != null) {
+				jpaMappingType.getBuilder().applyIdAttribute(
+						attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty, false )
+				);
+			}
+		}
+		//an MappedSuperclass can have no identifier if the id is set below in the hierarchy
+		else if ( mappingType.getIdentifierMapper() != null ){
+			final Set<SingularAttribute<? super X, ?>> attributes = buildIdClassAttributes(
+					jpaMappingType, mappingType
+			);
+			jpaMappingType.getBuilder().applyIdClassAttributes( attributes );
+		}
+	}
+
 	private <X> void applyVersionAttribute(PersistentClass persistentClass, EntityTypeImpl<X> jpaEntityType) {
-		if ( ! persistentClass.isVersioned() ) {
-			return;
+		final Property declaredVersion = persistentClass.getDeclaredVersion();
+		if (declaredVersion != null) {
+			jpaEntityType.getBuilder().applyVersionAttribute(
+					attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion, true )
+			);
 		}
-		jpaEntityType.getBuilder().applyVersionAttribute(
-				attributeFactory.buildVerisonAttribute( jpaEntityType, persistentClass.getVersion() )
-		);
 	}
 
-	@SuppressWarnings( "unchecked")
+	private <X> void applyVersionAttribute(MappedSuperclass mappingType, MappedSuperclassTypeImpl<X> jpaMappingType) {
+		final Property declaredVersion = mappingType.getDeclaredVersion();
+		if ( declaredVersion != null ) {
+			jpaMappingType.getBuilder().applyVersionAttribute(
+					attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion, false )
+			);
+		}
+	}
+
 	private <X> Set<SingularAttribute<? super X, ?>> buildIdClassAttributes(
 			EntityTypeImpl<X> jpaEntityType,
 			PersistentClass persistentClass) {
 		Set<SingularAttribute<? super X, ?>> attributes = new HashSet<SingularAttribute<? super X, ?>>();
+		@SuppressWarnings( "unchecked")
 		Iterator<Property> properties = persistentClass.getIdentifierMapper().getPropertyIterator();
 		while ( properties.hasNext() ) {
-			attributes.add( attributeFactory.buildIdAttribute( jpaEntityType, properties.next() ) );
+			attributes.add( attributeFactory.buildIdAttribute( jpaEntityType, properties.next(), true ) );
 		}
 		return attributes;
 	}
 
+	private <X> Set<SingularAttribute<? super X, ?>> buildIdClassAttributes(
+			MappedSuperclassTypeImpl<X> jpaMappingType,
+			MappedSuperclass mappingType) {
+		Set<SingularAttribute<? super X, ?>> attributes = new HashSet<SingularAttribute<? super X, ?>>();
+		@SuppressWarnings( "unchecked" )
+		Iterator<Property> properties = mappingType.getIdentifierMapper().getPropertyIterator();
+		while ( properties.hasNext() ) {
+			attributes.add( attributeFactory.buildIdAttribute( jpaMappingType, properties.next(), false ) );
+		}
+		return attributes;
+	}
+
 	private <X> void populateStaticMetamodel(AbstractManagedType<X> managedType) {
 		final Class<X> managedTypeClass = managedType.getJavaType();
 		final String metamodelClassName = managedTypeClass.getName() + "_";
@@ -206,4 +285,7 @@
 		// push the attributes on to the metamodel class...
 	}
 
+	public MappedSuperclassTypeImpl<?> locateMappedSuperclassType(MappedSuperclass mappedSuperclass) {
+		return mappedSuperclassByMappedSuperclassMapping.get(mappedSuperclass);
+	}
 }

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -32,6 +32,7 @@
 import javax.persistence.metamodel.EmbeddableType;
 
 import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.MappedSuperclass;
 import org.hibernate.engine.SessionFactoryImplementor;
 
 /**
@@ -46,7 +47,7 @@
 
 	/**
 	 * Build the metamodel using the information from the collection of Hibernate
-	 * {@link PersistentClass} models as well as the Hibernate {@link SessionFactory}.
+	 * {@link 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 factry.
@@ -74,16 +75,24 @@
 		return entityType;
 	}
 
-	@SuppressWarnings({ "unchecked" })
+	//TODO remove / reduce @SW scope
+	@SuppressWarnings( "unchecked" )
 	private static EntityTypeImpl<?> buildEntityType(PersistentClass persistentClass, MetadataContext context) {
-		final PersistentClass superPersistentClass = persistentClass.getSuperclass();
-		final EntityTypeImpl superEntityType = superPersistentClass == null
+		final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass();
+		AbstractIdentifiableType<?> superType = superMappedSuperclass == null
 				? null
-				: locateOrBuildEntityType( superPersistentClass, context );
+				: 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 );
+		}
 		final Class javaType = persistentClass.getMappedClass();
 		EntityTypeImpl entityType = new EntityTypeImpl(
 				javaType,
-				superEntityType,
+				superType,
 				persistentClass.getClassName(),
 				persistentClass.hasIdentifierProperty(),
 				persistentClass.isVersioned()
@@ -92,6 +101,41 @@
 		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.
 	 *

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Animal.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,31 @@
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at MappedSuperclass
+public class Animal extends SubThing {
+	private Long id;
+	private int legNbr;
+
+	@Id @GeneratedValue
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public int getLegNbr() {
+		return legNbr;
+	}
+
+	public void setLegNbr(int legNbr) {
+		this.legNbr = legNbr;
+	}
+}

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cat.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,19 @@
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.Entity;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+public class Cat extends Cattish {
+	private String nickname;
+
+	public String getNickname() {
+		return nickname;
+	}
+
+	public void setNickname(String nickname) {
+		this.nickname = nickname;
+	}
+}

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Cattish.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,19 @@
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.MappedSuperclass;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at MappedSuperclass
+public class Cattish extends Feline {
+	private long hoursOfSleep;
+
+	public long getHoursOfSleep() {
+		return hoursOfSleep;
+	}
+
+	public void setHoursOfSleep(long hoursOfSleep) {
+		this.hoursOfSleep = hoursOfSleep;
+	}
+}

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Dog.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,19 @@
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.Entity;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+public class Dog extends Animal {
+	private String name;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Feline.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,19 @@
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.Entity;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+public class Feline extends Animal {
+	private String color;
+
+	public String getColor() {
+		return color;
+	}
+
+	public void setColor(String color) {
+		this.color = color;
+	}
+}

Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java	2009-10-29 17:22:00 UTC (rev 17878)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -12,6 +12,9 @@
 import javax.persistence.metamodel.PluralAttribute;
 import javax.persistence.metamodel.MapAttribute;
 import javax.persistence.metamodel.ListAttribute;
+import javax.persistence.metamodel.MappedSuperclassType;
+import javax.persistence.metamodel.CollectionAttribute;
+import javax.persistence.metamodel.IdentifiableType;
 
 import org.hibernate.ejb.test.TestCase;
 
@@ -53,6 +56,8 @@
 		assertFalse( fridgeType.hasVersionAttribute() );
 		assertEquals( Type.PersistenceType.ENTITY, fridgeType.getPersistenceType() );
 
+		assertEquals( 3, fridgeType.getDeclaredAttributes().size() );
+
 		final EntityType<House> houseType = factory.getMetamodel().entity( House.class );
 		assertTrue( houseType.hasSingleIdAttribute() );
 		final SingularAttribute<House, House.Key> houseId = houseType.getDeclaredId( House.Key.class );
@@ -74,6 +79,7 @@
 		final SingularAttribute<? super FoodItem, Long> version = foodType.getVersion( Long.class );
 		assertNotNull( version );
 		assertTrue( version.isVersion() );
+		assertEquals( 3, foodType.getDeclaredAttributes().size() );
 
 	}
 
@@ -158,15 +164,96 @@
 		assertEquals( PluralAttribute.CollectionType.LIST, roomsBySize.getCollectionType() );
 	}
 
-		//todo test plural
+	public void testHierarchy() {
+		final EntityType<Cat> cat = factory.getMetamodel().entity( Cat.class );
+		assertNotNull( cat );
+		assertEquals( 7, cat.getAttributes().size() );
+		assertEquals( 1, cat.getDeclaredAttributes().size() );
 
+		assertTrue( cat.hasVersionAttribute() );
+		assertEquals( "version", cat.getVersion(Long.class).getName() );
+		verifyDeclaredVersiobnNotPresent( cat );
+		verifyDeclaredIdNotPresentAndIdPresent(cat);
+
+		assertEquals( Type.PersistenceType.MAPPED_SUPERCLASS, cat.getSupertype().getPersistenceType() );
+		MappedSuperclassType<Cattish> cattish = (MappedSuperclassType<Cattish>) cat.getSupertype();
+		assertEquals( 6, cattish.getAttributes().size() );
+		assertEquals( 1, cattish.getDeclaredAttributes().size() );
+
+		assertTrue( cattish.hasVersionAttribute() );
+		assertEquals( "version", cattish.getVersion(Long.class).getName() );
+		verifyDeclaredVersiobnNotPresent( cattish );
+		verifyDeclaredIdNotPresentAndIdPresent(cattish);
+
+		assertEquals( Type.PersistenceType.ENTITY, cattish.getSupertype().getPersistenceType() );
+		EntityType<Feline> feline = (EntityType<Feline>) cattish.getSupertype();
+		assertEquals( 5, feline.getAttributes().size() );
+		assertEquals( 1, feline.getDeclaredAttributes().size() );
+
+		assertTrue( feline.hasVersionAttribute() );
+		assertEquals( "version", feline.getVersion(Long.class).getName() );
+		verifyDeclaredVersiobnNotPresent( feline );
+		verifyDeclaredIdNotPresentAndIdPresent(feline);
+
+		assertEquals( Type.PersistenceType.MAPPED_SUPERCLASS, feline.getSupertype().getPersistenceType() );
+		MappedSuperclassType<Animal> animal = (MappedSuperclassType<Animal>) feline.getSupertype();
+		assertEquals( 4, animal.getAttributes().size() );
+		assertEquals( 2, animal.getDeclaredAttributes().size() );
+
+		assertTrue( animal.hasVersionAttribute() );
+		assertEquals( "version", animal.getVersion(Long.class).getName() );
+		verifyDeclaredVersiobnNotPresent( animal );
+		assertEquals( "id", animal.getId(Long.class).getName() );
+		assertEquals( "id", animal.getDeclaredId(Long.class).getName() );
+
+		assertEquals( Type.PersistenceType.MAPPED_SUPERCLASS, animal.getSupertype().getPersistenceType() );
+		MappedSuperclassType<Thing> thing = (MappedSuperclassType<Thing>) animal.getSupertype();
+		assertEquals( 2, thing.getAttributes().size() );
+		assertEquals( 2, thing.getDeclaredAttributes().size() );
+		final SingularAttribute<Thing, Double> weight = thing.getDeclaredSingularAttribute( "weight", Double.class );
+		assertEquals( Double.class, weight.getJavaType() );
+
+		assertEquals( "version", thing.getVersion(Long.class).getName() );
+		assertEquals( "version", thing.getDeclaredVersion(Long.class).getName() );
+		assertNull( thing.getId( Long.class ) );
+
+		assertNull( thing.getSupertype() );
+	}
+
+	private void verifyDeclaredIdNotPresentAndIdPresent(IdentifiableType<?> type) {
+		assertEquals( "id", type.getId(Long.class).getName() );
+		try {
+			type.getDeclaredId(Long.class);
+			fail("Should not have a declared id");
+		}
+		catch (IllegalArgumentException e) {
+			//success
+		}
+	}
+
+	private void verifyDeclaredVersiobnNotPresent(IdentifiableType<?> type) {
+		try {
+			type.getDeclaredVersion(Long.class);
+			fail("Should not have a declared version");
+		}
+		catch (IllegalArgumentException e) {
+			//success
+		}
+	}
+
+	//todo test plural
+
 	@Override
 	public Class[] getAnnotatedClasses() {
 		return new Class[]{
 				Fridge.class,
 				FoodItem.class,
 				Person.class,
-				House.class
+				House.class,
+				Dog.class,
+				Cat.class,
+				Cattish.class,
+				Feline.class
 		};
 	}
 

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/SubThing.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/SubThing.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/SubThing.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,17 @@
+package org.hibernate.ejb.test.metadata;
+
+/**
+ * @author Emmanuel Bernard
+ */
+//not an entity but in between mapped superclass and entity
+public class SubThing extends Thing {
+	private String blah;
+
+	public String getBlah() {
+		return blah;
+	}
+
+	public void setBlah(String blah) {
+		this.blah = blah;
+	}
+}

Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java	                        (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/Thing.java	2009-10-29 18:57:24 UTC (rev 17879)
@@ -0,0 +1,30 @@
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Version;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at MappedSuperclass
+public class Thing {
+	private Double weight;
+	private Long version;
+
+	public Double getWeight() {
+		return weight;
+	}
+
+	public void setWeight(Double weight) {
+		this.weight = weight;
+	}
+
+	@Version
+	public Long getVersion() {
+		return version;
+	}
+
+	public void setVersion(Long version) {
+		this.version = version;
+	}
+}



More information about the hibernate-commits mailing list