[hibernate-commits] Hibernate SVN: r18583 - in core/trunk/annotations/src: test/java/org/hibernate/test/annotations/derivedidentities and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Jan 19 13:57:20 EST 2010


Author: epbernard
Date: 2010-01-19 13:57:19 -0500 (Tue, 19 Jan 2010)
New Revision: 18583

Added:
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java
Modified:
   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/ExtendedMappings.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java
Log:
HHH-4529 Support for basic @MapsId on simple id on both parent and derived (example 4.a). However I am losing the creation of the FK constraint.

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2010-01-19 18:50:29 UTC (rev 18582)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -56,6 +56,7 @@
 import javax.persistence.ManyToOne;
 import javax.persistence.MapKey;
 import javax.persistence.MappedSuperclass;
+import javax.persistence.MapsId;
 import javax.persistence.NamedNativeQueries;
 import javax.persistence.NamedNativeQuery;
 import javax.persistence.NamedQueries;
@@ -891,7 +892,7 @@
 		boolean hasIdentifier = false;
 
 		for ( int index = 0; index < deep; index++ ) {
-			PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ) );
+			PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ), clazzToProcess );
 			boolean currentHasIdentifier = addElementsOfClass( elements, accessType, properyContainer, mappings );
 			hasIdentifier = hasIdentifier || currentHasIdentifier;
 		}
@@ -1116,7 +1117,7 @@
 		Collection<XProperty> properties = propertyContainer.getProperties( accessType );
 		for ( XProperty p : properties ) {
 			final boolean currentHasIdentifier = addProperty(
-					propertyContainer.getXClass(), p, elements, accessType.getType(), mappings
+					propertyContainer, p, elements, accessType.getType(), mappings
 			);
 			hasIdentifier = hasIdentifier || currentHasIdentifier;
 		}
@@ -1124,9 +1125,11 @@
 	}
 
 	private static boolean addProperty(
-			XClass declaringClass, XProperty property, List<PropertyData> annElts,
+			PropertyContainer propertyContainer, XProperty property, List<PropertyData> annElts,
 			String propertyAccessor, ExtendedMappings mappings
 	) {
+		final XClass declaringClass = propertyContainer.getDeclaringClass();
+		final XClass entity = propertyContainer.getEntityAtStake();
 		boolean hasIdentifier;
 		PropertyData propertyAnnotatedElement = new PropertyInferredData(
 				declaringClass, property, propertyAccessor,
@@ -1145,6 +1148,9 @@
 			annElts.add( propertyAnnotatedElement );
 			hasIdentifier = false;
 		}
+		if ( element.isAnnotationPresent( MapsId.class  ) ) {
+			mappings.addPropertyAnnotatedWithMapsId( entity, propertyAnnotatedElement );
+		}
 
 		return hasIdentifier;
 	}
@@ -1166,7 +1172,7 @@
 		 * ordering does not matter
 		 */
 		Ejb3Column[] columns = null;
-		Ejb3JoinColumn[] joinColumns = null;
+
 		log.debug(
 				"Processing annotations of {}.{}", propertyHolder.getEntityName(), inferredData.getPropertyName()
 		);
@@ -1183,36 +1189,11 @@
 			}
 			return;
 		}
+		Ejb3JoinColumn[] joinColumns = buildExplicitJoinColumns(
+				propertyHolder, property, inferredData, entityBinder, mappings
+		);
 
