[hibernate-commits] Hibernate SVN: r18692 - in core/trunk: annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a and 3 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Feb 4 12:54:06 EST 2010


Author: epbernard
Date: 2010-02-04 12:54:05 -0500 (Thu, 04 Feb 2010)
New Revision: 18692

Modified:
   core/trunk/annotations/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyHolder.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DependentId.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DerivedIdentitySimpleParentIdClassDepTest.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/Employee.java
   core/trunk/core/src/main/java/org/hibernate/id/ForeignGenerator.java
   core/trunk/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
   core/trunk/core/src/main/java/org/hibernate/type/EntityType.java
Log:
HHH-4848 partial implementation of @IdClass support in derivedidentity (example 1 case a of the spec)

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -55,6 +55,7 @@
 	private Map<String, JoinTable> currentPropertyJoinTableOverride;
 	private String path;
 	private ExtendedMappings mappings;
+	private Boolean isInIdClass;
 
 
 	public AbstractPropertyHolder(
@@ -66,6 +67,15 @@
 		buildHierarchyColumnOverride( clazzToProcess );
 	}
 
+
+	public boolean isInIdClass() {
+		return isInIdClass != null ? isInIdClass : parent != null ? parent.isInIdClass() : false;
+	}
+
+	public void setInIdClass(Boolean isInIdClass) {
+		this.isInIdClass = isInIdClass;
+	}
+
 	public String getPath() {
 		return path;
 	}

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -701,6 +701,7 @@
 			HashMap<String, IdGenerator> localGenerators = new HashMap<String, IdGenerator>();
 			boolean ignoreIdAnnotations = entityBinder.isIgnoreIdAnnotations();
 			entityBinder.setIgnoreIdAnnotations( true );
+			propertyHolder.setInIdClass( true );
 			bindId(
 					generatorType,
 					generator,
@@ -716,6 +717,7 @@
 					mappings,
 					inheritanceStatePerClass
 			);
+			propertyHolder.setInIdClass( null );
 			inferredData = new PropertyPreloadedData(
 					propertyAccessor, "_identifierMapper", compositeClass
 			);
@@ -728,7 +730,9 @@
 					entityBinder,
 					true,
 					true,
-					false, mappings, inheritanceStatePerClass
+					false,
+					mappings,
+					inheritanceStatePerClass
 			);
 			entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations );
 			persistentClass.setIdentifierMapper( mapper );
@@ -1164,7 +1168,7 @@
 	 *        strategy is used
 	 * @param propertyContainer Metadata about a class and its properties
 	 * @param mappings Mapping meta data
