HHH-4533 Populate the JPA 2 metamodel with the new mapping.MappedSuperclass metadata

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17879 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Emmanuel Bernard 2009-10-29 18:57:24 +00:00
parent fceda002d0
commit fb9bdb7f38
20 changed files with 658 additions and 69 deletions

View File

@ -775,6 +775,21 @@ public final class AnnotationBinder {
);
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" );
@ -1463,6 +1478,20 @@ public final class AnnotationBinder {
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" );
rootClass.setOptimisticLockMode( Versioning.OPTIMISTIC_LOCK_VERSION );
@ -2202,6 +2231,19 @@ public final class AnnotationBinder {
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 );
}
}
}

View File

@ -60,6 +60,7 @@ import org.hibernate.mapping.SimpleValue;
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 @@ public class BinderHelper {
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;
}
}

View File

@ -130,7 +130,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
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) {

View File

@ -12,20 +12,27 @@ import java.util.List;
*
* 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 @@ public class MappedSuperclass {
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 @@ public class MappedSuperclass {
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 class MappedSuperclass {
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;
}
}

View File

@ -98,6 +98,7 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
protected int optimisticLockMode;
private MappedSuperclass superMappedSuperclass;
private Component declaredIdentifierMapper;
public String getClassName() {
return className;
@ -236,8 +237,10 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
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 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
return identifierMapper;
}
public Component getDeclaredIdentifierMapper() {
return declaredIdentifierMapper;
}
public void setDeclaredIdentifierMapper(Component declaredIdentifierMapper) {
this.declaredIdentifierMapper = declaredIdentifierMapper;
}
public boolean hasIdentifierMapper() {
return identifierMapper != null;
}

View File

@ -61,6 +61,8 @@ public class RootClass extends PersistentClass implements TableOwner {
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 class RootClass extends PersistentClass implements TableOwner {
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 class RootClass extends PersistentClass implements TableOwner {
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 class RootClass extends PersistentClass implements TableOwner {
public void setIdentifierProperty(Property identifierProperty) {
this.identifierProperty = identifierProperty;
identifierProperty.setPersistentClass(this);
}
public void setMutable(boolean mutable) {

View File

@ -70,6 +70,11 @@ public class Subclass extends PersistentClass {
public Property getIdentifierProperty() {
return getSuperclass().getIdentifierProperty();
}
public Property getDeclaredIdentifierProperty() {
return null;
}
public KeyValue getIdentifier() {
return getSuperclass().getIdentifier();
}
@ -143,6 +148,10 @@ public class Subclass extends PersistentClass {
return getSuperclass().getVersion();
}
public Property getDeclaredVersion() {
return null;
}
public boolean hasEmbeddedIdentifier() {
return getSuperclass().hasEmbeddedIdentifier();
}

View File

@ -96,9 +96,21 @@ public abstract class AbstractIdentifiableType<X>
throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() );
}
}
else {
//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 @@ public abstract class AbstractIdentifiableType<X>
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) {

View File

@ -54,19 +54,19 @@ public class AttributeFactory {
}
@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 @@ public class AttributeFactory {
}
@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 @@ public class AttributeFactory {
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 @@ public class AttributeFactory {
}
@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 @@ public class AttributeFactory {
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 @@ public class AttributeFactory {
}
@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 @@ public class AttributeFactory {
// 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 {

View File

@ -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;
}
}

View File

@ -25,16 +25,18 @@ import java.util.Collections;
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 @@ class MetadataContext {
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 @@ class MetadataContext {
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,50 +141,116 @@ class MetadataContext {
@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();
//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( entry.getValue(), property );
entry.getValue().getBuilder().addAttribute( attribute );
final Attribute attribute = attributeFactory.buildAttribute( jpa2Mapping, property, true );
jpa2Mapping.getBuilder().addAttribute( attribute );
}
jpa2Mapping.lock();
populateStaticMetamodel( jpa2Mapping );
}
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() );
}
entry.getValue().lock();
populateStaticMetamodel( entry.getValue() );
}
}
private <X> void applyIdMetadata(PersistentClass persistentClass, EntityTypeImpl<X> jpaEntityType) {
if ( persistentClass.hasIdentifierProperty() ) {
final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty();
if (declaredIdentifierProperty != null) {
jpaEntityType.getBuilder().applyIdAttribute(
attributeFactory.buildIdAttribute( jpaEntityType, persistentClass.getIdentifierProperty() )
attributeFactory.buildIdAttribute( jpaEntityType, declaredIdentifierProperty, true )
);
}
}
else {
jpaEntityType.getBuilder().applyIdClassAttributes( buildIdClassAttributes( jpaEntityType, persistentClass ) );
}
}
private <X> void applyVersionAttribute(PersistentClass persistentClass, EntityTypeImpl<X> jpaEntityType) {
if ( ! persistentClass.isVersioned() ) {
return;
}
jpaEntityType.getBuilder().applyVersionAttribute(
attributeFactory.buildVerisonAttribute( jpaEntityType, persistentClass.getVersion() )
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) {
final Property declaredVersion = persistentClass.getDeclaredVersion();
if (declaredVersion != null) {
jpaEntityType.getBuilder().applyVersionAttribute(
attributeFactory.buildVersionAttribute( jpaEntityType, declaredVersion, true )
);
}
}
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 )
);
}
}
@SuppressWarnings( "unchecked")
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;
}
@ -206,4 +285,7 @@ class MetadataContext {
// push the attributes on to the metamodel class...
}
public MappedSuperclassTypeImpl<?> locateMappedSuperclassType(MappedSuperclass mappedSuperclass) {
return mappedSuperclassByMappedSuperclassMapping.get(mappedSuperclass);
}
}

