[hibernate-commits] Hibernate SVN: r17187 - in core/trunk/annotations/src: main/java/org/hibernate/cfg/annotations and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Jul 21 20:16:59 EDT 2009


Author: epbernard
Date: 2009-07-21 20:16:59 -0400 (Tue, 21 Jul 2009)
New Revision: 17187

Added:
   core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/MapKeyJoinColumnDelegator.java
Modified:
   core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3Column.java
   core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/Atmosphere.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/target/Brand.java
Log:
ANN-857 implement @MapKeyJoinColumn and @MapKeyJoinColumns + _KEY default column name for key. Also keep legacy support for old naming solution

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2009-07-21 15:57:57 UTC (rev 17186)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -74,6 +74,8 @@
 import javax.persistence.CollectionTable;
 import javax.persistence.UniqueConstraint;
 import javax.persistence.MapKeyColumn;
+import javax.persistence.MapKeyJoinColumns;
+import javax.persistence.MapKeyJoinColumn;
 
 import org.hibernate.AnnotationException;
 import org.hibernate.AssertionFailure;
@@ -135,6 +137,7 @@
 import org.hibernate.cfg.annotations.TableBinder;
 import org.hibernate.cfg.annotations.MapKeyColumnDelegator;
 import org.hibernate.cfg.annotations.CustomizableColumns;
+import org.hibernate.cfg.annotations.MapKeyJoinColumnDelegator;
 import org.hibernate.engine.FilterDefinition;
 import org.hibernate.engine.Versioning;
 import org.hibernate.id.MultipleHiLoPerTableGenerator;
@@ -1540,39 +1543,88 @@
 						mappings
 				);
 			}
+			{
+				Column[] keyColumns = null;
+				//JPA 2 has priority and has different default column values, differenciate legacy from JPA 2
+				Boolean isJPA2 = null;
+				if ( property.isAnnotationPresent( MapKeyColumn.class ) ) {
+					isJPA2 = Boolean.TRUE;
+					keyColumns = new Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) };
+				}
+				else if ( property.isAnnotationPresent( org.hibernate.annotations.MapKey.class ) ) {
+					if ( isJPA2 == null) {
+						isJPA2 = Boolean.FALSE;
+					}
+					keyColumns = property.getAnnotation( org.hibernate.annotations.MapKey.class ).columns();
+				}
 
-			Column[] keyColumns = null;
-			//JPA 2 has priority
-			if ( property.isAnnotationPresent( MapKeyColumn.class ) ) {
-				keyColumns = new Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) };
+				//not explicitly legacy
+				if ( isJPA2 == null) {
+					isJPA2 = Boolean.TRUE;
+				}
+
+				//nullify empty array
+				keyColumns = keyColumns != null && keyColumns.length > 0 ? keyColumns : null;
+	            
+				PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" );
+				Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation(
+						keyColumns,
+						null,
+						Nullability.FORCED_NOT_NULL,
+						propertyHolder,
+						isJPA2 ? inferredData : mapKeyVirtualProperty,
+						isJPA2 ? "_KEY" : null,
+						entityBinder.getSecondaryTables(),
+						mappings
+				);
+				collectionBinder.setMapKeyColumns( mapColumns );
 			}