-	 * @return the number of id properties found while iterating the elements of {@code annoatedClass} using
+	 * @return the number of id properties found while iterating the elements of {@code annotatedClass} using
 	 * the determined access strategy, {@code false} otherwise.
 	 */
 	static int addElementsOfClass(
@@ -1206,6 +1210,9 @@
 		final XAnnotatedElement element = propertyAnnotatedElement.getProperty();
 		if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) {
 			annElts.add( 0, propertyAnnotatedElement );
+			if ( element.isAnnotationPresent( ManyToOne.class ) || element.isAnnotationPresent( OneToOne.class ) ) {
+				mappings.addToOneAndIdProperty( entity, propertyAnnotatedElement );
+			}
 			idPropertyCounter++;
 		}
 		else {
@@ -1713,15 +1720,15 @@
 				//FIXME do the overrideColumnFromMapsIdProperty here and force the idclass type to look like an @embedded
 				//Overrides from @MapsId if needed
 				boolean isOverridden = false;
-				if ( isId || propertyHolder.isOrWithinEmbeddedId() ) {
+				if ( isId || propertyHolder.isOrWithinEmbeddedId() || propertyHolder.isInIdClass() ) {
 					Ejb3Column[] oldColumns = columns;
-					columns = columnsBuilder.overrideColumnFromMapsIdProperty(isId);
+					columns = columnsBuilder.overrideColumnFromMapperOrMapsIdProperty(isId);
 					isOverridden = oldColumns != columns;
 				}
 				if ( isComponent ) {
 					String referencedEntityName = null;
 					if (isOverridden) {
-						final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
+						final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(
 								isId, propertyHolder, property.getName(), mappings
 						);
 						referencedEntityName = mapsIdProperty.getClassOrElementName();
@@ -1761,7 +1768,7 @@
 					propertyBinder.setLazy( lazy );
 					propertyBinder.setColumns( columns );
 					if (isOverridden) {
-						final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
+						final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(
 								isId, propertyHolder, property.getName(), mappings
 						);
 						propertyBinder.setReferencedEntityName( mapsIdProperty.getClassOrElementName() );
@@ -1771,7 +1778,7 @@
 
 				}
 				if (isOverridden) {
-						final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
+						final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(
 								isId, propertyHolder, property.getName(), mappings
 						);
 						HashMap<String, IdGenerator> localGenerators = (HashMap<String, IdGenerator>) classGenerators.clone();
@@ -2021,7 +2028,8 @@
 	}
 
 	public static Component fillComponent(
-          PropertyHolder propertyHolder, PropertyData inferredData, PropertyData baseInferredData,
+          PropertyHolder propertyHolder, PropertyData inferredData,
+		  PropertyData baseInferredData, //base inferred data correspond to the entity reproducing inferredData's properties (ie IdClass)
 		  AccessType propertyAccessor, boolean isNullable, EntityBinder entityBinder,
           boolean isComponentEmbedded, boolean isIdentifierMapper, boolean inSecondPass, ExtendedMappings mappings,
 		  Map<XClass, InheritanceState> inheritanceStatePerClass
@@ -2045,14 +2053,17 @@
 		XClass returnedClassOrElement = inferredData.getClassOrElement();
 
 		List<PropertyData> baseClassElements = null;
+		Map<String, PropertyData> orderedBaseClassElements = new HashMap<String, PropertyData>();
 		XClass baseReturnedClassOrElement;
-		if(baseInferredData != null)
-		{
+		if(baseInferredData != null) {
 		   baseClassElements = new ArrayList<PropertyData>();
 		   baseReturnedClassOrElement = baseInferredData.getClassOrElement();
 		   bindTypeDefs(baseReturnedClassOrElement, mappings);
 	       PropertyContainer propContainer = new PropertyContainer( baseReturnedClassOrElement, entityXClass );
 		   addElementsOfClass( baseClassElements, propertyAccessor, propContainer, mappings );
+			for (PropertyData element : baseClassElements) {
+				orderedBaseClassElements.put( element.getPropertyName(), element );
+			}
 		}
 
 		//embeddable elements can have type defs
@@ -2069,9 +2080,24 @@
 			superClass = superClass.getSuperclass();
 		}
 		if ( baseClassElements != null ) {
-			if ( !hasIdClassAnnotations( entityXClass ) ) {
+			//useful to avoid breaking pre JPA 2 mappings
+			if ( !hasAnnotationsOnIdClass( entityXClass ) ) {
 				for ( int i = 0; i < classElements.size(); i++ ) {
-					classElements.set( i, baseClassElements.get( i ) );  //this works since they are in the same order
+					final PropertyData idClassPropertyData = classElements.get( i );
+					final PropertyData entityPropertyData = orderedBaseClassElements.get( idClassPropertyData.getPropertyName() );
+					if ( propertyHolder.isInIdClass() ) {
+						if ( entityPropertyData.getProperty().isAnnotationPresent( ManyToOne.class )
+								|| entityPropertyData.getProperty().isAnnotationPresent( OneToOne.class ) ) {
+							//don't replace here as we need to use the actual original return type
+							//the annotation overriding will be dealt with by a mechanism similar to @MapsId
+						}
+						else {
+							classElements.set( i, entityPropertyData );  //this works since they are in the same order
+						}
+					}
+					else {
+						classElements.set( i, entityPropertyData );  //this works since they are in the same order
+					}
 				}
 			}
 		}
@@ -2087,10 +2113,9 @@
 			
 			XProperty property = propertyAnnotatedElement.getProperty();
 			if(property.isAnnotationPresent(GeneratedValue.class) &&
-			      property.isAnnotationPresent(Id.class))
-			{
+			      property.isAnnotationPresent(Id.class) ) {
 			   //clone classGenerator and override with local values
-			   HashMap<String, IdGenerator> localGenerators = (HashMap<String, IdGenerator>) new HashMap<String, IdGenerator>();
+			   HashMap<String, IdGenerator> localGenerators = new HashMap<String, IdGenerator>();
 			   localGenerators.putAll( buildLocalGenerators( property, mappings ) );
 
 			   GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class );
@@ -2647,10 +2672,10 @@
 		return inheritanceStatePerClass;
 	}
 
-	private static boolean hasIdClassAnnotations(XClass idClass)
+	private static boolean hasAnnotationsOnIdClass(XClass idClass)
 	{
-		if(idClass.getAnnotation(Embeddable.class) != null)
-			return true;
+//		if(idClass.getAnnotation(Embeddable.class) != null)
+//			return true;
 
 		List<XProperty> properties = idClass.getDeclaredProperties( XClass.ACCESS_FIELD );
 		for ( XProperty property : properties ) {

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -65,7 +65,6 @@
 import org.hibernate.HibernateException;
 import org.hibernate.Interceptor;
 import org.hibernate.MappingException;
-import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import org.hibernate.annotations.AnyMetaDef;
 import org.hibernate.annotations.Cache;
@@ -158,6 +157,7 @@
 	private boolean isDefaultProcessed = false;
 	private boolean isValidatorNotPresentLogged;
 	private Map<XClass,Map<String,PropertyData>> propertiesAnnotatedWithMapsId;
+	private Map<XClass,Map<String,PropertyData>> propertiesAnnotatedWithIdAndToOne;
 
 	public AnnotationConfiguration() {
 		super();
@@ -297,6 +297,7 @@
 		setEntityResolver( new EJB3DTDEntityResolver() );
 		anyMetaDefs = new HashMap<String, AnyMetaDef>();
 		propertiesAnnotatedWithMapsId = new HashMap<XClass, Map<String,PropertyData>>();
+		propertiesAnnotatedWithIdAndToOne = new HashMap<XClass, Map<String,PropertyData>>(); 
 		reflectionManager = new JavaReflectionManager();
 		( ( MetadataProviderInjector ) reflectionManager ).setMetadataProvider( new JPAMetadataProvider() );
 
@@ -1293,6 +1294,20 @@
 			map.put( property.getProperty().getAnnotation( MapsId.class ).value(), property );
 		}
 
+		public PropertyData getPropertyAnnotatedWithIdAndToOne(XClass entityType, String propertyName) {
+			final Map<String, PropertyData> map = propertiesAnnotatedWithIdAndToOne.get( entityType );
+			return map == null ? null : map.get( propertyName );
+		}
+
+		public void addToOneAndIdProperty(XClass entityType, PropertyData property) {
+			Map<String, PropertyData> map = propertiesAnnotatedWithIdAndToOne.get( entityType );
+			if (map == null) {
+				map = new HashMap<String, PropertyData>();
+				propertiesAnnotatedWithIdAndToOne.put( entityType, map );
+			}
+			map.put( property.getPropertyName(), property );
+		}
+
 		private Boolean useNewGeneratorMappings;
 
 		@SuppressWarnings({ "UnnecessaryUnboxing" })

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/BinderHelper.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -652,7 +652,7 @@
 		return StringHelper.qualify( holder.getPath(), property.getPropertyName() );
 	}
 
-	static PropertyData getPropertyAnnotatedWithMapsId(boolean isId, PropertyHolder propertyHolder, String propertyName, ExtendedMappings mappings) {
+	static PropertyData getPropertyOverriddenByMapperOrMapsId(boolean isId, PropertyHolder propertyHolder, String propertyName, ExtendedMappings mappings) {
 		final XClass persistentXClass;
 		try {
 			 persistentXClass = mappings.getReflectionManager()
@@ -661,8 +661,12 @@
 		catch ( ClassNotFoundException e ) {
 			throw new AssertionFailure( "PersistentClass name cannot be converted into a Class", e);
 		}
-		String propertyPath = isId ? "" : propertyName;
-		final PropertyData annotatedWithMapsId = mappings.getPropertyAnnotatedWithMapsId( persistentXClass, propertyPath );
-		return annotatedWithMapsId;
+		if ( propertyHolder.isInIdClass() ) {
+			return mappings.getPropertyAnnotatedWithIdAndToOne( persistentXClass, propertyName );
+		}
+		else {
+			String propertyPath = isId ? "" : propertyName;
+			return mappings.getPropertyAnnotatedWithMapsId( persistentXClass, propertyPath );
+		}
 	}
 }

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -11,12 +11,10 @@
 import javax.persistence.OneToOne;
 
 import org.hibernate.AnnotationException;
-import org.hibernate.AssertionFailure;
 import org.hibernate.annotations.CollectionOfElements;
 import org.hibernate.annotations.Columns;
 import org.hibernate.annotations.Formula;
 import org.hibernate.annotations.JoinColumnsOrFormulas;
-import org.hibernate.annotations.common.reflection.XClass;
 import org.hibernate.annotations.common.reflection.XProperty;
 import org.hibernate.cfg.annotations.EntityBinder;
 import org.hibernate.cfg.annotations.Nullability;
@@ -183,15 +181,13 @@
 		return joinColumns;
 	}
 
-	Ejb3Column[] overrideColumnFromMapsIdProperty(boolean isId) {
+	Ejb3Column[] overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
 		Ejb3Column[] result = columns;
-		final PropertyData annotatedWithMapsId = BinderHelper.getPropertyAnnotatedWithMapsId( isId, propertyHolder, property.getName(), mappings );
+		final PropertyData annotatedWithMapsId = BinderHelper.getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), mappings );
 		if ( annotatedWithMapsId != null ) {
 			result = buildExplicitJoinColumns( annotatedWithMapsId.getProperty(), annotatedWithMapsId );
 			if (result == null) {
 				result = buildDefaultJoinColumnsForXToOne( annotatedWithMapsId.getProperty(), annotatedWithMapsId);
-//				throw new UnsupportedOperationException( "Implicit @JoinColumn is not supported on @MapsId properties: "
-//						+ annotatedWithMapsId.getDeclaringClass() + " " + annotatedWithMapsId.getPropertyName() );
 			}
 		}
 		return result;

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -188,4 +188,12 @@
 	 * @return True if the new generators should be used, false otherwise.
 	 */
 	public boolean useNewGeneratorMappings();
+
+	/**
+	 * Return the property annotated with @ToOne and @Id if any.
+	 * Null otherwise
+	 */
+	public PropertyData getPropertyAnnotatedWithIdAndToOne(XClass entityType, String propertyName);
+
+	void addToOneAndIdProperty(XClass entity, PropertyData property);
 }
\ No newline at end of file

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyHolder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyHolder.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyHolder.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -89,4 +89,8 @@
 	String getEntityName();
 
 	Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation);
+
+	boolean isInIdClass();
+
+	void setInIdClass(Boolean isInIdClass);
 }

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DependentId.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DependentId.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DependentId.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -7,5 +7,5 @@
  */
 public class DependentId implements Serializable {
 	String name;
-	long empPK;	// corresponds to PK type of Employee
+	long emp;	// corresponds to PK type of Employee
 }
\ No newline at end of file

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DerivedIdentitySimpleParentIdClassDepTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DerivedIdentitySimpleParentIdClassDepTest.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/DerivedIdentitySimpleParentIdClassDepTest.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -1,6 +1,7 @@
 package org.hibernate.test.annotations.derivedidentities.e1.a;
 
 import org.hibernate.Session;
+import org.hibernate.junit.FailureExpected;
 import org.hibernate.test.annotations.TestCase;
 import org.hibernate.test.util.SchemaUtil;
 
@@ -10,36 +11,40 @@
 public class
 		DerivedIdentitySimpleParentIdClassDepTest extends TestCase {
 
+	@FailureExpected( jiraKey = "HHH-4848" )
 	public void testManyToOne() throws Exception {
-//		assertTrue( SchemaUtil.isColumnPresent( "Dependent", "FK", getCfg() ) );
-//		assertTrue( ! SchemaUtil.isColumnPresent( "Dependent", "empPK", getCfg() ) );
-//		Employee e = new Employee();
-//		e.empId = 1;
-//		e.empName = "Emmanuel";
-//		Session s = openSession(  );
-//		s.getTransaction().begin();
-//		s.persist( e );
-//		Dependent d = new Dependent();
-//		d.emp = e;
-//		d.name = "Doggy";
-//		d.emp = e;
-//		s.persist( d );
-//		s.flush();
-//		s.clear();
-//		DependentId dId = new DependentId();
-//		dId.name = d.name;
-//		dId.empPK = d.emp.empId;
-//		d = (Dependent) s.get( Dependent.class, dId );
-//		assertEquals( e.empId, d.emp.empId );
-//		s.getTransaction().rollback();
-//		s.close();
+		assertTrue( SchemaUtil.isColumnPresent( "Dependent", "emp_empId", getCfg() ) );
+		assertTrue( ! SchemaUtil.isColumnPresent( "Dependent", "emp", getCfg() ) );
+		Employee e = new Employee();
+		e.empId = 1;
+		e.empName = "Emmanuel";
+		e.nickname = "Manu";
+		Session s = openSession(  );
+		s.getTransaction().begin();
+		s.persist( e );
+		Dependent d = new Dependent();
+		d.emp = e;
+		d.name = "Doggy";
+		d.emp = e;
+		s.persist( d );
+		s.flush();
+		s.clear();
+		DependentId dId = new DependentId();
+		dId.name = d.name;
+		dId.emp = d.emp.empId;
+		d = (Dependent) s.get( Dependent.class, dId );
+		assertEquals( e.empId, d.emp.empId );
+		assertEquals( e.empName, d.emp.empName );
+		assertEquals( e.nickname, d.emp.nickname );
+		s.getTransaction().rollback();
+		s.close();
 	}
 
 	@Override
 	protected Class<?>[] getAnnotatedClasses() {
 		return new Class<?>[] {
-				//Dependent.class,
-				//Employee.class
+				Dependent.class,
+				Employee.class
 		};
 	}
 }
\ No newline at end of file

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/Employee.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/Employee.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/a/Employee.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -11,4 +11,6 @@
 	@Id
 	long empId;
 	String empName;
+
+	String nickname;
 }
\ No newline at end of file

Modified: core/trunk/core/src/main/java/org/hibernate/id/ForeignGenerator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/ForeignGenerator.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/core/src/main/java/org/hibernate/id/ForeignGenerator.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -33,6 +33,7 @@
 import org.hibernate.dialect.Dialect;
 import org.hibernate.engine.ForeignKeys;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.metadata.ClassMetadata;
 import org.hibernate.type.EntityType;
 import org.hibernate.type.Type;
 
@@ -95,19 +96,27 @@
 	public Serializable generate(SessionImplementor sessionImplementor, Object object) {
 		Session session = ( Session ) sessionImplementor;
 
-		Object associatedObject = sessionImplementor.getFactory()
-				.getClassMetadata( entityName )
+		final ClassMetadata classMetadata = sessionImplementor.getFactory()
+				.getClassMetadata( entityName );
+		Object associatedObject = classMetadata
 		        .getPropertyValue( object, propertyName, session.getEntityMode() );
 		if ( associatedObject == null ) {
 			throw new IdentifierGenerationException(
 					"attempted to assign id from null one-to-one property [" + getRole() + "]"
 			);
 		}
-		
-		EntityType type = (EntityType) sessionImplementor.getFactory()
-        	.getClassMetadata( entityName )
-        	.getPropertyType( propertyName );
 
+		final Type uncheckedType = classMetadata
+				.getPropertyType( propertyName );
+		EntityType type;
+		if (uncheckedType instanceof EntityType) {
+		 	type = (EntityType) uncheckedType;
+		}
+		else {
+			//try identifier mapper
+			type = (EntityType) classMetadata.getPropertyType( "_identifierMapper." + propertyName );
+		}
+
 		Serializable id;
 		try {
 			id = ForeignKeys.getEntityIdentifierIfNotUnsaved(

Modified: core/trunk/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -30,6 +30,8 @@
 
 import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
+import org.hibernate.PropertyAccessException;
+import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.tuple.Instantiator;
 import org.hibernate.tuple.VersionProperty;
 import org.hibernate.tuple.StandardProperty;
@@ -45,6 +47,8 @@
 import org.hibernate.proxy.ProxyFactory;
 import org.hibernate.type.AbstractComponentType;
 import org.hibernate.type.ComponentType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
 
 
 /**
@@ -70,6 +74,9 @@
 	private final ProxyFactory proxyFactory;
 	private final AbstractComponentType identifierMapperType;
 
+	public Type getIdentifierMapperType() {
+		return identifierMapperType;
+	}
 
 	/**
 	 * Build an appropriate Getter for the given property.
@@ -192,13 +199,27 @@
 				else {
 					ComponentType copier = (ComponentType) entityMetamodel.getIdentifierProperty().getType();
 					id = copier.instantiate( getEntityMode() );
-					copier.setPropertyValues( id, identifierMapperType.getPropertyValues( entity, getEntityMode() ), getEntityMode() );
+					final Object[] propertyValues = identifierMapperType.getPropertyValues( entity, getEntityMode() );
+					Type[] subTypes = identifierMapperType.getSubtypes();
+					Type[] copierSubTypes = copier.getSubtypes();
+					final int length = subTypes.length;
+					for ( int i = 0 ; i < length; i++ ) {
+						//JPA 2 in @IdClass points to the pk of the entity
+						if ( subTypes[i].isAssociationType() && ! copierSubTypes[i].isAssociationType()) {
+							final String associatedEntityName = ( ( EntityType ) subTypes[i] ).getAssociatedEntityName();
+							final EntityPersister entityPersister = getFactory().getEntityPersister(
+									associatedEntityName
+							);
+							propertyValues[i] = entityPersister.getIdentifier( propertyValues[i], getEntityMode() );
+						}
+					}
+					copier.setPropertyValues( id, propertyValues, getEntityMode() );
 				}
 			}
 			else {
-				id = idGetter.get( entity );
-			}
-		}
+                id = idGetter.get( entity );
+            }
+        }
 
 		try {
 			return (Serializable) id;
@@ -229,7 +250,18 @@
 		else if ( identifierMapperType != null ) {
 			ComponentType extractor = (ComponentType) entityMetamodel.getIdentifierProperty().getType();
 			ComponentType copier = (ComponentType) identifierMapperType;
-			copier.setPropertyValues( entity, extractor.getPropertyValues( id, getEntityMode() ), getEntityMode() );
+			final Object[] propertyValues = extractor.getPropertyValues( id, getEntityMode() );
+			Type[] subTypes = identifierMapperType.getSubtypes();
+			Type[] copierSubTypes = copier.getSubtypes();
+			final int length = subTypes.length;
+			for ( int i = 0 ; i < length; i++ ) {
+				//JPA 2 in @IdClass points to the pk of the entity
+				if ( subTypes[i].isAssociationType() && ! copierSubTypes[i].isAssociationType() ) {
+					final String associatedEntityName = ( ( EntityType ) subTypes[i] ).getAssociatedEntityName();
+					//FIXME find the entity for the given id (propertyValue[i])
+				}
+			}
+			copier.setPropertyValues( entity, propertyValues, getEntityMode() );
 		}
 	}
 
@@ -299,18 +331,27 @@
 	}
 
 	public Object getPropertyValue(Object entity, String propertyPath) throws HibernateException {
-		final int loc = propertyPath.indexOf('.');
-		final String basePropertyName = loc > 0
+		int loc = propertyPath.indexOf('.');
+		String basePropertyName = loc > 0
 				? propertyPath.substring( 0, loc )
 				: propertyPath;
-		final int index = entityMetamodel.getPropertyIndex( basePropertyName );
-		final Object baseValue = getPropertyValue( entity, index );
+		//final int index = entityMetamodel.getPropertyIndexOrNull( basePropertyName );
+		Integer index = entityMetamodel.getPropertyIndexOrNull( basePropertyName );
+		if (index == null) {
+			propertyPath = "_identifierMapper." + propertyPath;
+			loc = propertyPath.indexOf('.');
+			basePropertyName = loc > 0
+				? propertyPath.substring( 0, loc )
+				: propertyPath;
+		}
+		index = entityMetamodel.getPropertyIndexOrNull( basePropertyName );
+		final Object baseValue = getPropertyValue( entity, index.intValue() );
 		if ( loc > 0 ) {
 			if ( baseValue == null ) {
 				return null;
 			}
 			return getComponentValue(
-					(ComponentType) entityMetamodel.getPropertyTypes()[index],
+					(ComponentType) entityMetamodel.getPropertyTypes()[index.intValue()],
 					baseValue,
 					propertyPath.substring(loc+1)
 			);

Modified: core/trunk/core/src/main/java/org/hibernate/type/EntityType.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/type/EntityType.java	2010-02-04 17:27:20 UTC (rev 18691)
+++ core/trunk/core/src/main/java/org/hibernate/type/EntityType.java	2010-02-04 17:54:05 UTC (rev 18692)
@@ -307,7 +307,13 @@
 			id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getIdentifier();
 		}
 		else {
-			id = persister.getIdentifier(x, entityMode);
+			final Class mappedClass = persister.getMappedClass( entityMode );
+			if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
+				id = persister.getIdentifier(x, entityMode);
+			}
+			else {
+				id = (Serializable) x;
+			}
 		}
 		return persister.getIdentifierType().getHashCode(id, entityMode, factory);
 	}
@@ -321,13 +327,20 @@
 			return super.isEqual(x, y, entityMode);
 		}
 
+		final Class mappedClass = persister.getMappedClass( entityMode );
 		Serializable xid;
 		if (x instanceof HibernateProxy) {
 			xid = ( (HibernateProxy) x ).getHibernateLazyInitializer()
 					.getIdentifier();
 		}
 		else {
-			xid = persister.getIdentifier(x, entityMode);
+			if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
+				xid = persister.getIdentifier(x, entityMode);
+			}
+			else {
+				//JPA 2 case where @IdClass contains the id and not the associated entity
+				xid = (Serializable) x;
+			}
 		}
 
 		Serializable yid;
@@ -336,7 +349,13 @@
 					.getIdentifier();
 		}
 		else {
-			yid = persister.getIdentifier(y, entityMode);
+			if ( mappedClass.isAssignableFrom( y.getClass() ) ) {
+				yid = persister.getIdentifier(x, entityMode);
+			}
+			else {
+				//JPA 2 case where @IdClass contains the id and not the associated entity
+				yid = (Serializable) y;
+			}
 		}
 
 		return persister.getIdentifierType()



More information about the hibernate-commits mailing list