From 2dc911855b585017126266afa9371ce52f359852 Mon Sep 17 00:00:00 2001 From: Emmanuel Bernard Date: Fri, 30 Oct 2009 13:00:07 +0000 Subject: [PATCH] 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 --- .../ejb/metamodel/AttributeFactory.java | 66 ++++++++++++------- .../ejb/metamodel/MetadataContext.java | 48 ++++++++++++-- .../ejb/metamodel/MetamodelImpl.java | 4 +- .../ejb/test/metadata/MetadataTest.java | 24 ++++++- 4 files changed, 113 insertions(+), 29 deletions(-) diff --git a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java index 87d67cb114..a2197e2ff4 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java @@ -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 SingularAttributeImpl buildIdAttribute(AbstractManagedType ownerType, Property property, boolean getMember) { + public SingularAttributeImpl buildIdAttribute(AbstractIdentifiableType ownerType, Property property, boolean getMember) { final AttributeContext attrContext = getAttributeContext( property ); final Type attrType = getType( ownerType, attrContext.getElementTypeStatus(), attrContext.getElementValue(), getMember ); final Class 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 SingularAttributeImpl buildVersionAttribute(AbstractManagedType ownerType, Property property, boolean getMember) { + public SingularAttributeImpl buildVersionAttribute(AbstractIdentifiableType ownerType, Property property, boolean getMember) { final AttributeContext attrContext = getAttributeContext( property ); final Class javaType = property.getType().getReturnedClass(); final Type 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... diff --git a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java index c7acb73e1d..170c763875 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetadataContext.java @@ -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>(); //this list contains MappedSuperclass and EntityTypes ordered by superclass first private List orderedMappings = new ArrayList(); + /** + * Stack of PersistentClass being process. Last in the list is the highest in the stack. + * + */ + private List stackOfPersistentClassesBeingProcessed + = new ArrayList(); + private Map, PersistentClass> mappedSuperClassTypeToPersistentClass + = new HashMap, PersistentClass>(); public MetadataContext(SessionFactoryImplementor sessionFactory) { 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 properties = ( Iterator ) 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 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; + } } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java index 30c71c4d9d..6d4cb5761f 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/metamodel/MetamodelImpl.java @@ -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; } diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java index db44c8958a..2f1149f30f 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java @@ -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 = (MappedSuperclassType) 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 = (EntityType) 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 = (MappedSuperclassType) 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 id = animal.getDeclaredId( Long.class ); + assertEquals( "id", id.getName() ); + assertNotNull( id.getJavaMember() ); assertEquals( Type.PersistenceType.MAPPED_SUPERCLASS, animal.getSupertype().getPersistenceType() ); MappedSuperclassType thing = (MappedSuperclassType) animal.getSupertype(); assertEquals( 2, thing.getAttributes().size() ); assertEquals( 2, thing.getDeclaredAttributes().size() ); + ensureProperMember(thing.getDeclaredAttributes()); final SingularAttribute 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 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> safeAttributes = ( Set> ) 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 {