-			else if ( property.isAnnotationPresent( org.hibernate.annotations.MapKey.class ) ) {
-				keyColumns = property.getAnnotation( org.hibernate.annotations.MapKey.class ).columns();
-			}
-			//nullify empty array
-			keyColumns = keyColumns != null && keyColumns.length > 0 ? keyColumns : null;
+			{
+				JoinColumn[] joinKeyColumns = null;
+				//JPA 2 has priority and has different default column values, differenciate legacy from JPA 2
+				Boolean isJPA2 = null;
+				if ( property.isAnnotationPresent( MapKeyJoinColumns.class ) ) {
+					isJPA2 = Boolean.TRUE;
+					final MapKeyJoinColumn[] mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class ).value();
+					joinKeyColumns = new JoinColumn[mapKeyJoinColumns.length];
+					int index = 0;
+					for ( MapKeyJoinColumn joinColumn : mapKeyJoinColumns ) {
+						joinKeyColumns[index] = new MapKeyJoinColumnDelegator( joinColumn );
+						index++;
+					}
+					if ( joinKeyColumns != null ) {
+						throw new AnnotationException( "@MapKeyJoinColumn and @MapKeyJoinColumns used on the same property: "
+								+ StringHelper.qualify( propertyHolder.getClassName(), property.getName() ) );
+					}
+				}
+				else if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) {
+					isJPA2 = Boolean.TRUE;
+					joinKeyColumns = new JoinColumn[] { new MapKeyJoinColumnDelegator( property.getAnnotation( MapKeyJoinColumn.class ) ) };
+				}
+				else if ( property.isAnnotationPresent( org.hibernate.annotations.MapKeyManyToMany.class ) ) {
+					if ( isJPA2 == null) {
+						isJPA2 = Boolean.FALSE;
+					}
+					joinKeyColumns = property.getAnnotation( org.hibernate.annotations.MapKeyManyToMany.class ).joinColumns();
+				}
 
-			PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" );
-			Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation(
-					keyColumns,
-					null,
-					Nullability.FORCED_NOT_NULL,
-					propertyHolder,
-					mapKeyVirtualProperty,
-					entityBinder.getSecondaryTables(),
-					mappings
-			);
-			collectionBinder.setMapKeyColumns( mapColumns );
+				//not explicitly legacy
+				if ( isJPA2 == null) {
+					isJPA2 = Boolean.TRUE;
+				}
 
-			MapKeyManyToMany mapKeyManyToMany = property.getAnnotation( MapKeyManyToMany.class );
-			Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumns(
-					mapKeyManyToMany != null ?
-							mapKeyManyToMany.joinColumns() :
-							null,
-					null, entityBinder.getSecondaryTables(),
-					propertyHolder, mapKeyVirtualProperty.getPropertyName(), mappings
-			);
-			collectionBinder.setMapKeyManyToManyColumns( mapJoinColumns );
+	            PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" );
+				Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumnsWithDefaultColumnSuffix(
+						joinKeyColumns,
+						null,
+						entityBinder.getSecondaryTables(),
+						propertyHolder,
+						isJPA2 ? inferredData.getPropertyName() : mapKeyVirtualProperty.getPropertyName(),
+						isJPA2 ? "_KEY" : null,
+						mappings
+				);
+				collectionBinder.setMapKeyManyToManyColumns( mapJoinColumns );
+			}
 
 			//potential element
 			collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) );

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3Column.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3Column.java	2009-07-21 15:57:57 UTC (rev 17186)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3Column.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -336,6 +336,18 @@
 			PropertyData inferredData,
 			Map<String, Join> secondaryTables,
 			ExtendedMappings mappings