-		//process @JoinColumn(s) before @Column(s) to handle collection of entities properly
-		{
-			JoinColumn[] anns = null;
 
-			if ( property.isAnnotationPresent( JoinColumn.class ) ) {
-				anns = new JoinColumn[] { property.getAnnotation( JoinColumn.class ) };
-			}
-			else if ( property.isAnnotationPresent( JoinColumns.class ) ) {
-				JoinColumns ann = property.getAnnotation( JoinColumns.class );
-				anns = ann.value();
-				int length = anns.length;
-				if ( length == 0 ) {
-					throw new AnnotationException( "Cannot bind an empty @JoinColumns" );
-				}
-			}
-			if ( anns != null ) {
-				joinColumns = Ejb3JoinColumn.buildJoinColumns(
-						anns, null, entityBinder.getSecondaryTables(),
-						propertyHolder, inferredData.getPropertyName(), mappings
-				);
-			}
-			else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) {
-				JoinColumnsOrFormulas ann = property.getAnnotation( JoinColumnsOrFormulas.class );
-				joinColumns = Ejb3JoinColumn.buildJoinColumnsOrFormulas(
-						ann, null, entityBinder.getSecondaryTables(),
-						propertyHolder, inferredData.getPropertyName(), mappings
-				);
-			}
-		}
 		if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent( Formula.class ) ) {
 			Column ann = property.getAnnotation( Column.class );
 			Formula formulaAnn = property.getAnnotation( Formula.class );
@@ -1234,30 +1215,9 @@
 				( property.isAnnotationPresent( ManyToOne.class )
 						|| property.isAnnotationPresent( OneToOne.class ) )
 				) {
-			JoinTable joinTableAnn = propertyHolder.getJoinTable( property );
-			if ( joinTableAnn != null ) {
-				joinColumns = Ejb3JoinColumn.buildJoinColumns(
-						joinTableAnn.inverseJoinColumns(), null, entityBinder.getSecondaryTables(),
-						propertyHolder, inferredData.getPropertyName(), mappings
-				);
-				if ( StringHelper.isEmpty( joinTableAnn.name() ) ) {
-					throw new AnnotationException(
-							"JoinTable.name() on a @ToOne association has to be explicit: "
-									+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
-					);
-				}
-			}
-			else {
-				OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class );
-				String mappedBy = oneToOneAnn != null ?
-						oneToOneAnn.mappedBy() :
-						null;
-				joinColumns = Ejb3JoinColumn.buildJoinColumns(
-						(JoinColumn[]) null,
-						mappedBy, entityBinder.getSecondaryTables(),
-						propertyHolder, inferredData.getPropertyName(), mappings
-				);
-			}
+			joinColumns = buildDefaultJoinColumnsForXToOne(
+					propertyHolder, property, inferredData, entityBinder, mappings
+			);
 		}
 		else if ( joinColumns == null &&
 				( property.isAnnotationPresent( OneToMany.class )
@@ -1843,6 +1803,69 @@
 		}
 	}
 
+	private static Ejb3JoinColumn[] buildDefaultJoinColumnsForXToOne(PropertyHolder propertyHolder, XProperty property, PropertyData inferredData, EntityBinder entityBinder, ExtendedMappings mappings) {
+		Ejb3JoinColumn[] joinColumns;
+		JoinTable joinTableAnn = propertyHolder.getJoinTable( property );
+		if ( joinTableAnn != null ) {
+			joinColumns = Ejb3JoinColumn.buildJoinColumns(
+					joinTableAnn.inverseJoinColumns(), null, entityBinder.getSecondaryTables(),
+					propertyHolder, inferredData.getPropertyName(), mappings
+			);
+			if ( StringHelper.isEmpty( joinTableAnn.name() ) ) {
+				throw new AnnotationException(
+						"JoinTable.name() on a @ToOne association has to be explicit: "
+								+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
+				);
+			}
+		}
+		else {
+			OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class );
+			String mappedBy = oneToOneAnn != null ?
+					oneToOneAnn.mappedBy() :
+					null;
+			joinColumns = Ejb3JoinColumn.buildJoinColumns(
+					( JoinColumn[]) null,
+					mappedBy, entityBinder.getSecondaryTables(),
+					propertyHolder, inferredData.getPropertyName(), mappings
+			);
+		}
+		return joinColumns;
+	}
+
+	private static Ejb3JoinColumn[] buildExplicitJoinColumns(PropertyHolder propertyHolder, XProperty property, PropertyData inferredData, EntityBinder entityBinder, ExtendedMappings mappings) {
+		//process @JoinColumn(s) before @Column(s) to handle collection of entities properly
+		Ejb3JoinColumn[] joinColumns = null;
+		{
+			JoinColumn[] anns = null;
+
+			if ( property.isAnnotationPresent( JoinColumn.class ) ) {
+				anns = new JoinColumn[] { property.getAnnotation( JoinColumn.class ) };
+			}
+			else if ( property.isAnnotationPresent( JoinColumns.class ) ) {
+				JoinColumns ann = property.getAnnotation( JoinColumns.class );
+				anns = ann.value();
+				int length = anns.length;
+				if ( length == 0 ) {
+					throw new AnnotationException( "Cannot bind an empty @JoinColumns" );
+				}
+			}
+			if ( anns != null ) {
+				joinColumns = Ejb3JoinColumn.buildJoinColumns(
+						anns, null, entityBinder.getSecondaryTables(),
+						propertyHolder, inferredData.getPropertyName(), mappings
+				);
+			}
+			else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) {
+				JoinColumnsOrFormulas ann = property.getAnnotation( JoinColumnsOrFormulas.class );
+				joinColumns = Ejb3JoinColumn.buildJoinColumnsOrFormulas(
+						ann, null, entityBinder.getSecondaryTables(),
+						propertyHolder, inferredData.getPropertyName(), mappings
+				);
+			}
+		}
+		return joinColumns;
+	}
+
 	//TODO move that to collection binder?
 	private static void bindJoinedTableAssociation(
 			XProperty property, ExtendedMappings mappings, EntityBinder entityBinder,
@@ -1979,6 +2002,7 @@
 				inferredData, propertyHolder, mappings
 		);
 