View File

@ -32,6 +32,7 @@ import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.EmbeddableType;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.engine.SessionFactoryImplementor;
/**
@ -46,7 +47,7 @@ public class MetamodelImpl implements Metamodel, Serializable {
/**
* 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 @@ public class MetamodelImpl implements Metamodel, Serializable {
return entityType;
}
@SuppressWarnings({ "unchecked" })
//TODO remove / reduce @SW scope
@SuppressWarnings( "unchecked" )
private static EntityTypeImpl<?> buildEntityType(PersistentClass persistentClass, MetadataContext context) {
final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass();
AbstractIdentifiableType<?> superType = superMappedSuperclass == null
? null
: locateOrBuildMappedsuperclassType( superMappedSuperclass, context );
//no mappedSuperclass, check for a super entity
if (superType == null) {
final PersistentClass superPersistentClass = persistentClass.getSuperclass();
final EntityTypeImpl superEntityType = superPersistentClass == null
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 @@ public class MetamodelImpl implements Metamodel, Serializable {
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.
*

View File

@ -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
*/
@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;
}
}

View File

@ -0,0 +1,19 @@
package org.hibernate.ejb.test.metadata;
import javax.persistence.Entity;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Cat extends Cattish {
private String nickname;
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
}

View File

@ -0,0 +1,19 @@
package org.hibernate.ejb.test.metadata;
import javax.persistence.MappedSuperclass;
/**
* @author Emmanuel Bernard
*/
@MappedSuperclass
public class Cattish extends Feline {
private long hoursOfSleep;
public long getHoursOfSleep() {
return hoursOfSleep;
}
public void setHoursOfSleep(long hoursOfSleep) {
this.hoursOfSleep = hoursOfSleep;
}
}

View File

@ -0,0 +1,19 @@
package org.hibernate.ejb.test.metadata;
import javax.persistence.Entity;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Dog extends Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,19 @@
package org.hibernate.ejb.test.metadata;
import javax.persistence.Entity;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Feline extends Animal {
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

View File

@ -12,6 +12,9 @@ import javax.persistence.metamodel.SetAttribute;
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 @@ public class MetadataTest extends TestCase {
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 @@ public class MetadataTest extends TestCase {
final SingularAttribute<? super FoodItem, Long> version = foodType.getVersion( Long.class );
assertNotNull( version );
assertTrue( version.isVersion() );
assertEquals( 3, foodType.getDeclaredAttributes().size() );
}
@ -158,6 +164,83 @@ public class MetadataTest extends TestCase {
assertEquals( PluralAttribute.CollectionType.LIST, roomsBySize.getCollectionType() );
}
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
@ -166,7 +249,11 @@ public class MetadataTest extends TestCase {
Fridge.class,
FoodItem.class,
Person.class,
House.class
House.class,
Dog.class,
Cat.class,
Cattish.class,
Feline.class
};
}

View File

@ -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;
}
}

View File

@ -0,0 +1,30 @@
package org.hibernate.ejb.test.metadata;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
/**
* @author Emmanuel Bernard
*/
@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;
}
}