+			){
+		return buildColumnFromAnnotation(
+				anns,
+				formulaAnn, nullability, propertyHolder, inferredData, null, secondaryTables, mappings);
+	}
+	public static Ejb3Column[] buildColumnFromAnnotation(
+			javax.persistence.Column[] anns,
+			org.hibernate.annotations.Formula formulaAnn, Nullability nullability, PropertyHolder propertyHolder,
+			PropertyData inferredData,
+			String suffixForDefaultColumnName,
+			Map<String, Join> secondaryTables,
+			ExtendedMappings mappings
 	) {
 		Ejb3Column[] columns;
 		if ( formulaAnn != null ) {
@@ -361,7 +373,12 @@
 				log.debug( "Column(s) overridden for property {}", inferredData.getPropertyName() );
 			}
 			if ( actualCols == null ) {
-				columns = buildImplicitColumn( inferredData, secondaryTables, propertyHolder, nullability, mappings );
+				columns = buildImplicitColumn( inferredData,
+						suffixForDefaultColumnName,
+						secondaryTables,
+						propertyHolder,
+						nullability,
+						mappings );
 			}
 			else {
 				final int length = actualCols.length;
@@ -376,6 +393,12 @@
 					column.setPrecision( col.precision() );
 					column.setScale( col.scale() );
 					column.setLogicalColumnName( col.name() );
+					//support for explicit property name + suffix
+					if ( StringHelper.isEmpty( column.getLogicalColumnName() )
+						&& ! StringHelper.isEmpty( suffixForDefaultColumnName ) ) {
+						column.setLogicalColumnName( inferredData.getPropertyName() + suffixForDefaultColumnName );
+					}
+
 					column.setPropertyName(
 							BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
 					);
@@ -398,8 +421,12 @@
 	}
 
 	private static Ejb3Column[] buildImplicitColumn(
-			PropertyData inferredData, Map<String, Join> secondaryTables, PropertyHolder propertyHolder,
-			Nullability nullability, ExtendedMappings mappings
+			PropertyData inferredData,
+			String suffixForDefaultColumnName,
+			Map<String, Join> secondaryTables,
+			PropertyHolder propertyHolder,
+			Nullability nullability,
+			ExtendedMappings mappings
 	) {
 		Ejb3Column[] columns;
 		columns = new Ejb3Column[1];
@@ -412,12 +439,22 @@
 			column.setNullable( false );
 		}
 		column.setLength( DEFAULT_COLUMN_LENGTH );
+		final String propertyName = inferredData.getPropertyName();
 		column.setPropertyName(
-				BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
+				BinderHelper.getRelativePath( propertyHolder, propertyName )
 		);
 		column.setPropertyHolder( propertyHolder );
 		column.setJoins( secondaryTables );
 		column.setMappings( mappings );
+
+		// property name + suffix is an "explicit" column name
+		if ( !StringHelper.isEmpty( suffixForDefaultColumnName ) ) {
+			column.setLogicalColumnName( propertyName + suffixForDefaultColumnName );
+			column.setImplicit( false );
+		}
+		else {
+			column.setImplicit( true );
+		}
 		column.bind();
 		columns[0] = column;
 		return columns;

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java	2009-07-21 15:57:57 UTC (rev 17186)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -134,13 +134,31 @@
 			String propertyName,
 			ExtendedMappings mappings
 	) {
+		return buildJoinColumnsWithDefaultColumnSuffix(anns, mappedBy, joins, propertyHolder, propertyName, "", mappings);
+	}
+
+	public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix(
+			JoinColumn[] anns,
+			String mappedBy, Map<String, Join> joins,
+			PropertyHolder propertyHolder,
+			String propertyName,
+			String suffixForDefaultColumnName,
+			ExtendedMappings mappings
+	) {
 		JoinColumn[] actualColumns = propertyHolder.getOverriddenJoinColumn(
 				StringHelper.qualify( propertyHolder.getPath(), propertyName )
 		);
 		if ( actualColumns == null ) actualColumns = anns;
 		if ( actualColumns == null || actualColumns.length == 0 ) {
 			return new Ejb3JoinColumn[] {
-					buildJoinColumn( (JoinColumn) null, mappedBy, joins, propertyHolder, propertyName, mappings )
+					buildJoinColumn(
+							(JoinColumn) null,
+							mappedBy,
+							joins,
+							propertyHolder,
+							propertyName,
+							suffixForDefaultColumnName,
+							mappings )
 			};
 		}
 		else {
@@ -153,6 +171,7 @@
 						joins,
 						propertyHolder,
 						propertyName,
+						suffixForDefaultColumnName,
 						mappings
 				);
 			}
@@ -168,6 +187,7 @@
 			String mappedBy, Map<String, Join> joins,
 			PropertyHolder propertyHolder,
 			String propertyName,