+		final XClass entityXClass = inferredData.getPropertyClass();
 		List<PropertyData> classElements = new ArrayList<PropertyData>();
 		XClass returnedClassOrElement = inferredData.getClassOrElement();
 
@@ -1989,25 +2013,25 @@
 		   baseClassElements = new ArrayList<PropertyData>();
 		   baseReturnedClassOrElement = baseInferredData.getClassOrElement();
 		   bindTypeDefs(baseReturnedClassOrElement, mappings);
-	       PropertyContainer propContainer = new PropertyContainer( baseReturnedClassOrElement );
+	       PropertyContainer propContainer = new PropertyContainer( baseReturnedClassOrElement, entityXClass );
 		   addElementsOfClass( baseClassElements, propertyAccessor, propContainer, mappings );
 		}
 
 		//embeddable elements can have type defs
 		bindTypeDefs(returnedClassOrElement, mappings);
-		PropertyContainer propContainer = new PropertyContainer( returnedClassOrElement );
+		PropertyContainer propContainer = new PropertyContainer( returnedClassOrElement, entityXClass );
 		addElementsOfClass( classElements, propertyAccessor, propContainer, mappings);
 
 		//add elements of the embeddable superclass
-		XClass superClass = inferredData.getPropertyClass().getSuperclass();
+		XClass superClass = entityXClass.getSuperclass();
 		while ( superClass != null && superClass.isAnnotationPresent( MappedSuperclass.class ) ) {
 			//FIXME: proper support of typevariables incl var resolved at upper levels
-			propContainer = new PropertyContainer( superClass );
+			propContainer = new PropertyContainer( superClass, entityXClass );
 			addElementsOfClass( classElements, propertyAccessor, propContainer, mappings );
 			superClass = superClass.getSuperclass();
 		}
 		if ( baseClassElements != null ) {
-			if ( !hasIdClassAnnotations( inferredData.getPropertyClass() ) ) {
+			if ( !hasIdClassAnnotations( entityXClass ) ) {
 				for ( int i = 0; i < classElements.size(); i++ ) {
 					classElements.set( i, baseClassElements.get( i ) );  //this works since they are in the same order
 				}
@@ -2082,6 +2106,22 @@
 			setupComponentTuplizer( property, componentId );
 		}
 		else {
+			final XClass persistentXClass;
+			try {
+				 persistentXClass = mappings.getReflectionManager()
+						.classForName( persistentClassName, AnnotationBinder.class );
+			}
+			catch ( ClassNotFoundException e ) {
+				throw new AssertionFailure( "Persistence class name cannot be converted into a Class", e);
+			}
+			final PropertyData annotatedWithMapsId = mappings.getPropertyAnnotatedWithMapsId( persistentXClass, "" );
+			if ( annotatedWithMapsId != null ) {
+				columns = buildExplicitJoinColumns( propertyHolder, annotatedWithMapsId.getProperty(), annotatedWithMapsId, entityBinder, mappings );
+				if (columns == null) {
+					columns = buildDefaultJoinColumnsForXToOne( propertyHolder, annotatedWithMapsId.getProperty(), annotatedWithMapsId, entityBinder, mappings );
+				}
+			}
+
 			for (Ejb3Column column : columns) {
 				column.forceNotNull(); //this is an id
 			}

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java	2010-01-19 18:50:29 UTC (rev 18582)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -46,6 +46,7 @@
 import javax.persistence.Embeddable;
 import javax.persistence.Entity;
 import javax.persistence.MappedSuperclass;
+import javax.persistence.MapsId;
 
 import org.dom4j.Attribute;
 import org.dom4j.Document;
@@ -64,6 +65,7 @@
 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.common.reflection.MetadataProvider;
@@ -141,6 +143,7 @@
 	private transient ReflectionManager reflectionManager;
 	private boolean isDefaultProcessed = false;
 	private boolean isValidatorNotPresentLogged;
+	private Map<XClass,Map<String,PropertyData>> propertiesAnnotatedWithMapsId;
 
 	public AnnotationConfiguration() {
 		super();
@@ -279,6 +282,7 @@
 		namingStrategy = EJB3NamingStrategy.INSTANCE;
 		setEntityResolver( new EJB3DTDEntityResolver() );
 		anyMetaDefs = new HashMap<String, AnyMetaDef>();
+		propertiesAnnotatedWithMapsId = new HashMap<XClass, Map<String,PropertyData>>();
 		reflectionManager = new JavaReflectionManager();
 		( ( MetadataProviderInjector ) reflectionManager ).setMetadataProvider( new JPAMetadataProvider() );
 
@@ -1271,6 +1275,20 @@
 			return inSecondPass;
 		}
 
+		public PropertyData getPropertyAnnotatedWithMapsId(XClass entityType, String propertyName) {
+			final Map<String, PropertyData> map = propertiesAnnotatedWithMapsId.get( entityType );
+			return map == null ? null : map.get( propertyName );
+		}
+
+		public void addPropertyAnnotatedWithMapsId(XClass entityType, PropertyData property) {
+			Map<String, PropertyData> map = propertiesAnnotatedWithMapsId.get( entityType );
+			if (map == null) {
+				map = new HashMap<String, PropertyData>();
+				propertiesAnnotatedWithMapsId.put( entityType, map );
+			}
+			map.put( property.getProperty().getAnnotation( MapsId.class ).value(), property );
+		}
+
 		public IdGenerator getGenerator(String name) {
 			return getGenerator( name, null );
 		}

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java	2010-01-19 18:50:29 UTC (rev 18582)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/ExtendedMappings.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -171,4 +171,12 @@
 	public AnyMetaDef getAnyMetaDef(String name);
 	
 	public boolean isInSecondPass();
+
+	/**
+	 * Return the property annotated with @MapsId("propertyName") if any.
+	 * Null otherwise
+	 */
+	public PropertyData getPropertyAnnotatedWithMapsId(XClass entityType, String propertyName);
+
+	public void addPropertyAnnotatedWithMapsId(XClass entityType, PropertyData property);
 }
\ No newline at end of file

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java	2010-01-19 18:50:29 UTC (rev 18582)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -1,4 +1,4 @@
-// $Id:$
+// $Id$
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
@@ -55,20 +55,26 @@
 class PropertyContainer {
 
 	private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class );
+	private final XClass entityAtStake;
 	private final TreeMap<String, XProperty> fieldAccessMap;
 	private final TreeMap<String, XProperty> propertyAccessMap;
 	private final XClass xClass;
 	private final AccessType explicitClassDefinedAccessType;
 
-	PropertyContainer(XClass clazz) {
+	PropertyContainer(XClass clazz, XClass entityAtStake) {
 		this.xClass = clazz;
+		this.entityAtStake = entityAtStake;
 		fieldAccessMap = initProperties( AccessType.FIELD );
 		propertyAccessMap = initProperties( AccessType.PROPERTY );
 		explicitClassDefinedAccessType = determineClassDefinedAccessStrategy();
 		checkForJpaAccess();
 	}
 
-	public XClass getXClass() {
+	public XClass getEntityAtStake() {
+		return entityAtStake;
+	}
+
+	public XClass getDeclaringClass() {
 		return xClass;
 	}
 

Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java	                        (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -0,0 +1,42 @@
+package org.hibernate.test.annotations.derivedidentities.e4.a;
+
+import org.hibernate.Session;
+import org.hibernate.test.annotations.TestCase;
+import org.hibernate.test.annotations.derivedidentities.e1.b.Dependent;
+import org.hibernate.test.annotations.derivedidentities.e1.b.DependentId;
+import org.hibernate.test.annotations.derivedidentities.e1.b.Employee;
+import org.hibernate.test.util.SchemaUtil;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class DerivedIdentitySimpleParentSimpleDepTest extends TestCase {
+
+	public void testIt() throws Exception {
+		assertTrue( SchemaUtil.isColumnPresent( "MedicalHistory", "FK", getCfg() ) );
+		assertTrue( ! SchemaUtil.isColumnPresent( "MedicalHistory", "id", getCfg() ) );
+		Person e = new Person();
+		e.ssn = "aaa";
+		Session s = openSession(  );
+		s.getTransaction().begin();
+		s.persist( e );
+		MedicalHistory d = new MedicalHistory();
+		d.patient = e;
+		d.id = "aaa"; //FIXME not needed when foreign is enabled
+		s.persist( d );
+		s.flush();
+		s.clear();
+		d = (MedicalHistory) s.get( MedicalHistory.class, d.id );
+		assertEquals( d.id, d.patient.ssn );
+		s.getTransaction().rollback();
+		s.close();
+	}
+
+	@Override
+	protected Class<?>[] getMappings() {
+		return new Class<?>[] {
+				MedicalHistory.class,
+				Person.class
+		};
+	}
+}
\ No newline at end of file

Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java	                        (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -0,0 +1,20 @@
+package org.hibernate.test.annotations.derivedidentities.e4.a;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.MapsId;
+import javax.persistence.OneToOne;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+public class MedicalHistory {
+	@Id
+	String id; // overriding not allowed ... // default join column name is overridden @MapsId
+	@JoinColumn(name = "FK")
+	@MapsId
+	@OneToOne
+	Person patient;
+}

Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java	                        (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java	2010-01-19 18:57:19 UTC (rev 18583)
@@ -0,0 +1,13 @@
+package org.hibernate.test.annotations.derivedidentities.e4.a;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+public class Person {
+	@Id
+	String ssn;
+}
\ No newline at end of file



More information about the hibernate-commits mailing list