HHH-4537 Add support for MappedSuperclassType Members in JPA 2

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17883 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Emmanuel Bernard 2009-10-30 13:00:07 +00:00
parent e759809c35
commit 2dc911855b
4 changed files with 113 additions and 29 deletions

View File

@ -27,6 +27,7 @@ import java.lang.reflect.Member;
import java.util.Iterator;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Type;
import javax.persistence.metamodel.IdentifiableType;
import org.hibernate.EntityMode;
import org.hibernate.type.EmbeddedComponentType;
@ -38,6 +39,7 @@ import org.hibernate.mapping.Map;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.tuple.entity.EntityMetamodel;
/**
@ -144,7 +146,7 @@ public class AttributeFactory {
}
@SuppressWarnings({ "unchecked" })
public <X, Y> SingularAttributeImpl<X, Y> buildIdAttribute(AbstractManagedType<X> ownerType, Property property, boolean getMember) {
public <X, Y> SingularAttributeImpl<X, Y> buildIdAttribute(AbstractIdentifiableType<X> ownerType, Property property, boolean getMember) {
final AttributeContext attrContext = getAttributeContext( property );
final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember );
final Class<Y> idJavaType = property.getType().getReturnedClass();
@ -158,7 +160,7 @@ public class AttributeFactory {
);
}
private Member determineIdentifierJavaMember(AbstractManagedType ownerType, Property property) {
private Member determineIdentifierJavaMember(IdentifiableType ownerType, Property property) {
// see below
// final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property );
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
@ -191,12 +193,26 @@ public class AttributeFactory {
// .getEntityMetamodel();
// }
// so we use the owner's java class to lookup the persister/entitymetamodel
private EntityMetamodel getDeclarerEntityMetamodel(AbstractManagedType ownerType) {
return context.getSessionFactory()
.getEntityPersister( ownerType.getJavaType().getName() )
private EntityMetamodel getDeclarerEntityMetamodel(IdentifiableType<?> ownerType) {
final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
if ( persistenceType == Type.PersistenceType.ENTITY) {
return context.getSessionFactory()
.getEntityPersister( ownerType.getJavaType().getName() )
.getEntityMetamodel();
}
else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS) {
PersistentClass persistentClass =
context.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl<?>) ownerType );
return context.getSessionFactory()
.getEntityPersister( persistentClass.getClassName() )
.getEntityMetamodel();
}
else {
throw new AssertionFailure( "Cannot get the metamodel for PersistenceType: " + persistenceType );
}
}
// getting the owning PersistentClass from the Property is broken in certain cases with annotations...
// private Member determineStandardJavaMember(Property property) {
// final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property );
@ -206,33 +222,39 @@ public class AttributeFactory {
// return entityMetamodel.getTuplizer( EntityMode.POJO ).getGetter( index ).getMember();
// }
// so we use the owner's java class to lookup the persister/entitymetamodel
private Member determineStandardJavaMember(AbstractManagedType ownerType, Property property) {
if ( Type.PersistenceType.EMBEDDABLE == ownerType.getPersistenceType() ) {
EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl ) ownerType;
private Member determineStandardJavaMember(AbstractManagedType<?> ownerType, Property property) {
final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
if ( Type.PersistenceType.EMBEDDABLE == persistenceType ) {
EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl<?> ) ownerType;
return embeddableType.getHibernateType().getTuplizerMapping()
.getTuplizer( EntityMode.POJO )
.getGetter( embeddableType.getHibernateType().getPropertyIndex( property.getName() ) )
.getMember();
}
else if ( Type.PersistenceType.ENTITY == ownerType.getPersistenceType() ) {
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
final String propertyName = property.getName();
final Integer index = entityMetamodel.getPropertyIndexOrNull( propertyName );
if ( index == null ) {
// just like in #determineIdentifierJavaMember , this *should* indicate we have an IdClass mapping
return determineVirtualIdentifierJavaMember( entityMetamodel, property );
}
else {
return entityMetamodel.getTuplizer( EntityMode.POJO ).getGetter( index ).getMember();
}
else if ( Type.PersistenceType.ENTITY == persistenceType
|| Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) {
return determineStandardJavaMemberOutOfIdentifiableType( (IdentifiableType<?>) ownerType, property );
}
else {
throw new IllegalArgumentException( "Unexpected owner type : " + ownerType.getPersistenceType() );
throw new IllegalArgumentException( "Unexpected owner type : " + persistenceType );
}
}
private Member determineStandardJavaMemberOutOfIdentifiableType(IdentifiableType<?> ownerType, Property property) {
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
final String propertyName = property.getName();
final Integer index = entityMetamodel.getPropertyIndexOrNull( propertyName );
if ( index == null ) {
// just like in #determineIdentifierJavaMember , this *should* indicate we have an IdClass mapping
return determineVirtualIdentifierJavaMember( entityMetamodel, property );
}
else {
return entityMetamodel.getTuplizer( EntityMode.POJO ).getGetter( index ).getMember();
}
}
@SuppressWarnings({ "unchecked" })
public <X, Y> SingularAttributeImpl<X, Y> buildVersionAttribute(AbstractManagedType<X> ownerType, Property property, boolean getMember) {
public <X, Y> SingularAttributeImpl<X, Y> buildVersionAttribute(AbstractIdentifiableType<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(), getMember );
@ -246,7 +268,7 @@ public class AttributeFactory {
);
}
private Member determineVersionJavaMember(AbstractManagedType ownerType, Property property) {
private Member determineVersionJavaMember(IdentifiableType ownerType, Property property) {
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
if ( ! property.getName().equals( entityMetamodel.getVersionProperty().getName() ) ) {
// this should never happen, but to be safe...

View File

@ -31,12 +31,14 @@ import java.util.List;
import java.util.ArrayList;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.swing.*;
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;
import org.hibernate.AnnotationException;
/**
* Defines a context for storing information during the building of the {@link MetamodelImpl}.
@ -67,6 +69,14 @@ class MetadataContext {
= new HashMap<MappedSuperclass,MappedSuperclassTypeImpl<?>>();
//this list contains MappedSuperclass and EntityTypes ordered by superclass first
private List<Object> orderedMappings = new ArrayList<Object>();
/**
* Stack of PersistentClass being process. Last in the list is the highest in the stack.
*
*/
private List<PersistentClass> stackOfPersistentClassesBeingProcessed
= new ArrayList<PersistentClass>();
private Map<MappedSuperclassTypeImpl<?>, PersistentClass> mappedSuperClassTypeToPersistentClass
= new HashMap<MappedSuperclassTypeImpl<?>, PersistentClass>();
public MetadataContext(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
@ -104,6 +114,7 @@ class MetadataContext {
MappedSuperclassTypeImpl<?> mappedSuperclassType) {
mappedSuperclassByMappedSuperclassMapping.put( mappedSuperclass, mappedSuperclassType );
orderedMappings.add( mappedSuperclass );
mappedSuperClassTypeToPersistentClass.put( mappedSuperclassType, getEntityWorkedOn() );
}
/**
@ -169,7 +180,7 @@ class MetadataContext {
Iterator<Property> properties = ( Iterator<Property> ) safeMapping.getDeclaredPropertyIterator();
while ( properties.hasNext() ) {
final Property property = properties.next();
final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property, false );
final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property, true );
jpa2Mapping.getBuilder().addAttribute( attribute );
}
jpa2Mapping.lock();
@ -200,7 +211,7 @@ class MetadataContext {
final Property declaredIdentifierProperty = mappingType.getDeclaredIdentifierProperty();
if (declaredIdentifierProperty != null) {
jpaMappingType.getBuilder().applyIdAttribute(
attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty, false )
attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty, true )
);
}
}
@ -226,7 +237,7 @@ class MetadataContext {
final Property declaredVersion = mappingType.getDeclaredVersion();
if ( declaredVersion != null ) {
jpaMappingType.getBuilder().applyVersionAttribute(
attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion, false )
attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion, true )
);
}
}
@ -250,7 +261,7 @@ class MetadataContext {
@SuppressWarnings( "unchecked" )
Iterator<Property> properties = mappingType.getIdentifierMapper().getPropertyIterator();
while ( properties.hasNext() ) {
attributes.add( attributeFactory.buildIdAttribute( jpaMappingType, properties.next(), false ) );
attributes.add( attributeFactory.buildIdAttribute( jpaMappingType, properties.next(), true ) );
}
return attributes;
}
@ -288,4 +299,33 @@ class MetadataContext {
public MappedSuperclassTypeImpl<?> locateMappedSuperclassType(MappedSuperclass mappedSuperclass) {
return mappedSuperclassByMappedSuperclassMapping.get(mappedSuperclass);
}
public void pushEntityWorkedOn(PersistentClass persistentClass) {
stackOfPersistentClassesBeingProcessed.add(persistentClass);
}
public void popEntityWorkedOn(PersistentClass persistentClass) {
final PersistentClass stackTop = stackOfPersistentClassesBeingProcessed.remove(
stackOfPersistentClassesBeingProcessed.size() - 1
);
if (stackTop != persistentClass) {
throw new AssertionFailure( "Inconsistent popping: "
+ persistentClass.getEntityName() + " instead of " + stackTop.getEntityName() );
}
}
private PersistentClass getEntityWorkedOn() {
return stackOfPersistentClassesBeingProcessed.get(
stackOfPersistentClassesBeingProcessed.size() - 1
);
}
public PersistentClass getPersistentClassHostingProperties(MappedSuperclassTypeImpl<?> mappedSuperclassType) {
final PersistentClass persistentClass = mappedSuperClassTypeToPersistentClass.get( mappedSuperclassType );
if (persistentClass == null) {
throw new AssertionFailure( "Could not find PersistentClass for MappedSuperclassType: "
+ mappedSuperclassType.getJavaType() );
}
return persistentClass;
}
}

View File

@ -78,6 +78,8 @@ public class MetamodelImpl implements Metamodel, Serializable {
//TODO remove / reduce @SW scope
@SuppressWarnings( "unchecked" )
private static EntityTypeImpl<?> buildEntityType(PersistentClass persistentClass, MetadataContext context) {
final Class javaType = persistentClass.getMappedClass();
context.pushEntityWorkedOn(persistentClass);
final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass();
AbstractIdentifiableType<?> superType = superMappedSuperclass == null
? null
@ -89,7 +91,6 @@ public class MetamodelImpl implements Metamodel, Serializable {
? null
: locateOrBuildEntityType( superPersistentClass, context );
}
final Class javaType = persistentClass.getMappedClass();
EntityTypeImpl entityType = new EntityTypeImpl(
javaType,
superType,
@ -98,6 +99,7 @@ public class MetamodelImpl implements Metamodel, Serializable {
persistentClass.isVersioned()
);
context.registerEntityType( persistentClass, entityType );
context.popEntityWorkedOn(persistentClass);
return entityType;
}

View File

@ -169,6 +169,7 @@ public class MetadataTest extends TestCase {
assertNotNull( cat );
assertEquals( 7, cat.getAttributes().size() );
assertEquals( 1, cat.getDeclaredAttributes().size() );
ensureProperMember(cat.getDeclaredAttributes());
assertTrue( cat.hasVersionAttribute() );
assertEquals( "version", cat.getVersion(Long.class).getName() );
@ -179,6 +180,7 @@ public class MetadataTest extends TestCase {
MappedSuperclassType<Cattish> cattish = (MappedSuperclassType<Cattish>) cat.getSupertype();
assertEquals( 6, cattish.getAttributes().size() );
assertEquals( 1, cattish.getDeclaredAttributes().size() );
ensureProperMember(cattish.getDeclaredAttributes());
assertTrue( cattish.hasVersionAttribute() );
assertEquals( "version", cattish.getVersion(Long.class).getName() );
@ -189,6 +191,7 @@ public class MetadataTest extends TestCase {
EntityType<Feline> feline = (EntityType<Feline>) cattish.getSupertype();
assertEquals( 5, feline.getAttributes().size() );
assertEquals( 1, feline.getDeclaredAttributes().size() );
ensureProperMember(feline.getDeclaredAttributes());
assertTrue( feline.hasVersionAttribute() );
assertEquals( "version", feline.getVersion(Long.class).getName() );
@ -199,27 +202,44 @@ public class MetadataTest extends TestCase {
MappedSuperclassType<Animal> animal = (MappedSuperclassType<Animal>) feline.getSupertype();
assertEquals( 4, animal.getAttributes().size() );
assertEquals( 2, animal.getDeclaredAttributes().size() );
ensureProperMember(animal.getDeclaredAttributes());
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() );
final SingularAttribute<Animal, Long> id = animal.getDeclaredId( Long.class );
assertEquals( "id", id.getName() );
assertNotNull( id.getJavaMember() );
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() );
ensureProperMember(thing.getDeclaredAttributes());
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() );
final SingularAttribute<Thing, Long> version = thing.getDeclaredVersion( Long.class );
assertEquals( "version", version.getName() );
assertNotNull( version.getJavaMember() );
assertNull( thing.getId( Long.class ) );
assertNull( thing.getSupertype() );
}
private void ensureProperMember(Set<?> attributes) {
//we do not update the set so we are safe
@SuppressWarnings( "unchecked" )
final Set<Attribute<?, ?>> safeAttributes = ( Set<Attribute<?, ?>> ) attributes;
for (Attribute<?,?> attribute : safeAttributes ) {
final String name = attribute.getJavaMember().getName();
assertNotNull( attribute.getJavaMember() );
assertTrue( name.toLowerCase().endsWith( attribute.getName().toLowerCase() ) );
}
}
private void verifyDeclaredIdNotPresentAndIdPresent(IdentifiableType<?> type) {
assertEquals( "id", type.getId(Long.class).getName() );
try {