+			String suffixForDefaultColumnName,
 			ExtendedMappings mappings
 	) {
 		if ( ann != null ) {
@@ -179,6 +199,10 @@
 			}
 			Ejb3JoinColumn joinColumn = new Ejb3JoinColumn();
 			joinColumn.setJoinAnnotation( ann, null );
+			if ( StringHelper.isEmpty( joinColumn.getLogicalColumnName() ) 
+				&& ! StringHelper.isEmpty( suffixForDefaultColumnName ) ) {
+				joinColumn.setLogicalColumnName( propertyName + suffixForDefaultColumnName );
+			}
 			joinColumn.setJoins( joins );
 			joinColumn.setPropertyHolder( propertyHolder );
 			joinColumn.setPropertyName( BinderHelper.getRelativePath( propertyHolder, propertyName ) );
@@ -192,8 +216,17 @@
 			joinColumn.setMappedBy( mappedBy );
 			joinColumn.setJoins( joins );
 			joinColumn.setPropertyHolder( propertyHolder );
-			joinColumn.setPropertyName( BinderHelper.getRelativePath( propertyHolder, propertyName ) );
-			joinColumn.setImplicit( true );
+			joinColumn.setPropertyName(
+					BinderHelper.getRelativePath( propertyHolder, propertyName )
+			);
+			// property name + suffix is an "explicit" column name
+			if ( !StringHelper.isEmpty( suffixForDefaultColumnName ) ) {
+				joinColumn.setLogicalColumnName( propertyName + suffixForDefaultColumnName );
+				joinColumn.setImplicit( false );
+			}
+			else {
+				joinColumn.setImplicit( true );
+			}
 			joinColumn.setMappings( mappings );
 			joinColumn.bind();
 			return joinColumn;

Added: core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/MapKeyJoinColumnDelegator.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/MapKeyJoinColumnDelegator.java	                        (rev 0)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/MapKeyJoinColumnDelegator.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -0,0 +1,54 @@
+package org.hibernate.cfg.annotations;
+
+import java.lang.annotation.Annotation;
+import javax.persistence.Column;
+import javax.persistence.MapKeyJoinColumn;
+import javax.persistence.JoinColumn;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at SuppressWarnings({ "ClassExplicitlyAnnotation" })
+public class MapKeyJoinColumnDelegator implements JoinColumn {
+	private final MapKeyJoinColumn column;
+
+	public MapKeyJoinColumnDelegator(MapKeyJoinColumn column) {
+		this.column = column;
+	}
+
+	public String name() {
+		return column.name();
+	}
+
+	public String referencedColumnName() {
+		return column.referencedColumnName();
+	}
+
+	public boolean unique() {
+		return column.unique();
+	}
+
+	public boolean nullable() {
+		return column.nullable();
+	}
+
+	public boolean insertable() {
+		return column.insertable();
+	}
+
+	public boolean updatable() {
+		return column.updatable();
+	}
+
+	public String columnDefinition() {
+		return column.columnDefinition();
+	}
+
+	public String table() {
+		return column.table();
+	}
+
+	public Class<? extends Annotation> annotationType() {
+		return Column.class;
+	}
+}

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/Atmosphere.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/Atmosphere.java	2009-07-21 15:57:57 UTC (rev 17186)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/Atmosphere.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -12,10 +12,10 @@
 import javax.persistence.JoinTable;
 import javax.persistence.JoinColumn;
 import javax.persistence.MapKeyColumn;
+import javax.persistence.MapKeyJoinColumn;
 
 import org.hibernate.annotations.MapKey;
 import org.hibernate.annotations.CollectionOfElements;
-import org.hibernate.annotations.MapKeyManyToMany;
 
 /**
  * @author Emmanuel Bernard
@@ -31,13 +31,31 @@
 	public Map<String, Gas> gases = new HashMap<String, Gas>();
 
 	@ManyToMany(cascade = CascadeType.ALL)
-	@MapKeyManyToMany(joinColumns = @JoinColumn(name="gas_id") )
+	@MapKeyJoinColumn(name="gas_id" )
 	@JoinTable(name = "Gas_per_key")
 	public Map<GasKey, Gas> gasesPerKey = new HashMap<GasKey, Gas>();
 
 	@CollectionOfElements //TODO migrate to @ElementCollection ;  @MapKeyManyToMany ??
 	@Column(name="composition_rate")
-	@MapKeyManyToMany(joinColumns = @JoinColumn(name="gas_id"))
+	@MapKeyJoinColumn(name="gas_id" )
 	@JoinTable(name = "Composition", joinColumns = @JoinColumn(name = "atmosphere_id"))
 	public Map<Gas, Double> composition = new HashMap<Gas, Double>();
+
+	//use default JPA 2 column name for map key
+	@ManyToMany(cascade = CascadeType.ALL)
+	@MapKeyColumn
+	@JoinTable(name="Atm_Gas_Def")
+	public Map<String, Gas> gasesDef = new HashMap<String, Gas>();
+
+	//use default HAN legacy column name for map key
+	@ManyToMany(cascade = CascadeType.ALL)
+	@MapKey
+	@JoinTable(name="Atm_Gas_DefLeg")
+	public Map<String, Gas> gasesDefLeg = new HashMap<String, Gas>();
+
+	@ManyToMany(cascade = CascadeType.ALL)
+	@MapKeyJoinColumn
+	@JoinTable(name = "Gas_p_key_def")
+	public Map<GasKey, Gas> gasesPerKeyDef = new HashMap<GasKey, Gas>();
+
 }

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java	2009-07-21 15:57:57 UTC (rev 17186)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -5,10 +5,14 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Iterator;
 
 import org.hibernate.Session;
 import org.hibernate.Transaction;
 import org.hibernate.Hibernate;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
 import org.hibernate.dialect.HSQLDialect;
 import org.hibernate.test.annotations.RequiresDialect;
 import org.hibernate.test.annotations.TestCase;
@@ -19,6 +23,35 @@
  * @author Emmanuel Bernard
  */
 public class IndexedCollectionTest extends TestCase {
+
+	public void testJPA2DefaultMapColumns() throws Exception {
+		isDefaultKeyColumnPresent( "gasesDef" );
+		isDefaultKeyColumnPresent( "gasesPerKeyDef" );
+		isNotDefaultKeyColumnPresent( "gasesDefLeg" );
+	}
+
+	private void isDefaultKeyColumnPresent(String propertyName) {
+		final Collection collection = getCfg().getCollectionMapping( Atmosphere.class.getName() + "." + propertyName );
+		final Iterator columnIterator = collection.getCollectionTable().getColumnIterator();
+		boolean hasDefault = false;
+		while ( columnIterator.hasNext() ) {
+			Column column = (Column) columnIterator.next();
+			if ( (propertyName + "_KEY").equals( column.getName() ) ) hasDefault = true;
+		}
+		assertTrue( "Could not find " + propertyName + "_KEY", hasDefault);
+	}
+
+	private void isNotDefaultKeyColumnPresent(String propertyName) {
+		final Collection collection = getCfg().getCollectionMapping( Atmosphere.class.getName() + "." + propertyName );
+		final Iterator columnIterator = collection.getCollectionTable().getColumnIterator();
+		boolean hasDefault = false;
+		while ( columnIterator.hasNext() ) {
+			Column column = (Column) columnIterator.next();
+			if ( (propertyName + "_KEY").equals( column.getName() ) ) hasDefault = true;
+		}
+		assertFalse( "Could not find " + propertyName + "_KEY", hasDefault);
+	}
+
 	public void testFkList() throws Exception {
 		Wardrobe w = new Wardrobe();
 		Drawer d1 = new Drawer();

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/target/Brand.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/target/Brand.java	2009-07-21 15:57:57 UTC (rev 17186)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/target/Brand.java	2009-07-22 00:16:59 UTC (rev 17187)
@@ -9,6 +9,7 @@
 import javax.persistence.Id;
 import javax.persistence.ManyToMany;
 import javax.persistence.MapKeyClass;
+import javax.persistence.JoinColumn;
 
 import org.hibernate.annotations.MapKey;
 import org.hibernate.annotations.MapKeyManyToMany;
@@ -27,8 +28,8 @@
 	private Map<Size, Luggage> luggagesBySize = new HashMap<Size, Luggage>();
 
 	@ElementCollection(targetClass = SizeImpl.class)
-	@MapKeyManyToMany(targetEntity = LuggageImpl.class)
-	//TODO @MapKeyClass(LuggageImpl.class)
+	@MapKeyClass(LuggageImpl.class)
+	@MapKeyManyToMany //legacy column name: was never officially supported BTW
 	private Map<Luggage, Size> sizePerLuggage = new HashMap<Luggage, Size>();
 
 



More information about the hibernate-commits mailing list