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 java.util.Iterator;
import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Type; import javax.persistence.metamodel.Type;
import javax.persistence.metamodel.IdentifiableType;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.type.EmbeddedComponentType; import org.hibernate.type.EmbeddedComponentType;
@ -38,6 +39,7 @@ import org.hibernate.mapping.Map;
import org.hibernate.mapping.OneToMany; import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value; import org.hibernate.mapping.Value;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityMetamodel;
/** /**
@ -144,7 +146,7 @@ public class AttributeFactory {
} }
@SuppressWarnings({ "unchecked" }) @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 AttributeContext attrContext = getAttributeContext( property );
final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember ); final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember );
final Class<Y> idJavaType = property.getType().getReturnedClass(); 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 // see below
// final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property ); // final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property );
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType ); final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
@ -191,12 +193,26 @@ public class AttributeFactory {
// .getEntityMetamodel(); // .getEntityMetamodel();
// } // }
// so we use the owner's java class to lookup the persister/entitymetamodel // so we use the owner's java class to lookup the persister/entitymetamodel
private EntityMetamodel getDeclarerEntityMetamodel(AbstractManagedType ownerType) { private EntityMetamodel getDeclarerEntityMetamodel(IdentifiableType<?> ownerType) {
return context.getSessionFactory() final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
.getEntityPersister( ownerType.getJavaType().getName() ) 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(); .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... // getting the owning PersistentClass from the Property is broken in certain cases with annotations...
// private Member determineStandardJavaMember(Property property) { // private Member determineStandardJavaMember(Property property) {
// final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property ); // final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property );
@ -206,33 +222,39 @@ public class AttributeFactory {
// return entityMetamodel.getTuplizer( EntityMode.POJO ).getGetter( index ).getMember(); // return entityMetamodel.getTuplizer( EntityMode.POJO ).getGetter( index ).getMember();
// } // }
// so we use the owner's java class to lookup the persister/entitymetamodel // so we use the owner's java class to lookup the persister/entitymetamodel
private Member determineStandardJavaMember(AbstractManagedType ownerType, Property property) { private Member determineStandardJavaMember(AbstractManagedType<?> ownerType, Property property) {
if ( Type.PersistenceType.EMBEDDABLE == ownerType.getPersistenceType() ) { final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl ) ownerType; if ( Type.PersistenceType.EMBEDDABLE == persistenceType ) {
EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl<?> ) ownerType;
return embeddableType.getHibernateType().getTuplizerMapping() return embeddableType.getHibernateType().getTuplizerMapping()
.getTuplizer( EntityMode.POJO ) .getTuplizer( EntityMode.POJO )
.getGetter( embeddableType.getHibernateType().getPropertyIndex( property.getName() ) ) .getGetter( embeddableType.getHibernateType().getPropertyIndex( property.getName() ) )
.getMember(); .getMember();
} }
else if ( Type.PersistenceType.ENTITY == ownerType.getPersistenceType() ) { else if ( Type.PersistenceType.ENTITY == persistenceType
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType ); || Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) {
final String propertyName = property.getName(); return determineStandardJavaMemberOutOfIdentifiableType( (IdentifiableType<?>) ownerType, property );
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 { 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" }) @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 AttributeContext attrContext = getAttributeContext( property );
final Class<Y> javaType = property.getType().getReturnedClass(); final Class<Y> javaType = property.getType().getReturnedClass();
final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember ); 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 ); final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
if ( ! property.getName().equals( entityMetamodel.getVersionProperty().getName() ) ) { if ( ! property.getName().equals( entityMetamodel.getVersionProperty().getName() ) ) {
// this should never happen, but to be safe... // this should never happen, but to be safe...

View File

@ -31,12 +31,14 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.SingularAttribute;
import javax.swing.*;
import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.annotations.common.AssertionFailure; import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.AnnotationException;
/** /**
* Defines a context for storing information during the building of the {@link MetamodelImpl}. * Defines a context for storing information during the building of the {@link MetamodelImpl}.
@ -67,6 +69,14 @@ class MetadataContext {
= new HashMap<MappedSuperclass,MappedSuperclassTypeImpl<?>>(); = new HashMap<MappedSuperclass,MappedSuperclassTypeImpl<?>>();
//this list contains MappedSuperclass and EntityTypes ordered by superclass first //this list contains MappedSuperclass and EntityTypes ordered by superclass first
private List<Object> orderedMappings = new ArrayList<Object>(); 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) { public MetadataContext(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory; this.sessionFactory = sessionFactory;
@ -104,6 +114,7 @@ class MetadataContext {
MappedSuperclassTypeImpl<?> mappedSuperclassType) { MappedSuperclassTypeImpl<?> mappedSuperclassType) {
mappedSuperclassByMappedSuperclassMapping.put( mappedSuperclass, mappedSuperclassType ); mappedSuperclassByMappedSuperclassMapping.put( mappedSuperclass, mappedSuperclassType );
orderedMappings.add( mappedSuperclass ); orderedMappings.add( mappedSuperclass );
mappedSuperClassTypeToPersistentClass.put( mappedSuperclassType, getEntityWorkedOn() );
} }
/** /**
@ -169,7 +180,7 @@ class MetadataContext {
Iterator<Property> properties = ( Iterator<Property> ) safeMapping.getDeclaredPropertyIterator(); Iterator<Property> properties = ( Iterator<Property> ) safeMapping.getDeclaredPropertyIterator();
while ( properties.hasNext() ) { while ( properties.hasNext() ) {
final Property property = properties.next(); 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.getBuilder().addAttribute( attribute );
} }
jpa2Mapping.lock(); jpa2Mapping.lock();
@ -200,7 +211,7 @@ class MetadataContext {
final Property declaredIdentifierProperty = mappingType.getDeclaredIdentifierProperty(); final Property declaredIdentifierProperty = mappingType.getDeclaredIdentifierProperty();
if (declaredIdentifierProperty != null) { if (declaredIdentifierProperty != null) {
jpaMappingType.getBuilder().applyIdAttribute( jpaMappingType.getBuilder().applyIdAttribute(
attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty, false ) attributeFactory.buildIdAttribute( jpaMappingType, declaredIdentifierProperty, true )
); );
} }
} }
@ -226,7 +237,7 @@ class MetadataContext {
final Property declaredVersion = mappingType.getDeclaredVersion(); final Property declaredVersion = mappingType.getDeclaredVersion();
if ( declaredVersion != null ) { if ( declaredVersion != null ) {
jpaMappingType.getBuilder().applyVersionAttribute( jpaMappingType.getBuilder().applyVersionAttribute(
attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion, false ) attributeFactory.buildVersionAttribute( jpaMappingType, declaredVersion, true )
); );
} }
} }
@ -250,7 +261,7 @@ class MetadataContext {
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
Iterator<Property> properties = mappingType.getIdentifierMapper().getPropertyIterator(); Iterator<Property> properties = mappingType.getIdentifierMapper().getPropertyIterator();
while ( properties.hasNext() ) { while ( properties.hasNext() ) {
attributes.add( attributeFactory.buildIdAttribute( jpaMappingType, properties.next(), false ) ); attributes.add( attributeFactory.buildIdAttribute( jpaMappingType, properties.next(), true ) );
} }
return attributes; return attributes;
} }
@ -288,4 +299,33 @@ class MetadataContext {
public MappedSuperclassTypeImpl<?> locateMappedSuperclassType(MappedSuperclass mappedSuperclass) { public MappedSuperclassTypeImpl<?> locateMappedSuperclassType(MappedSuperclass mappedSuperclass) {
return mappedSuperclassByMappedSuperclassMapping.get(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 //TODO remove / reduce @SW scope
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private static EntityTypeImpl<?> buildEntityType(PersistentClass persistentClass, MetadataContext context) { private static EntityTypeImpl<?> buildEntityType(PersistentClass persistentClass, MetadataContext context) {
final Class javaType = persistentClass.getMappedClass();
context.pushEntityWorkedOn(persistentClass);
final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass(); final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass();
AbstractIdentifiableType<?> superType = superMappedSuperclass == null AbstractIdentifiableType<?> superType = superMappedSuperclass == null
? null ? null
@ -89,7 +91,6 @@ public class MetamodelImpl implements Metamodel, Serializable {
? null ? null
: locateOrBuildEntityType( superPersistentClass, context ); : locateOrBuildEntityType( superPersistentClass, context );
} }
final Class javaType = persistentClass.getMappedClass();
EntityTypeImpl entityType = new EntityTypeImpl( EntityTypeImpl entityType = new EntityTypeImpl(
javaType, javaType,
superType, superType,
@ -98,6 +99,7 @@ public class MetamodelImpl implements Metamodel, Serializable {
persistentClass.isVersioned() persistentClass.isVersioned()
); );
context.registerEntityType( persistentClass, entityType ); context.registerEntityType( persistentClass, entityType );
context.popEntityWorkedOn(persistentClass);
return entityType; return entityType;
} }

View File

@ -169,6 +169,7 @@ public class MetadataTest extends TestCase {
assertNotNull( cat ); assertNotNull( cat );
assertEquals( 7, cat.getAttributes().size() ); assertEquals( 7, cat.getAttributes().size() );
assertEquals( 1, cat.getDeclaredAttributes().size() ); assertEquals( 1, cat.getDeclaredAttributes().size() );
ensureProperMember(cat.getDeclaredAttributes());
assertTrue( cat.hasVersionAttribute() ); assertTrue( cat.hasVersionAttribute() );
assertEquals( "version", cat.getVersion(Long.class).getName() ); assertEquals( "version", cat.getVersion(Long.class).getName() );
@ -179,6 +180,7 @@ public class MetadataTest extends TestCase {
MappedSuperclassType<Cattish> cattish = (MappedSuperclassType<Cattish>) cat.getSupertype(); MappedSuperclassType<Cattish> cattish = (MappedSuperclassType<Cattish>) cat.getSupertype();
assertEquals( 6, cattish.getAttributes().size() ); assertEquals( 6, cattish.getAttributes().size() );
assertEquals( 1, cattish.getDeclaredAttributes().size() ); assertEquals( 1, cattish.getDeclaredAttributes().size() );
ensureProperMember(cattish.getDeclaredAttributes());
assertTrue( cattish.hasVersionAttribute() ); assertTrue( cattish.hasVersionAttribute() );
assertEquals( "version", cattish.getVersion(Long.class).getName() ); assertEquals( "version", cattish.getVersion(Long.class).getName() );
@ -189,6 +191,7 @@ public class MetadataTest extends TestCase {
EntityType<Feline> feline = (EntityType<Feline>) cattish.getSupertype(); EntityType<Feline> feline = (EntityType<Feline>) cattish.getSupertype();
assertEquals( 5, feline.getAttributes().size() ); assertEquals( 5, feline.getAttributes().size() );
assertEquals( 1, feline.getDeclaredAttributes().size() ); assertEquals( 1, feline.getDeclaredAttributes().size() );
ensureProperMember(feline.getDeclaredAttributes());
assertTrue( feline.hasVersionAttribute() ); assertTrue( feline.hasVersionAttribute() );
assertEquals( "version", feline.getVersion(Long.class).getName() ); assertEquals( "version", feline.getVersion(Long.class).getName() );
@ -199,27 +202,44 @@ public class MetadataTest extends TestCase {
MappedSuperclassType<Animal> animal = (MappedSuperclassType<Animal>) feline.getSupertype(); MappedSuperclassType<Animal> animal = (MappedSuperclassType<Animal>) feline.getSupertype();
assertEquals( 4, animal.getAttributes().size() ); assertEquals( 4, animal.getAttributes().size() );
assertEquals( 2, animal.getDeclaredAttributes().size() ); assertEquals( 2, animal.getDeclaredAttributes().size() );
ensureProperMember(animal.getDeclaredAttributes());
assertTrue( animal.hasVersionAttribute() ); assertTrue( animal.hasVersionAttribute() );
assertEquals( "version", animal.getVersion(Long.class).getName() ); assertEquals( "version", animal.getVersion(Long.class).getName() );
verifyDeclaredVersiobnNotPresent( animal ); verifyDeclaredVersiobnNotPresent( animal );
assertEquals( "id", animal.getId(Long.class).getName() ); 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() ); assertEquals( Type.PersistenceType.MAPPED_SUPERCLASS, animal.getSupertype().getPersistenceType() );
MappedSuperclassType<Thing> thing = (MappedSuperclassType<Thing>) animal.getSupertype(); MappedSuperclassType<Thing> thing = (MappedSuperclassType<Thing>) animal.getSupertype();
assertEquals( 2, thing.getAttributes().size() ); assertEquals( 2, thing.getAttributes().size() );
assertEquals( 2, thing.getDeclaredAttributes().size() ); assertEquals( 2, thing.getDeclaredAttributes().size() );
ensureProperMember(thing.getDeclaredAttributes());
final SingularAttribute<Thing, Double> weight = thing.getDeclaredSingularAttribute( "weight", Double.class ); final SingularAttribute<Thing, Double> weight = thing.getDeclaredSingularAttribute( "weight", Double.class );
assertEquals( Double.class, weight.getJavaType() ); assertEquals( Double.class, weight.getJavaType() );
assertEquals( "version", thing.getVersion(Long.class).getName() ); 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.getId( Long.class ) );
assertNull( thing.getSupertype() ); 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) { private void verifyDeclaredIdNotPresentAndIdPresent(IdentifiableType<?> type) {
assertEquals( "id", type.getId(Long.class).getName() ); assertEquals( "id", type.getId(Long.class).getName() );
try { try {