Author: steve.ebersole(a)jboss.com
Date: 2009-12-21 18:34:10 -0500 (Mon, 21 Dec 2009)
New Revision: 18310
Added:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/JoinedManyToOneOwner.java
Modified:
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractManagedType.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/EmbeddedTypeTest.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Info.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java
Log:
HHH-4720 - Improve javax.persistence.metamodel.Attribute support
Modified:
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractManagedType.java
===================================================================
---
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractManagedType.java 2009-12-21
20:06:42 UTC (rev 18309)
+++
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AbstractManagedType.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -218,6 +218,9 @@
String name,
Class<Y> javaType) {
if ( attribute == null || ( javaType != null &&
!attribute.getBindableJavaType().equals( javaType ) ) ) {
+ if ( isPrimitiveVariant( attribute, javaType ) ) {
+ return;
+ }
throw new IllegalArgumentException(
attributeType + " named " + name
+ ( javaType != null ? " and of type " + javaType.getName() : ""
)
@@ -226,6 +229,38 @@
}
}
+ @SuppressWarnings({ "SimplifiableIfStatement" })
+ protected <Y> boolean isPrimitiveVariant(SingularAttribute<?,?> attribute,
Class<Y> javaType) {
+ if ( attribute == null ) {
+ return false;
+ }
+ Class declaredType = attribute.getBindableJavaType();
+
+ if ( declaredType.isPrimitive() ) {
+ return ( Boolean.class.equals( javaType ) && Boolean.TYPE.equals( declaredType
) )
+ || ( Character.class.equals( javaType ) && Character.TYPE.equals(
declaredType ) )
+ || ( Byte.class.equals( javaType ) && Byte.TYPE.equals( declaredType ) )
+ || ( Short.class.equals( javaType ) && Short.TYPE.equals( declaredType ) )
+ || ( Integer.class.equals( javaType ) && Integer.TYPE.equals( declaredType )
)
+ || ( Long.class.equals( javaType ) && Long.TYPE.equals( javaType ) )
+ || ( Float.class.equals( javaType ) && Float.TYPE.equals( declaredType ) )
+ || ( Double.class.equals( javaType ) && Double.TYPE.equals( declaredType )
);
+ }
+
+ if ( javaType.isPrimitive() ) {
+ return ( Boolean.class.equals( declaredType ) && Boolean.TYPE.equals( javaType
) )
+ || ( Character.class.equals( declaredType ) && Character.TYPE.equals(
javaType ) )
+ || ( Byte.class.equals( declaredType ) && Byte.TYPE.equals( javaType ) )
+ || ( Short.class.equals( declaredType ) && Short.TYPE.equals( javaType ) )
+ || ( Integer.class.equals( declaredType ) && Integer.TYPE.equals( javaType )
)
+ || ( Long.class.equals( declaredType ) && Long.TYPE.equals( javaType ) )
+ || ( Float.class.equals( declaredType ) && Float.TYPE.equals( javaType ) )
+ || ( Double.class.equals( declaredType ) && Double.TYPE.equals( javaType )
);
+ }
+
+ return false;
+ }
+
/**
* {@inheritDoc}
*/
Modified:
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java
===================================================================
---
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java 2009-12-21
20:06:42 UTC (rev 18309)
+++
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/metamodel/AttributeFactory.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -26,8 +26,12 @@
import java.lang.reflect.Member;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToOne;
import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.Type;
import javax.persistence.metamodel.IdentifiableType;
@@ -43,9 +47,14 @@
import org.hibernate.mapping.Value;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.type.EntityType;
/**
- * TODO : javadoc
+ * A factory for building {@link Attribute} instances. Exposes 3 main services for
building<ol>
+ * <li>{@link #buildAttribute normal attributes}</li>
+ * <li>{@link #buildIdAttribute id attributes}</li>
+ * <li>{@link #buildVersionAttribute version attributes}</li>
+ * <ol>
*
* @author Steve Ebersole
* @author Emmanuel Bernard
@@ -57,157 +66,169 @@
this.context = context;
}
+ /**
+ * Build a normal attribute.
+ *
+ * @param ownerType The descriptor of the attribute owner (aka declarer).
+ * @param property The Hibernate property descriptor for the attribute
+ * @param <X> The type of the owner
+ * @param <Y> The attribute type
+ * @return The built attribute descriptor
+ */
@SuppressWarnings({ "unchecked" })
public <X, Y> AttributeImplementor<X, Y>
buildAttribute(AbstractManagedType<X> ownerType, Property property) {
- AttributeContext attrContext = getAttributeContext( property );
- final AttributeImplementor<X, Y> attribute;
- if ( attrContext.isCollection() ) {
- attribute = buildPluralAttribute( ownerType, property, attrContext);
+ final AttributeContext<X> attributeContext = wrap( ownerType, property );
+ final AttributeMetadata<X,Y> attributeMetadata =
+ determineAttributeMetadata( attributeContext, NORMAL_MEMBER_RESOLVER );
+
+ if ( attributeMetadata.isPlural() ) {
+ return buildPluralAttribute( (PluralAttributeMetadata) attributeMetadata );
}
else {
- final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(),
attrContext.getElementValue() );
- attribute = new SingularAttributeImpl<X,Y>(
- property.getName(),
- property.getType().getReturnedClass(),
+ final SingularAttributeMetadata<X,Y> singularAttributeMetadata =
+ (SingularAttributeMetadata<X,Y>) attributeMetadata;
+ final Type<Y> metaModelType = getMetaModelType(
singularAttributeMetadata.getValueContext() );
+ return new SingularAttributeImpl<X,Y>(
+ attributeMetadata.getName(),
+ attributeMetadata.getJavaType(),
ownerType,
- determineStandardJavaMember( ownerType, property ),
+ attributeMetadata.getMember(),
false,
false,
property.isOptional(),
- attrType,
- attrContext.getElementAttributeType()
+ metaModelType,
+ attributeMetadata.getPersistentAttributeType()
);
}
- return attribute;
}
- @SuppressWarnings( "unchecked" )
- private <X, Y, V, K> AttributeImplementor<X, Y>
buildPluralAttribute(AbstractManagedType<X> ownerType, Property property,
AttributeContext attrContext) {
- AttributeImplementor<X, Y> attribute;
- final Type<V> attrType = getType( ownerType, attrContext.getElementTypeStatus(),
attrContext.getElementValue() );
- final Member member = determineStandardJavaMember( ownerType, property );
- final Class<Y> collectionClass = (Class<Y>) ( member instanceof Field
- ? ( ( Field ) member ).getType()
- : ( ( Method ) member ).getReturnType() );
- if ( java.util.Map.class.isAssignableFrom( collectionClass ) ) {
- final Type<K> keyType = getType( ownerType, attrContext.getKeyTypeStatus(),
attrContext.getKeyValue() );
- attribute = PluralAttributeImpl.create( ownerType, attrType, collectionClass, keyType
)
- .member( member )
- .property( property )
- .persistentAttributeType( attrContext.getElementAttributeType() )
- .build();
- }
- else {
- attribute = PluralAttributeImpl.create( ownerType, attrType, collectionClass, null )
- .member( member )
- .property( property )
- .persistentAttributeType( attrContext.getElementAttributeType() )
- .build();
- }
- return attribute;
- }
+ private <X> AttributeContext<X> wrap(final AbstractManagedType<X>
ownerType, final Property property) {
+ return new AttributeContext<X>() {
+ public AbstractManagedType<X> getOwnerType() {
+ return ownerType;
+ }
- private <X> Type<X> getType(AbstractManagedType owner,
AttributeContext.TypeStatus elementTypeStatus, Value value) {
- final org.hibernate.type.Type type = value.getType();
- switch ( elementTypeStatus ) {
- case BASIC:
- return buildBasicType( type );
- case EMBEDDABLE:
- return buildEmbeddableType( owner, value, type );
- case ENTITY:
- return buildEntityType( type );
- default:
- throw new AssertionFailure( "Unknown AttributeContext.TypeStatus: " +
elementTypeStatus );
-
- }
+ public Property getPropertyMapping() {
+ return property;
+ }
+ };
}
- @SuppressWarnings( "unchecked" )
- private <X> Type<X> buildBasicType(org.hibernate.type.Type type) {
- final Class<X> clazz = type.getReturnedClass();
- return new BasicTypeImpl<X>( clazz, Type.PersistenceType.BASIC );
- }
-
- @SuppressWarnings( "unchecked" )
- private <X> Type<X> buildEntityType(org.hibernate.type.Type type) {
- String entityName = ( (org.hibernate.type.EntityType) type
).getAssociatedEntityName();
- return ( Type<X> ) context.locateEntityType( entityName );
- }
-
- @SuppressWarnings( "unchecked" )
- private <X> Type<X> buildEmbeddableType(AbstractManagedType owner, Value
value, org.hibernate.type.Type type) {
- //build embedable type
- final Class<X> clazz = type.getReturnedClass();
- final EmbeddableTypeImpl<X> embeddableType = new EmbeddableTypeImpl<X>(
clazz, owner, (ComponentType) type );
- context.registerEmbeddedableType( embeddableType );
- final Component component = (Component) value;
- final Iterator<Property> subProperties = component.getPropertyIterator();
- while ( subProperties.hasNext() ) {
- final Property property = subProperties.next();
- embeddableType.getBuilder().addAttribute( buildAttribute( embeddableType, property)
);
- }
- embeddableType.lock();
- return embeddableType;
- }
-
+ /**
+ * Build the identifier attribute descriptor
+ *
+ * @param ownerType The descriptor of the attribute owner (aka declarer).
+ * @param property The Hibernate property descriptor for the identifier attribute
+ * @param <X> The type of the owner
+ * @param <Y> The attribute type
+ * @return The built attribute descriptor
+ */
@SuppressWarnings({ "unchecked" })
public <X, Y> SingularAttributeImpl<X, Y>
buildIdAttribute(AbstractIdentifiableType<X> ownerType, Property property) {
- final AttributeContext attrContext = getAttributeContext( property );
- final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(),
attrContext.getElementValue() );
- final Class<Y> idJavaType = property.getType().getReturnedClass();
+ final AttributeContext<X> attributeContext = wrap( ownerType, property );
+ final SingularAttributeMetadata<X,Y> attributeMetadata =
+ (SingularAttributeMetadata<X, Y>) determineAttributeMetadata( attributeContext,
IDENTIFIER_MEMBER_RESOLVER );
+ final Type<Y> metaModelType = getMetaModelType(
attributeMetadata.getValueContext() );
return new SingularAttributeImpl.Identifier(
property.getName(),
- idJavaType,
+ attributeMetadata.getJavaType(),
ownerType,
- determineIdentifierJavaMember( ownerType, property ),
- attrType,
- attrContext.getElementAttributeType()
+ attributeMetadata.getMember(),
+ metaModelType,
+ attributeMetadata.getPersistentAttributeType()
);
}
- private Member determineIdentifierJavaMember(IdentifiableType ownerType, Property
property) {
-// see below
-// final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property );
- final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( ownerType );
- if ( ! property.getName().equals( entityMetamodel.getIdentifierProperty().getName() ) )
{
- // this *should* indicate processing part of an IdClass...
- return determineVirtualIdentifierJavaMember( entityMetamodel, property );
- }
- return entityMetamodel.getTuplizer( EntityMode.POJO
).getIdentifierGetter().getMember();
+ /**
+ * Build the version attribute descriptor
+ *
+ * @param ownerType The descriptor of the attribute owner (aka declarer).
+ * @param property The Hibernate property descriptor for the version attribute
+ * @param <X> The type of the owner
+ * @param <Y> The attribute type
+ * @return The built attribute descriptor
+ */
+ @SuppressWarnings({ "unchecked" })
+ public <X, Y> SingularAttributeImpl<X, Y>
buildVersionAttribute(AbstractIdentifiableType<X> ownerType, Property property) {
+ final AttributeContext<X> attributeContext = wrap( ownerType, property );
+ final SingularAttributeMetadata<X,Y> attributeMetadata =
+ (SingularAttributeMetadata<X, Y>) determineAttributeMetadata( attributeContext,
VERSION_MEMBER_RESOLVER );
+ final Type<Y> metaModelType = getMetaModelType(
attributeMetadata.getValueContext() );
+ return new SingularAttributeImpl.Version(
+ property.getName(),
+ attributeMetadata.getJavaType(),
+ ownerType,
+ attributeMetadata.getMember(),
+ metaModelType,
+ attributeMetadata.getPersistentAttributeType()
+ );
}
- private Member determineVirtualIdentifierJavaMember(EntityMetamodel entityMetamodel,
Property property) {
- if ( ! entityMetamodel.getIdentifierProperty().isVirtual() ) {
- throw new IllegalArgumentException( "expecting IdClass mapping" );
+ @SuppressWarnings( "unchecked" )
+ private <X, Y, E, K> AttributeImplementor<X, Y>
buildPluralAttribute(PluralAttributeMetadata<X,Y,E> attributeMetadata) {
+ final Type<E> elementType = getMetaModelType(
attributeMetadata.getElementValueContext() );
+ if ( java.util.Map.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) {
+ final Type<K> keyType = getMetaModelType(
attributeMetadata.getMapKeyValueContext() );
+ return PluralAttributeImpl.create( attributeMetadata.getOwnerType(), elementType,
attributeMetadata.getJavaType(), keyType )
+ .member( attributeMetadata.getMember() )
+ .property( attributeMetadata.getPropertyMapping() )
+ .persistentAttributeType( attributeMetadata.getPersistentAttributeType() )
+ .build();
}
- org.hibernate.type.Type type = entityMetamodel.getIdentifierProperty().getType();
- if ( ! EmbeddedComponentType.class.isInstance( type ) ) {
- throw new IllegalArgumentException( "expecting IdClass mapping" );
+ else {
+ return PluralAttributeImpl.create( attributeMetadata.getOwnerType(), elementType,
attributeMetadata.getJavaType(), null )
+ .member( attributeMetadata.getMember() )
+ .property( attributeMetadata.getPropertyMapping() )
+ .persistentAttributeType( attributeMetadata.getPersistentAttributeType() )
+ .build();
}
- final EmbeddedComponentType componentType = (EmbeddedComponentType) type;
- return componentType.getTuplizerMapping()
- .getTuplizer( EntityMode.POJO )
- .getGetter( componentType.getPropertyIndex( property.getName() ) )
- .getMember();
}
-// getting the owning PersistentClass from the Property is broken in certain cases with
annotations...
-// private EntityMetamodel getDeclarerEntityMetamodel(Property property) {
-// return context.getSessionFactory()
-// .getEntityPersister( property.getPersistentClass().getEntityName() )
-// .getEntityMetamodel();
-// }
-// so we use the owner's java class to lookup the persister/entitymetamodel
+ @SuppressWarnings( "unchecked" )
+ private <Y> Type<Y> getMetaModelType(ValueContext typeContext) {
+ switch ( typeContext.getValueClassification() ) {
+ case BASIC: {
+ return new BasicTypeImpl<Y>(
+ typeContext.getBindableType(),
+ Type.PersistenceType.BASIC
+ );
+ }
+ case ENTITY: {
+ final org.hibernate.type.EntityType type = (EntityType)
typeContext.getValue().getType();
+ return (Type<Y>) context.locateEntityType( type.getAssociatedEntityName() );
+ }
+ case EMBEDDABLE: {
+ final Component component = (Component) typeContext.getValue();
+ final EmbeddableTypeImpl<Y> embeddableType = new EmbeddableTypeImpl<Y>(
+ typeContext.getBindableType(),
+ typeContext.getAttributeMetadata().getOwnerType(),
+ (ComponentType) typeContext.getValue().getType()
+ );
+ context.registerEmbeddedableType( embeddableType );
+ final Iterator<Property> subProperties = component.getPropertyIterator();
+ while ( subProperties.hasNext() ) {
+ final Property property = subProperties.next();
+ embeddableType.getBuilder().addAttribute( buildAttribute( embeddableType, property)
);
+ }
+ embeddableType.lock();
+ return embeddableType;
+ }
+ default: {
+ throw new AssertionFailure( "Unknown type : " +
typeContext.getValueClassification() );
+ }
+ }
+ }
+
private EntityMetamodel getDeclarerEntityMetamodel(IdentifiableType<?> ownerType)
{
- final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
- if ( persistenceType == Type.PersistenceType.ENTITY) {
+ 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 );
+ context.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl<?>)
ownerType );
return context.getSessionFactory()
.getEntityPersister( persistentClass.getClassName() )
.getEntityMetamodel();
@@ -217,243 +238,708 @@
}
}
-
-// getting the owning PersistentClass from the Property is broken in certain cases with
annotations...
-// private Member determineStandardJavaMember(Property property) {
-// final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( property );
-//
-// final String propertyName = property.getName();
-// final int index = entityMetamodel.getPropertyIndex( propertyName );
-// 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) {
- 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();
+ /**
+ * A contract for defining the meta information about a {@link Value}
+ */
+ private interface ValueContext {
+ /**
+ * Enum of the simplified types a value might be. These relate more to the Hibernate
classification
+ * then the JPA classification
+ */
+ enum ValueClassification {
+ EMBEDDABLE,
+ ENTITY,
+ BASIC
}
- else if ( Type.PersistenceType.ENTITY == persistenceType
- || Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) {
- return determineStandardJavaMemberOutOfIdentifiableType( (IdentifiableType<?>)
ownerType, property );
- }
- else {
- 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();
- }
- }
+ /**
+ * Retrieve the value itself
+ *
+ * @return The value
+ */
+ public Value getValue();
- @SuppressWarnings({ "unchecked" })
- public <X, Y> SingularAttributeImpl<X, Y>
buildVersionAttribute(AbstractIdentifiableType<X> ownerType, Property property) {
- final AttributeContext attrContext = getAttributeContext( property );
- final Class<Y> javaType = property.getType().getReturnedClass();
- final Type<Y> attrType = getType( ownerType, attrContext.getElementTypeStatus(),
attrContext.getElementValue() );
- return new SingularAttributeImpl.Version(
- property.getName(),
- javaType,
- ownerType,
- determineVersionJavaMember( ownerType, property ),
- attrType,
- attrContext.getElementAttributeType()
- );
- }
+ public Class getBindableType();
- 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...
- throw new IllegalArgumentException( "Given property did not match declared
version property" );
- }
- return entityMetamodel.getTuplizer( EntityMode.POJO ).getVersionGetter().getMember();
+ /**
+ * Retrieve the simplified value classification
+ *
+ * @return The value type
+ */
+ public ValueClassification getValueClassification();
+
+ /**
+ * Retrieve the metadata about the attribute from which this value comes
+ *
+ * @return The "containing" attribute metadata.
+ */
+ public AttributeMetadata getAttributeMetadata();
}
- private static class AttributeContext {
- private final Value elementValue;
- private final TypeStatus typeStatus;
- private final Class<?> collectionClass;
- private final Attribute.PersistentAttributeType attrType;
- private final Value keyValue;
- private final TypeStatus keyTypeStatus;
+ /**
+ * Basic contract for describing an attribute. The "description" is partially
in terms
+ * of JPA ({@link #getPersistentAttributeType} and {@link #getOwnerType}), partially in
+ * terms of Hibernate ({@link #getPropertyMapping}) and partially just in terms of the
java
+ * model itself ({@link #getName}, {@link #getMember} and {@link #getJavaType}).
+ *
+ * @param <X> The attribute owner type
+ * @param <Y> The attribute type.
+ */
+ private interface AttributeMetadata<X,Y> {
+ /**
+ * Retrieve the name of the attribute
+ *
+ * @return The attribute name
+ */
+ public String getName();
- enum TypeStatus {
- EMBEDDABLE,
- ENTITY,
- BASIC
- }
+ /**
+ * Retrieve the member defining the attribute
+ *
+ * @return The attribute member
+ */
+ public Member getMember();
- private AttributeContext(
- Value elementValue,
- TypeStatus elementTypeStatus,
- Attribute.PersistentAttributeType elementPAT,
- Class<?> collectionClass,
- Value keyValue,
- TypeStatus keyTypeStatus) {
- this.elementValue = elementValue;
- this.typeStatus = elementTypeStatus;
- this.collectionClass = collectionClass;
- this.attrType = elementPAT;
- this.keyValue = keyValue;
- this.keyTypeStatus = keyTypeStatus;
- }
+ /**
+ * Retrieve the attribute java type.
+ *
+ * @return The java type of the attribute.
+ */
+ public Class<Y> getJavaType();
- public Value getElementValue() {
- return elementValue;
- }
+ /**
+ * Get the JPA attribute type classification for this attribute.
+ *
+ * @return The JPA attribute type classification
+ */
+ public Attribute.PersistentAttributeType getPersistentAttributeType();
- public TypeStatus getElementTypeStatus() {
- return typeStatus;
- }
+ /**
+ * Retrieve the attribute owner's metamodel information
+ *
+ * @return The metamodel information for the attribute owner
+ */
+ public AbstractManagedType<X> getOwnerType();
- public boolean isCollection() {
- return collectionClass != null;
- }
+ /**
+ * Retrieve the Hibernate property mapping related to this attribute.
+ *
+ * @return The Hibernate property mapping
+ */
+ public Property getPropertyMapping();
- public Attribute.PersistentAttributeType getElementAttributeType() {
- return attrType;
- }
+ /**
+ * Is the attribute plural (a collection)?
+ *
+ * @return True if it is plural, false otherwise.
+ */
+ public boolean isPlural();
+ }
- public Value getKeyValue() {
- return keyValue;
- }
+ /**
+ * Attribute metadata contract for a non-plural attribute.
+ * @param <X> The owner type
+ * @param <Y> The attribute type
+ */
+ private interface SingularAttributeMetadata<X,Y> extends
AttributeMetadata<X,Y> {
+ /**
+ * Retrieve the value context for this attribute
+ *
+ * @return The attributes value context
+ */
+ public ValueContext getValueContext();
+ }
- public TypeStatus getKeyTypeStatus() {
- return keyTypeStatus;
- }
+ /**
+ * Attribute metadata contract for a plural attribute.
+ * @param <X> The owner type
+ * @param <Y> The attribute type (the collection type)
+ * @param <E> The collection element type
+ */
+ private interface PluralAttributeMetadata<X,Y,E> extends
AttributeMetadata<X,Y> {
+ /**
+ * Retrieve the JPA collection type classification for this attribute
+ *
+ * @return The JPA collection type classification
+ */
+ public PluralAttribute.CollectionType getAttributeCollectionType();
+
+ /**
+ * Retrieve the value context for the collection's elements.
+ *
+ * @return The value context for the collection's elements.
+ */
+ public ValueContext getElementValueContext();
+
+ /**
+ * Retrieve the value context for the collection's keys (if a map, null
otherwise).
+ *
+ * @return The value context for the collection's keys (if a map, null otherwise).
+ */
+ public ValueContext getMapKeyValueContext();
}
- private static AttributeContext getAttributeContext(Property property) {
+ /**
+ * Bundle's a Hibernate property mapping together with the JPA metamodel
information
+ * of the attribute owner.
+ *
+ * @param <X> The owner type.
+ */
+ private interface AttributeContext<X> {
+ /**
+ * Retrieve the attribute owner.
+ *
+ * @return The owner.
+ */
+ public AbstractManagedType<X> getOwnerType();
+
+ /**
+ * Retrieve the Hibernate property mapping.
+ *
+ * @return The Hibvernate property mapping.
+ */
+ public Property getPropertyMapping();
+ }
+
+ /**
+ * Contract for how we resolve the {@link Member} for a give attribute context.
+ */
+ private interface MemberResolver {
+ public Member resolveMember(AttributeContext attributeContext);
+ }
+
+ /**
+ * Here is most of the nuts and bolts of this factory, where we interpret the known JPA
metadata
+ * against the known Hibernate metadata and build a descriptor for the attribute.
+ *
+ * @param attributeContext The attribute to be described
+ * @param memberResolver Strategy for how to resolve the member defining the attribute.
+ * @param <X> The owner type
+ * @param <Y> The attribute type
+ *
+ * @return The attribute description
+ */
+ @SuppressWarnings({ "unchecked" })
+ private <X,Y> AttributeMetadata<X,Y> determineAttributeMetadata(
+ AttributeContext<X> attributeContext,
+ MemberResolver memberResolver) {
+ final Member member = memberResolver.resolveMember( attributeContext );
+ // TODO (steve->emmanuel) not so sure this is true any longer...
// FIXME the logical level for *To* is different from the Hibernate physical model.
// ie a @ManyToOne @AssocTable is a many-to-many for hibernate
// and a @OneToMany @AssocTable is a many-to-many for hibernate
// FIXME so basically Attribute.PersistentAttributeType is crap at the moment
- final Value value = property.getValue();
+ final Value value = attributeContext.getPropertyMapping().getValue();
final org.hibernate.type.Type type = value.getType();
if ( type.isAnyType() ) {
throw new UnsupportedOperationException( "any not supported yet" );
}
else if ( type.isAssociationType() ) {
- //collection or entity
- if ( type.isCollectionType() ) {
- //do collection
+ // collection or entity
+ if ( type.isEntityType() ) {
+ // entity
+ return new SingularAttributeMetadataImpl<X,Y>(
+ attributeContext.getPropertyMapping(),
+ attributeContext.getOwnerType(),
+ member,
+ determineSingularAssociationAttributeType( member )
+ );
+ }
+ else {
+ // collection
if ( value instanceof Collection ) {
- final Collection collValue = ( Collection ) value;
+ final Collection collValue = (Collection) value;
final Value elementValue = collValue.getElement();
final org.hibernate.type.Type elementType = elementValue.getType();
- final AttributeContext.TypeStatus elementTypeStatus;
- final Attribute.PersistentAttributeType elementPAT;
- final Class<?> collectionClass =
collValue.getCollectionType().getReturnedClass();
- final Value keyValue;
- final org.hibernate.type.Type keyType;
- final AttributeContext.TypeStatus keyTypeStatus;
+ // First, determine the type of the elements and use that to help determine the
+ // collection type)
+ final Attribute.PersistentAttributeType elementPersistentAttributeType;
+ final Attribute.PersistentAttributeType persistentAttributeType;
+ if ( elementType.isAnyType() ) {
+ throw new UnsupportedOperationException( "collection of any not supported
yet" );
+ }
+ final boolean isManyToMany = isManyToMany( member );
+ if ( elementValue instanceof Component ) {
+ elementPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED;
+ persistentAttributeType = Attribute.PersistentAttributeType.ELEMENT_COLLECTION;
+ }
+ else if ( elementType.isAssociationType() ) {
+ elementPersistentAttributeType = isManyToMany
+ ? Attribute.PersistentAttributeType.MANY_TO_MANY
+ : Attribute.PersistentAttributeType.ONE_TO_MANY;
+ persistentAttributeType = elementPersistentAttributeType;
+ }
+ else {
+ elementPersistentAttributeType = Attribute.PersistentAttributeType.BASIC;
+ persistentAttributeType = Attribute.PersistentAttributeType.ELEMENT_COLLECTION;
+ }
+
+ final Attribute.PersistentAttributeType keyPersistentAttributeType;
+
+ // Finally, we determine the type of the map key (if needed)
if ( value instanceof Map ) {
- keyValue = ( ( Map ) value ).getIndex();
- keyType = keyValue.getType();
+ final Value keyValue = ( ( Map ) value ).getIndex();
+ final org.hibernate.type.Type keyType = keyValue.getType();
+
+ if ( keyType.isAnyType() ) {
+ throw new UnsupportedOperationException( "collection of any not supported
yet" );
+ }
if ( keyValue instanceof Component ) {
- keyTypeStatus = AttributeContext.TypeStatus.EMBEDDABLE;
+ keyPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED;
}
- else if ( keyType.isAnyType() ) {
- throw new UnsupportedOperationException( "collection of any not supported
yet" );
- }
else if ( keyType.isAssociationType() ) {
- keyTypeStatus = AttributeContext.TypeStatus.ENTITY;
+ keyPersistentAttributeType = Attribute.PersistentAttributeType.MANY_TO_ONE;
}
else {
- keyTypeStatus = AttributeContext.TypeStatus.BASIC;
+ keyPersistentAttributeType = Attribute.PersistentAttributeType.BASIC;
}
}
else {
- keyValue = null;
- keyTypeStatus = null;
+ keyPersistentAttributeType = null;
}
+ return new PluralAttributeMetadataImpl(
+ attributeContext.getPropertyMapping(),
+ attributeContext.getOwnerType(),
+ member,
+ persistentAttributeType,
+ elementPersistentAttributeType,
+ keyPersistentAttributeType
+ );
+ }
+ else if ( value instanceof OneToMany ) {
+ // TODO : is this even possible??? Really OneToMany should be describing the
+ // element value within a o.h.mapping.Collection (see logic branch above)
+ throw new IllegalArgumentException( "HUH???" );
+// final boolean isManyToMany = isManyToMany( member );
+// //one to many with FK => entity
+// return new PluralAttributeMetadataImpl(
+// attributeContext.getPropertyMapping(),
+// attributeContext.getOwnerType(),
+// member,
+// isManyToMany
+// ? Attribute.PersistentAttributeType.MANY_TO_MANY
+// : Attribute.PersistentAttributeType.ONE_TO_MANY
+// value,
+// AttributeContext.TypeStatus.ENTITY,
+// Attribute.PersistentAttributeType.ONE_TO_MANY,
+// null, null, null
+// );
+ }
+ }
+ }
+ else if ( attributeContext.getPropertyMapping().isComposite() ) {
+ // component
+ return new SingularAttributeMetadataImpl<X,Y>(
+ attributeContext.getPropertyMapping(),
+ attributeContext.getOwnerType(),
+ member,
+ Attribute.PersistentAttributeType.EMBEDDED
+ );
+ }
+ else {
+ // basic type
+ return new SingularAttributeMetadataImpl<X,Y>(
+ attributeContext.getPropertyMapping(),
+ attributeContext.getOwnerType(),
+ member,
+ Attribute.PersistentAttributeType.BASIC
+ );
+ }
+ throw new UnsupportedOperationException( "oops, we are missing something: " +
attributeContext.getPropertyMapping() );
+ }
- if ( elementValue instanceof Component ) {
- //collection of components
- elementTypeStatus = AttributeContext.TypeStatus.EMBEDDABLE;
- elementPAT = Attribute.PersistentAttributeType.ELEMENT_COLLECTION;
+ public static Attribute.PersistentAttributeType
determineSingularAssociationAttributeType(Member member) {
+ if ( Field.class.isInstance( member ) ) {
+ return ( (Field) member ).getAnnotation( OneToOne.class ) != null
+ ? Attribute.PersistentAttributeType.ONE_TO_ONE
+ : Attribute.PersistentAttributeType.MANY_TO_ONE;
+ }
+ else {
+ return ( (Method) member ).getAnnotation( OneToOne.class ) != null
+ ? Attribute.PersistentAttributeType.ONE_TO_ONE
+ : Attribute.PersistentAttributeType.MANY_TO_ONE;
+ }
+ }
+
+ private abstract class BaseAttributeMetadata<X,Y> implements
AttributeMetadata<X,Y> {
+ private final Property propertyMapping;
+ private final AbstractManagedType<X> ownerType;
+ private final Member member;
+ private final Class<Y> javaType;
+ private final Attribute.PersistentAttributeType persistentAttributeType;
+
+ @SuppressWarnings({ "unchecked" })
+ protected BaseAttributeMetadata(
+ Property propertyMapping,
+ AbstractManagedType<X> ownerType,
+ Member member,
+ Attribute.PersistentAttributeType persistentAttributeType) {
+ this.propertyMapping = propertyMapping;
+ this.ownerType = ownerType;
+ this.member = member;
+ this.persistentAttributeType = persistentAttributeType;
+ final Class declaredType;
+ // we can support method or field members here. Is there really any other valid
type?
+ if ( Field.class.isInstance( member ) ) {
+ declaredType = ( (Field) member ).getType();
+ }
+ else if ( Method.class.isInstance( member ) ) {
+ declaredType = ( (Method) member ).getReturnType();
+ }
+ else {
+ throw new IllegalArgumentException( "Cannot determine java-type from given
member [" + member + "]" );
+ }
+ this.javaType = accountForPrimitiveTypes( declaredType );
+ }
+
+ public String getName() {
+ return propertyMapping.getName();
+ }
+
+ public Member getMember() {
+ return member;
+ }
+
+ public Class<Y> getJavaType() {
+ return javaType;
+ }
+
+ public Attribute.PersistentAttributeType getPersistentAttributeType() {
+ return persistentAttributeType;
+ }
+
+ public AbstractManagedType<X> getOwnerType() {
+ return ownerType;
+ }
+
+ public boolean isPlural() {
+ return propertyMapping.getType().isCollectionType();
+ }
+
+ public Property getPropertyMapping() {
+ return propertyMapping;
+ }
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ protected <Y> Class<Y> accountForPrimitiveTypes(Class<Y> declaredType)
{
+// if ( !declaredType.isPrimitive() ) {
+// return declaredType;
+// }
+//
+// if ( Boolean.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Boolean.class;
+// }
+// if ( Character.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Character.class;
+// }
+// if( Byte.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Byte.class;
+// }
+// if ( Short.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Short.class;
+// }
+// if ( Integer.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Integer.class;
+// }
+// if ( Long.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Long.class;
+// }
+// if ( Float.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Float.class;
+// }
+// if ( Double.TYPE.equals( declaredType ) ) {
+// return (Class<Y>) Double.class;
+// }
+//
+// throw new IllegalArgumentException( "Unexpected type [" + declaredType +
"]" );
+ // if the field is defined as int, return int not Integer...
+ return declaredType;
+ }
+
+ private class SingularAttributeMetadataImpl<X,Y>
+ extends BaseAttributeMetadata<X,Y>
+ implements SingularAttributeMetadata<X,Y> {
+ private final ValueContext valueContext;
+
+ private SingularAttributeMetadataImpl(
+ Property propertyMapping,
+ AbstractManagedType<X> ownerType,
+ Member member,
+ Attribute.PersistentAttributeType persistentAttributeType) {
+ super( propertyMapping, ownerType, member, persistentAttributeType );
+ valueContext = new ValueContext() {
+ public Value getValue() {
+ return getPropertyMapping().getValue();
+ }
+
+ public Class getBindableType() {
+ return getAttributeMetadata().getJavaType();
+ }
+
+ public ValueClassification getValueClassification() {
+ switch ( getPersistentAttributeType() ) {
+ case EMBEDDED: {
+ return ValueClassification.EMBEDDABLE;
+ }
+ case BASIC: {
+ return ValueClassification.BASIC;
+ }
+ default: {
+ return ValueClassification.ENTITY;
+ }
}
- else if ( elementType.isAnyType() ) {
- throw new UnsupportedOperationException( "collection of any not supported
yet" );
+ }
+
+ public AttributeMetadata getAttributeMetadata() {
+ return SingularAttributeMetadataImpl.this;
+ }
+ };
+ }
+
+ public ValueContext getValueContext() {
+ return valueContext;
+ }
+ }
+
+ private class PluralAttributeMetadataImpl<X,Y,E>
+ extends BaseAttributeMetadata<X,Y>
+ implements PluralAttributeMetadata<X,Y,E> {
+ private final PluralAttribute.CollectionType attributeCollectionType;
+ private final Attribute.PersistentAttributeType elementPersistentAttributeType;
+ private final Attribute.PersistentAttributeType keyPersistentAttributeType;
+ private final Class elementJavaType;
+ private final Class keyJavaType;
+ private final ValueContext elementValueContext;
+ private final ValueContext keyValueContext;
+
+ private PluralAttributeMetadataImpl(
+ Property propertyMapping,
+ AbstractManagedType<X> ownerType,
+ Member member,
+ Attribute.PersistentAttributeType persistentAttributeType,
+ Attribute.PersistentAttributeType elementPersistentAttributeType,
+ Attribute.PersistentAttributeType keyPersistentAttributeType) {
+ super( propertyMapping, ownerType, member, persistentAttributeType );
+ this.attributeCollectionType = determineCollectionType( getJavaType() );
+ this.elementPersistentAttributeType = elementPersistentAttributeType;
+ this.keyPersistentAttributeType = keyPersistentAttributeType;
+
+ ParameterizedType signatureType = getSignatureType( member );
+ if ( keyPersistentAttributeType == null ) {
+ elementJavaType = (Class) signatureType.getActualTypeArguments()[0];
+ keyJavaType = null;
+ }
+ else {
+ keyJavaType = (Class) signatureType.getActualTypeArguments()[0];
+ elementJavaType = (Class) signatureType.getActualTypeArguments()[1];
+ }
+
+ this.elementValueContext = new ValueContext() {
+ public Value getValue() {
+ return ( (Collection) getPropertyMapping().getValue() ).getElement();
+ }
+
+ public Class getBindableType() {
+ return elementJavaType;
+ }
+
+ public ValueClassification getValueClassification() {
+ switch ( PluralAttributeMetadataImpl.this.elementPersistentAttributeType ) {
+ case EMBEDDED: {
+ return ValueClassification.EMBEDDABLE;
+ }
+ case BASIC: {
+ return ValueClassification.BASIC;
+ }
+ default: {
+ return ValueClassification.ENTITY;
+ }
}
- else if ( elementType.isAssociationType() ) {
- //collection of entity
- elementTypeStatus = AttributeContext.TypeStatus.ENTITY;
- elementPAT = Attribute.PersistentAttributeType.MANY_TO_MANY;
- }
- else {
- //collection of basic type
- elementTypeStatus = AttributeContext.TypeStatus.BASIC;
- elementPAT = Attribute.PersistentAttributeType.ELEMENT_COLLECTION;
- }
- return new AttributeContext(
- elementValue,
- elementTypeStatus,
- elementPAT,
- collectionClass,
- keyValue,
- keyTypeStatus
- );
}
- else if ( value instanceof OneToMany ) {
- //one to many with FK => entity
- return new AttributeContext(
- value,
- AttributeContext.TypeStatus.ENTITY,
- Attribute.PersistentAttributeType.ONE_TO_MANY,
- null, null, null
- );
+
+ public AttributeMetadata getAttributeMetadata() {
+ return PluralAttributeMetadataImpl.this;
}
+ };
+ // interpret the key, if one
+ if ( keyPersistentAttributeType != null ) {
+ this.keyValueContext = new ValueContext() {
+ public Value getValue() {
+ return ( (Map) getPropertyMapping().getValue() ).getIndex();
+ }
+
+ public Class getBindableType() {
+ return keyJavaType;
+ }
+
+ public ValueClassification getValueClassification() {
+ switch ( PluralAttributeMetadataImpl.this.keyPersistentAttributeType ) {
+ case EMBEDDED: {
+ return ValueClassification.EMBEDDABLE;
+ }
+ case BASIC: {
+ return ValueClassification.BASIC;
+ }
+ default: {
+ return ValueClassification.ENTITY;
+ }
+ }
+ }
+
+ public AttributeMetadata getAttributeMetadata() {
+ return PluralAttributeMetadataImpl.this;
+ }
+ };
}
else {
- //ToOne association
- return new AttributeContext(
- value,
- AttributeContext.TypeStatus.ENTITY,
- Attribute.PersistentAttributeType.MANY_TO_MANY,
- //FIXME how to differentiate the logical many to one from the one to one (not
physical level)
- null,
- null,
- null
- );
+ keyValueContext = null;
}
}
- else if ( property.isComposite() ) {
- //embeddable
- return new AttributeContext(
- value,
- AttributeContext.TypeStatus.EMBEDDABLE,
- Attribute.PersistentAttributeType.EMBEDDED,
- null, null, null
- );
+ public ValueContext getElementValueContext() {
+ return elementValueContext;
}
+
+ public PluralAttribute.CollectionType getAttributeCollectionType() {
+ return attributeCollectionType;
+ }
+
+ public ValueContext getMapKeyValueContext() {
+ return keyValueContext;
+ }
+ }
+
+ public static ParameterizedType getSignatureType(Member member) {
+ return (ParameterizedType) ( Field.class.isInstance( member )
+ ? ( (Field) member ).getGenericType()
+ : ( (Method) member ).getGenericReturnType());
+ }
+
+ public static PluralAttribute.CollectionType determineCollectionType(Class javaType) {
+ if ( java.util.List.class.isAssignableFrom( javaType ) ) {
+ return PluralAttribute.CollectionType.LIST;
+ }
+ else if ( java.util.Set.class.isAssignableFrom( javaType ) ) {
+ return PluralAttribute.CollectionType.SET;
+ }
+ else if ( java.util.Map.class.isAssignableFrom( javaType ) ) {
+ return PluralAttribute.CollectionType.MAP;
+ }
+ else if ( java.util.Collection.class.isAssignableFrom( javaType ) ) {
+ return PluralAttribute.CollectionType.COLLECTION;
+ }
else {
- //basic type
- return new AttributeContext(
- value,
- AttributeContext.TypeStatus.BASIC,
- Attribute.PersistentAttributeType.BASIC,
- null, null, null
- );
+ throw new IllegalArgumentException( "Expecting collection type [" +
javaType.getName() + "]" );
}
- throw new UnsupportedOperationException( "oops, we are missing something: " +
property.toString() );
}
+ public static boolean isManyToMany(Member member) {
+ return Field.class.isInstance( member )
+ ? ( (Field) member ).getAnnotation( ManyToMany.class ) != null
+ : ( (Method) member ).getAnnotation( ManyToMany.class ) != null;
+ }
+ private final MemberResolver EMBEDDED_MEMBER_RESOLVER = new MemberResolver() {
+ /**
+ * {@inheritDoc}
+ */
+ public Member resolveMember(AttributeContext attributeContext) {
+ final EmbeddableTypeImpl embeddableType = ( EmbeddableTypeImpl<?> )
attributeContext.getOwnerType();
+ final String attributeName = attributeContext.getPropertyMapping().getName();
+ return embeddableType.getHibernateType().getTuplizerMapping()
+ .getTuplizer( EntityMode.POJO )
+ .getGetter( embeddableType.getHibernateType().getPropertyIndex( attributeName ) )
+ .getMember();
+ }
+ };
+
+
+ private final MemberResolver VIRTUAL_IDENTIFIER_MEMBER_RESOLVER = new MemberResolver()
{
+ /**
+ * {@inheritDoc}
+ */
+ public Member resolveMember(AttributeContext attributeContext) {
+ final IdentifiableType identifiableType = (IdentifiableType)
attributeContext.getOwnerType();
+ final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType
);
+ if ( ! entityMetamodel.getIdentifierProperty().isVirtual() ) {
+ throw new IllegalArgumentException( "expecting IdClass mapping" );
+ }
+ org.hibernate.type.Type type = entityMetamodel.getIdentifierProperty().getType();
+ if ( ! EmbeddedComponentType.class.isInstance( type ) ) {
+ throw new IllegalArgumentException( "expecting IdClass mapping" );
+ }
+
+ final EmbeddedComponentType componentType = (EmbeddedComponentType) type;
+ final String attributeName = attributeContext.getPropertyMapping().getName();
+ return componentType.getTuplizerMapping()
+ .getTuplizer( EntityMode.POJO )
+ .getGetter( componentType.getPropertyIndex( attributeName ) )
+ .getMember();
+ }
+ };
+
+ /**
+ * A {@link Member} resolver for normal attributes.
+ */
+ private final MemberResolver NORMAL_MEMBER_RESOLVER = new MemberResolver() {
+ /**
+ * {@inheritDoc}
+ */
+ public Member resolveMember(AttributeContext attributeContext) {
+ final AbstractManagedType ownerType = attributeContext.getOwnerType();
+ final Property property = attributeContext.getPropertyMapping();
+ final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
+ if ( Type.PersistenceType.EMBEDDABLE == persistenceType ) {
+ return EMBEDDED_MEMBER_RESOLVER.resolveMember( attributeContext );
+ }
+ else if ( Type.PersistenceType.ENTITY == persistenceType
+ || Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) {
+ final IdentifiableType identifiableType = (IdentifiableType) ownerType;
+ final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType
);
+ 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 VIRTUAL_IDENTIFIER_MEMBER_RESOLVER.resolveMember( attributeContext );
+ }
+ else {
+ return entityMetamodel.getTuplizer( EntityMode.POJO )
+ .getGetter( index )
+ .getMember();
+ }
+ }
+ else {
+ throw new IllegalArgumentException( "Unexpected owner type : " +
persistenceType );
+ }
+ }
+ };
+
+ private final MemberResolver IDENTIFIER_MEMBER_RESOLVER = new MemberResolver() {
+ public Member resolveMember(AttributeContext attributeContext) {
+ final IdentifiableType identifiableType = (IdentifiableType)
attributeContext.getOwnerType();
+ final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType
);
+ if ( ! attributeContext.getPropertyMapping().getName()
+ .equals( entityMetamodel.getIdentifierProperty().getName() ) ) {
+ // this *should* indicate processing part of an IdClass...
+ return VIRTUAL_IDENTIFIER_MEMBER_RESOLVER.resolveMember( attributeContext );
+ }
+ return entityMetamodel.getTuplizer( EntityMode.POJO
).getIdentifierGetter().getMember();
+ }
+ };
+
+ private final MemberResolver VERSION_MEMBER_RESOLVER = new MemberResolver() {
+ public Member resolveMember(AttributeContext attributeContext) {
+ final IdentifiableType identifiableType = (IdentifiableType)
attributeContext.getOwnerType();
+ final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType
);
+ final String versionPropertyName = attributeContext.getPropertyMapping().getName();
+ if ( ! versionPropertyName.equals( entityMetamodel.getVersionProperty().getName() ) )
{
+ // this should never happen, but to be safe...
+ throw new IllegalArgumentException( "Given property did not match declared
version property" );
+ }
+ return entityMetamodel.getTuplizer( EntityMode.POJO ).getVersionGetter().getMember();
+ }
+ };
}
Modified:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/EmbeddedTypeTest.java
===================================================================
---
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/EmbeddedTypeTest.java 2009-12-21
20:06:42 UTC (rev 18309)
+++
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/EmbeddedTypeTest.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -41,7 +41,7 @@
};
}
- public void testSingularAttributeAccessByNameFailureExpected() {
+ public void testSingularAttributeAccessByName() {
// HHH-4702
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Info.java
===================================================================
---
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Info.java 2009-12-21
20:06:42 UTC (rev 18309)
+++
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Info.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -26,6 +26,7 @@
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
+import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@@ -112,7 +113,7 @@
zip = v;
}
- @OneToOne(mappedBy = "info")
+ @OneToOne(mappedBy = "info") @JoinTable
public Spouse getSpouse() {
return spouse;
}
Added:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/JoinedManyToOneOwner.java
===================================================================
---
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/JoinedManyToOneOwner.java
(rev 0)
+++
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/JoinedManyToOneOwner.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -0,0 +1,60 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.ejb.test.metadata;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToOne;
+
+/**
+ * An entity that defines a @ManyToOne @JoinTable
+ * <p/>
+ * See HHH-4720 for details
+ *
+ * @author Steve Ebersole
+ */
+@Entity
+public class JoinedManyToOneOwner {
+ private Long id;
+ private House house;
+
+ @Id
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @ManyToOne @JoinTable( name = "SOME_OTHER_TABLE" )
+ public House getHouse() {
+ return house;
+ }
+
+ public void setHouse(House house) {
+ this.house = house;
+ }
+}
Modified:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java
===================================================================
---
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java 2009-12-21
20:06:42 UTC (rev 18309)
+++
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/MetadataTest.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -36,7 +36,6 @@
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,11 +52,23 @@
assertNotNull( entityType );
}
+ public void testLogicalManyToOne() throws Exception {
+ final EntityType<JoinedManyToOneOwner> entityType =
factory.getMetamodel().entity( JoinedManyToOneOwner.class );
+ final SingularAttribute attr = entityType.getDeclaredSingularAttribute(
"house" );
+ assertEquals( Attribute.PersistentAttributeType.MANY_TO_ONE,
attr.getPersistentAttributeType() );
+ assertEquals( House.class, attr.getBindableJavaType() );
+ final EntityType<House> houseType = factory.getMetamodel().entity( House.class
);
+ assertEquals( houseType.getBindableJavaType(), attr.getBindableJavaType() );
+ }
+
public void testEntity() throws Exception {
final EntityType<Fridge> fridgeType = factory.getMetamodel().entity( Fridge.class
);
assertEquals( Fridge.class, fridgeType.getBindableJavaType() );
assertEquals( Bindable.BindableType.ENTITY_TYPE, fridgeType.getBindableType() );
- assertNotNull( fridgeType.getDeclaredSingularAttribute( "temperature",
Integer.class ) );
+ SingularAttribute<Fridge,Integer> wrapped =
fridgeType.getDeclaredSingularAttribute( "temperature", Integer.class );
+ assertNotNull( wrapped );
+ SingularAttribute<Fridge,Integer> primitive =
fridgeType.getDeclaredSingularAttribute( "temperature", int.class );
+ assertNotNull( primitive );
assertNotNull( fridgeType.getDeclaredSingularAttribute( "temperature" ) );
assertNotNull( fridgeType.getDeclaredAttribute( "temperature" ) );
final SingularAttribute<Fridge, Long> id = fridgeType.getDeclaredId( Long.class
);
@@ -112,19 +123,22 @@
"temperature",
Integer.class
);
- assertEquals( Integer.class, singularAttribute.getBindableJavaType() );
+// assertEquals( Integer.class, singularAttribute.getBindableJavaType() );
+// assertEquals( Integer.class, singularAttribute.getType().getJavaType() );
+ assertEquals( int.class, singularAttribute.getBindableJavaType() );
+ assertEquals( int.class, singularAttribute.getType().getJavaType() );
assertEquals( Bindable.BindableType.SINGULAR_ATTRIBUTE,
singularAttribute.getBindableType() );
assertFalse( singularAttribute.isId() );
assertFalse( singularAttribute.isOptional() );
assertFalse( entityType.getDeclaredSingularAttribute( "brand", String.class
).isOptional() );
- assertEquals( Integer.class, singularAttribute.getType().getJavaType() );
assertEquals( Type.PersistenceType.BASIC,
singularAttribute.getType().getPersistenceType() );
final Attribute<? super Fridge, ?> attribute = entityType.getDeclaredAttribute(
"temperature" );
assertNotNull( attribute );
assertEquals( "temperature", attribute.getName() );
assertEquals( Fridge.class, attribute.getDeclaringType().getJavaType() );
assertEquals( Attribute.PersistentAttributeType.BASIC,
attribute.getPersistentAttributeType() );
- assertEquals( Integer.class, attribute.getJavaType() );
+// assertEquals( Integer.class, attribute.getJavaType() );
+ assertEquals( int.class, attribute.getJavaType() );
assertFalse( attribute.isAssociation() );
assertFalse( attribute.isCollection() );
@@ -306,7 +320,8 @@
Cattish.class,
Feline.class,
Garden.class,
- Flower.class
+ Flower.class,
+ JoinedManyToOneOwner.class
};
}
Modified:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java
===================================================================
---
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java 2009-12-21
20:06:42 UTC (rev 18309)
+++
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/metadata/StaticMetadataTest.java 2009-12-21
23:34:10 UTC (rev 18310)
@@ -53,7 +53,8 @@
assertTrue( Animal_.id.isId() );
assertEquals( Long.class, Animal_.id.getJavaType() );
assertNotNull( Animal_.legNbr );
- assertEquals( Integer.class, Animal_.legNbr.getJavaType() );
+// assertEquals( Integer.class, Animal_.legNbr.getJavaType() );
+ assertEquals( int.class, Animal_.legNbr.getJavaType() );
// Cat (hierarchy)
assertNotNull( Cat_.id );
@@ -72,9 +73,12 @@
assertNotNull( Fridge_.temperature );
assertEquals( "temperature", Fridge_.temperature.getName() );
assertEquals( Fridge.class, Fridge_.temperature.getDeclaringType().getJavaType() );
- assertEquals( Integer.class, Fridge_.temperature.getJavaType() );
- assertEquals( Integer.class, Fridge_.temperature.getBindableJavaType() );
- assertEquals( Integer.class, Fridge_.temperature.getType().getJavaType() );
+// assertEquals( Integer.class, Fridge_.temperature.getJavaType() );
+// assertEquals( Integer.class, Fridge_.temperature.getBindableJavaType() );
+// assertEquals( Integer.class, Fridge_.temperature.getType().getJavaType() );
+ assertEquals( int.class, Fridge_.temperature.getJavaType() );
+ assertEquals( int.class, Fridge_.temperature.getBindableJavaType() );
+ assertEquals( int.class, Fridge_.temperature.getType().getJavaType() );
assertEquals( Bindable.BindableType.SINGULAR_ATTRIBUTE,
Fridge_.temperature.getBindableType() );
assertEquals( Type.PersistenceType.BASIC,
Fridge_.temperature.getType().getPersistenceType() );
assertEquals( Attribute.PersistentAttributeType.BASIC,
Fridge_.temperature.getPersistentAttributeType() );