[hibernate-commits] Hibernate SVN: r18656 - in core/trunk/annotations/src: test/java/org/hibernate/test/annotations/derivedidentities/e1/b and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Jan 27 13:58:28 EST 2010


Author: epbernard
Date: 2010-01-27 13:58:28 -0500 (Wed, 27 Jan 2010)
New Revision: 18656

Modified:
   core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java
   core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/b/DerivedIdentitySimpleParentEmbeddedIdDepTest.java
Log:
HHH-4858 add implicit PERSIST cascade when @MapsId is present

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-27 18:46:51 UTC (rev 18655)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java	2010-01-27 18:58:28 UTC (rev 18656)
@@ -1328,479 +1328,482 @@
 					( (SimpleValue) rootClass.getVersion().getValue() ).getNullValue()
 			);
 		}
-		else if ( property.isAnnotationPresent( ManyToOne.class ) ) {
-			ManyToOne ann = property.getAnnotation( ManyToOne.class );
+		else {
+			final boolean isMapsId = property.isAnnotationPresent( MapsId.class );
+			if ( property.isAnnotationPresent( ManyToOne.class ) ) {
+				ManyToOne ann = property.getAnnotation( ManyToOne.class );
 
-			//check validity
-			if ( property.isAnnotationPresent( Column.class )
-					|| property.isAnnotationPresent( Columns.class ) ) {
-				throw new AnnotationException( "@Column(s) not allowed on a @ManyToOne property: "
-						+ BinderHelper.getPath( propertyHolder, inferredData ) );
-			}
+				//check validity
+				if ( property.isAnnotationPresent( Column.class )
+						|| property.isAnnotationPresent( Columns.class ) ) {
+					throw new AnnotationException( "@Column(s) not allowed on a @ManyToOne property: "
+							+ BinderHelper.getPath( propertyHolder, inferredData ) );
+				}
 
-			Cascade hibernateCascade = property.getAnnotation( Cascade.class );
-			NotFound notFound = property.getAnnotation( NotFound.class );
-			boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
-			OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
-			boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
-			JoinTable assocTable = propertyHolder.getJoinTable( property );
-			if ( assocTable != null ) {
-				Join join = propertyHolder.addJoin( assocTable, false );
-				for (Ejb3JoinColumn joinColumn : joinColumns) {
-					joinColumn.setSecondaryTableName( join.getTable().getName() );
+				Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+				NotFound notFound = property.getAnnotation( NotFound.class );
+				boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
+				OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+				boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+				JoinTable assocTable = propertyHolder.getJoinTable( property );
+				if ( assocTable != null ) {
+					Join join = propertyHolder.addJoin( assocTable, false );
+					for (Ejb3JoinColumn joinColumn : joinColumns) {
+						joinColumn.setSecondaryTableName( join.getTable().getName() );
+					}
 				}
+				final boolean mandatory = !ann.optional() || isMapsId;
+				bindManyToOne(
+						getCascadeStrategy( ann.cascade(), hibernateCascade, false, isMapsId),
+						joinColumns,
+						!mandatory,
+						ignoreNotFound, onDeleteCascade,
+						ToOneBinder.getTargetEntity( inferredData, mappings ),
+						propertyHolder,
+						inferredData, false, isIdentifierMapper,
+						inSecondPass, propertyBinder, mappings
+				);
 			}
-			final boolean mandatory = !ann.optional() || property.isAnnotationPresent( MapsId.class );
-			bindManyToOne(
-					getCascadeStrategy( ann.cascade(), hibernateCascade, false),
-					joinColumns,
-					!mandatory,
-					ignoreNotFound, onDeleteCascade,
-					ToOneBinder.getTargetEntity( inferredData, mappings ),
-					propertyHolder,
-					inferredData, false, isIdentifierMapper,
-					inSecondPass, propertyBinder, mappings
-			);
-		}
-		else if ( property.isAnnotationPresent( OneToOne.class ) ) {
-			OneToOne ann = property.getAnnotation( OneToOne.class );
+			else if ( property.isAnnotationPresent( OneToOne.class ) ) {
+				OneToOne ann = property.getAnnotation( OneToOne.class );
 
-			//check validity
-			if ( property.isAnnotationPresent( Column.class )
-					|| property.isAnnotationPresent( Columns.class ) ) {
-				throw new AnnotationException( "@Column(s) not allowed on a @OneToOne property: "
-						+ BinderHelper.getPath( propertyHolder, inferredData ) );
-			}
-
-			//FIXME support a proper PKJCs
-			boolean trueOneToOne = property.isAnnotationPresent( PrimaryKeyJoinColumn.class )
-					|| property.isAnnotationPresent( PrimaryKeyJoinColumns.class );
-			Cascade hibernateCascade = property.getAnnotation( Cascade.class );
-			NotFound notFound = property.getAnnotation( NotFound.class );
-			boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
-			OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
-			boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
-			JoinTable assocTable = propertyHolder.getJoinTable( property );
-			if ( assocTable != null ) {
-				Join join = propertyHolder.addJoin( assocTable, false );
-				for (Ejb3JoinColumn joinColumn : joinColumns) {
-					joinColumn.setSecondaryTableName( join.getTable().getName() );
+				//check validity
+				if ( property.isAnnotationPresent( Column.class )
+						|| property.isAnnotationPresent( Columns.class ) ) {
+					throw new AnnotationException( "@Column(s) not allowed on a @OneToOne property: "
+							+ BinderHelper.getPath( propertyHolder, inferredData ) );
 				}
-			}
-			//MapsId means the columns belong to the pk => not null
-			final boolean mandatory = !ann.optional() || property.isAnnotationPresent( MapsId.class );
-			bindOneToOne(
-					getCascadeStrategy( ann.cascade(), hibernateCascade, ann.orphanRemoval()),
-					joinColumns,
-					!mandatory,
-					getFetchMode( ann.fetch() ),
-					ignoreNotFound, onDeleteCascade,
-					ToOneBinder.getTargetEntity( inferredData, mappings ),
-					propertyHolder,
-					inferredData,
-					ann.mappedBy(),
-					trueOneToOne,
-					isIdentifierMapper,
-					inSecondPass,
-					propertyBinder,
-					mappings
-			);
-		}
-		else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
 
-			//check validity
-			if ( property.isAnnotationPresent( Column.class )
-					|| property.isAnnotationPresent( Columns.class ) ) {
-				throw new AnnotationException( "@Column(s) not allowed on a @Any property: "
-						+ BinderHelper.getPath( propertyHolder, inferredData ) );
-			}
-
-			Cascade hibernateCascade = property.getAnnotation( Cascade.class );
-			OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
-			boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
-			JoinTable assocTable = propertyHolder.getJoinTable( property );
-			if ( assocTable != null ) {
-				Join join = propertyHolder.addJoin( assocTable, false );
-				for (Ejb3JoinColumn joinColumn : joinColumns) {
-					joinColumn.setSecondaryTableName( join.getTable().getName() );
+				//FIXME support a proper PKJCs
+				boolean trueOneToOne = property.isAnnotationPresent( PrimaryKeyJoinColumn.class )
+						|| property.isAnnotationPresent( PrimaryKeyJoinColumns.class );
+				Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+				NotFound notFound = property.getAnnotation( NotFound.class );
+				boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
+				OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+				boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+				JoinTable assocTable = propertyHolder.getJoinTable( property );
+				if ( assocTable != null ) {
+					Join join = propertyHolder.addJoin( assocTable, false );
+					for (Ejb3JoinColumn joinColumn : joinColumns) {
+						joinColumn.setSecondaryTableName( join.getTable().getName() );
+					}
 				}
-			}
-			bindAny( getCascadeStrategy( null, hibernateCascade, false), //@Any has not cascade attribute
-					joinColumns, onDeleteCascade, nullability,
-					propertyHolder, inferredData, entityBinder,
-					isIdentifierMapper, mappings );
-		}
-		else if ( property.isAnnotationPresent( OneToMany.class )
-				|| property.isAnnotationPresent( ManyToMany.class )
-				|| property.isAnnotationPresent( CollectionOfElements.class ) //legacy Hibernate
-				|| property.isAnnotationPresent( ElementCollection.class )
-				|| property.isAnnotationPresent( ManyToAny.class ) ) {
-			OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
-			ManyToMany manyToManyAnn = property.getAnnotation( ManyToMany.class );
-			ElementCollection elementCollectionAnn = property.getAnnotation( ElementCollection.class );
-			CollectionOfElements collectionOfElementsAnn = property.getAnnotation( CollectionOfElements.class ); //legacy hibernate
-
-			final IndexColumn indexColumn;
-
-			if ( property.isAnnotationPresent( OrderColumn.class ) ) {
-				indexColumn = IndexColumn.buildColumnFromAnnotation(
-						property.getAnnotation(OrderColumn.class),
+				//MapsId means the columns belong to the pk => not null
+				final boolean mandatory = !ann.optional() || isMapsId;
+				bindOneToOne(
+						getCascadeStrategy( ann.cascade(), hibernateCascade, ann.orphanRemoval(), isMapsId),
+						joinColumns,
+						!mandatory,
+						getFetchMode( ann.fetch() ),
+						ignoreNotFound, onDeleteCascade,
+						ToOneBinder.getTargetEntity( inferredData, mappings ),
 						propertyHolder,
 						inferredData,
-						entityBinder.getSecondaryTables(),
+						ann.mappedBy(),
+						trueOneToOne,
+						isIdentifierMapper,
+						inSecondPass,
+						propertyBinder,
 						mappings
 				);
 			}
-			else {
-				//if @IndexColumn is not there, the generated IndexColumn is an implicit column and not used.
-				//so we can leave the legacy processing as the default
-				indexColumn = IndexColumn.buildColumnFromAnnotation(
-						property.getAnnotation(org.hibernate.annotations.IndexColumn.class),
-						propertyHolder,
-						inferredData,
-						mappings
-				);
-			}
-			CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(
-					propertyHolder.getEntityName(),
-					property,
-					!indexColumn.isImplicit(),
-					property.isAnnotationPresent( CollectionOfElements.class )
-					|| property.isAnnotationPresent( org.hibernate.annotations.MapKey.class )
-							// || property.isAnnotationPresent( ManyToAny.class )
-			);
-			collectionBinder.setIndexColumn( indexColumn );
-			MapKey mapKeyAnn = property.getAnnotation( MapKey.class );
-			collectionBinder.setMapKey( mapKeyAnn );
-			collectionBinder.setPropertyName( inferredData.getPropertyName() );
-			BatchSize batchAnn = property.getAnnotation( BatchSize.class );
-			collectionBinder.setBatchSize( batchAnn );
-			javax.persistence.OrderBy ejb3OrderByAnn = property.getAnnotation( javax.persistence.OrderBy.class );
-			OrderBy orderByAnn = property.getAnnotation( OrderBy.class );
-			collectionBinder.setEjb3OrderBy( ejb3OrderByAnn );
-			collectionBinder.setSqlOrderBy( orderByAnn );
-			Sort sortAnn = property.getAnnotation( Sort.class );
-			collectionBinder.setSort( sortAnn );
-			Cache cachAnn = property.getAnnotation( Cache.class );
-			collectionBinder.setCache( cachAnn );
-			collectionBinder.setPropertyHolder( propertyHolder );
-			Cascade hibernateCascade = property.getAnnotation( Cascade.class );
-			NotFound notFound = property.getAnnotation( NotFound.class );
-			boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
-			collectionBinder.setIgnoreNotFound( ignoreNotFound );
-			collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
-			collectionBinder.setMappings( mappings );
-			collectionBinder.setAccessType( inferredData.getDefaultAccess() );
+			else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
 
-			Ejb3Column[] elementColumns;
-			//do not use "element" if you are a JPA 2 @ElementCollection only for legacy Hibernate mappings
-			boolean isJPA2ForValueMapping = property.isAnnotationPresent( ElementCollection.class );
-			PropertyData virtualProperty = isJPA2ForValueMapping ? inferredData : new WrappedInferredData( inferredData, "element" );
-			if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent(
-					Formula.class
-			) ) {
-				Column ann = property.getAnnotation( Column.class );
-				Formula formulaAnn = property.getAnnotation( Formula.class );
-				elementColumns = Ejb3Column.buildColumnFromAnnotation(
-						new Column[] { ann },
-						formulaAnn,
-						nullability,
-						propertyHolder,
-						virtualProperty,
-						entityBinder.getSecondaryTables(),
-						mappings
-				);
-			}
-			else if ( property.isAnnotationPresent( Columns.class ) ) {
-				Columns anns = property.getAnnotation( Columns.class );
-				elementColumns = Ejb3Column.buildColumnFromAnnotation(
-						anns.columns(), null, nullability, propertyHolder, virtualProperty,
-						entityBinder.getSecondaryTables(), mappings
-				);
-			}
-			else {
-				elementColumns = Ejb3Column.buildColumnFromAnnotation(
-						null,
-						null,
-						nullability,
-						propertyHolder,
-						virtualProperty,
-						entityBinder.getSecondaryTables(),
-						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 ) ) };
+				//check validity
+				if ( property.isAnnotationPresent( Column.class )
+						|| property.isAnnotationPresent( Columns.class ) ) {
+					throw new AnnotationException( "@Column(s) not allowed on a @Any property: "
+							+ BinderHelper.getPath( propertyHolder, inferredData ) );
 				}
-				else if ( property.isAnnotationPresent( org.hibernate.annotations.MapKey.class ) ) {
-					if ( isJPA2 == null) {
-						isJPA2 = Boolean.FALSE;
+
+				Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+				OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+				boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+				JoinTable assocTable = propertyHolder.getJoinTable( property );
+				if ( assocTable != null ) {
+					Join join = propertyHolder.addJoin( assocTable, false );
+					for (Ejb3JoinColumn joinColumn : joinColumns) {
+						joinColumn.setSecondaryTableName( join.getTable().getName() );
 					}
-					keyColumns = property.getAnnotation( org.hibernate.annotations.MapKey.class ).columns();
 				}
+				bindAny( getCascadeStrategy( null, hibernateCascade, false, isMapsId), //@Any has not cascade attribute
+						joinColumns, onDeleteCascade, nullability,
+						propertyHolder, inferredData, entityBinder,
+						isIdentifierMapper, mappings );
+			}
+			else if ( property.isAnnotationPresent( OneToMany.class )
+					|| property.isAnnotationPresent( ManyToMany.class )
+					|| property.isAnnotationPresent( CollectionOfElements.class ) //legacy Hibernate
+					|| property.isAnnotationPresent( ElementCollection.class )
+					|| property.isAnnotationPresent( ManyToAny.class ) ) {
+				OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
+				ManyToMany manyToManyAnn = property.getAnnotation( ManyToMany.class );
+				ElementCollection elementCollectionAnn = property.getAnnotation( ElementCollection.class );
+				CollectionOfElements collectionOfElementsAnn = property.getAnnotation( CollectionOfElements.class ); //legacy hibernate
 
-				//not explicitly legacy
-				if ( isJPA2 == null) {
-					isJPA2 = Boolean.TRUE;
+				final IndexColumn indexColumn;
+
+				if ( property.isAnnotationPresent( OrderColumn.class ) ) {
+					indexColumn = IndexColumn.buildColumnFromAnnotation(
+							property.getAnnotation(OrderColumn.class),
+							propertyHolder,
+							inferredData,
+							entityBinder.getSecondaryTables(),
+							mappings
+					);
 				}
+				else {
+					//if @IndexColumn is not there, the generated IndexColumn is an implicit column and not used.
+					//so we can leave the legacy processing as the default
+					indexColumn = IndexColumn.buildColumnFromAnnotation(
+							property.getAnnotation(org.hibernate.annotations.IndexColumn.class),
+							propertyHolder,
+							inferredData,
+							mappings
+					);
+				}
+				CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(
+						propertyHolder.getEntityName(),
+						property,
+						!indexColumn.isImplicit(),
+						property.isAnnotationPresent( CollectionOfElements.class )
+						|| property.isAnnotationPresent( org.hibernate.annotations.MapKey.class )
+								// || property.isAnnotationPresent( ManyToAny.class )
+				);
+				collectionBinder.setIndexColumn( indexColumn );
+				MapKey mapKeyAnn = property.getAnnotation( MapKey.class );
+				collectionBinder.setMapKey( mapKeyAnn );
+				collectionBinder.setPropertyName( inferredData.getPropertyName() );
+				BatchSize batchAnn = property.getAnnotation( BatchSize.class );
+				collectionBinder.setBatchSize( batchAnn );
+				javax.persistence.OrderBy ejb3OrderByAnn = property.getAnnotation( javax.persistence.OrderBy.class );
+				OrderBy orderByAnn = property.getAnnotation( OrderBy.class );
+				collectionBinder.setEjb3OrderBy( ejb3OrderByAnn );
+				collectionBinder.setSqlOrderBy( orderByAnn );
+				Sort sortAnn = property.getAnnotation( Sort.class );
+				collectionBinder.setSort( sortAnn );
+				Cache cachAnn = property.getAnnotation( Cache.class );
+				collectionBinder.setCache( cachAnn );
+				collectionBinder.setPropertyHolder( propertyHolder );
+				Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+				NotFound notFound = property.getAnnotation( NotFound.class );
+				boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
+				collectionBinder.setIgnoreNotFound( ignoreNotFound );
+				collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
+				collectionBinder.setMappings( mappings );
+				collectionBinder.setAccessType( inferredData.getDefaultAccess() );
 
-				//nullify empty array
-				keyColumns = keyColumns != null && keyColumns.length > 0 ? keyColumns : null;
-
-				//"mapkey" is the legacy column name of the key column pre JPA 2
-				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 );
-			}
-			{
-				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++;
+				Ejb3Column[] elementColumns;
+				//do not use "element" if you are a JPA 2 @ElementCollection only for legacy Hibernate mappings
+				boolean isJPA2ForValueMapping = property.isAnnotationPresent( ElementCollection.class );
+				PropertyData virtualProperty = isJPA2ForValueMapping ? inferredData : new WrappedInferredData( inferredData, "element" );
+				if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent(
+						Formula.class
+				) ) {
+					Column ann = property.getAnnotation( Column.class );
+					Formula formulaAnn = property.getAnnotation( Formula.class );
+					elementColumns = Ejb3Column.buildColumnFromAnnotation(
+							new Column[] { ann },
+							formulaAnn,
+							nullability,
+							propertyHolder,
+							virtualProperty,
+							entityBinder.getSecondaryTables(),
+							mappings
+					);
+				}
+				else if ( property.isAnnotationPresent( Columns.class ) ) {
+					Columns anns = property.getAnnotation( Columns.class );
+					elementColumns = Ejb3Column.buildColumnFromAnnotation(
+							anns.columns(), null, nullability, propertyHolder, virtualProperty,
+							entityBinder.getSecondaryTables(), mappings
+					);
+				}
+				else {
+					elementColumns = Ejb3Column.buildColumnFromAnnotation(
+							null,
+							null,
+							nullability,
+							propertyHolder,
+							virtualProperty,
+							entityBinder.getSecondaryTables(),
+							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 ) ) };
 					}
-					if ( joinKeyColumns != null ) {
-						throw new AnnotationException( "@MapKeyJoinColumn and @MapKeyJoinColumns used on the same property: "
-								+ BinderHelper.getPath( propertyHolder, inferredData ) );
+					else if ( property.isAnnotationPresent( org.hibernate.annotations.MapKey.class ) ) {
+						if ( isJPA2 == null) {
+							isJPA2 = Boolean.FALSE;
+						}
+						keyColumns = property.getAnnotation( org.hibernate.annotations.MapKey.class ).columns();
 					}
-				}
-				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 ) ) {
+
+					//not explicitly legacy
 					if ( isJPA2 == null) {
-						isJPA2 = Boolean.FALSE;
+						isJPA2 = Boolean.TRUE;
 					}
-					joinKeyColumns = property.getAnnotation( org.hibernate.annotations.MapKeyManyToMany.class ).joinColumns();
-				}
 
-				//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" );
-				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 ) );
-			collectionBinder.setElementColumns( elementColumns );
-			collectionBinder.setProperty( property );
-
-			//TODO enhance exception with @ManyToAny and @CollectionOfElements
-			if ( oneToManyAnn != null && manyToManyAnn != null ) {
-				throw new AnnotationException(
-						"@OneToMany and @ManyToMany on the same property is not allowed: "
-								+ propertyHolder.getEntityName() + "." + inferredData.getPropertyName()
-				);
-			}
-			String mappedBy = null;
-			if ( oneToManyAnn != null ) {
-				for (Ejb3JoinColumn column : joinColumns) {
-					if ( column.isSecondary() ) {
-						throw new NotYetImplementedException( "Collections having FK in secondary table" );
-					}
+					//"mapkey" is the legacy column name of the key column pre JPA 2
+					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 );
 				}
-				collectionBinder.setFkJoinColumns( joinColumns );
-				mappedBy = oneToManyAnn.mappedBy();
-				collectionBinder.setTargetEntity(
-						mappings.getReflectionManager().toXClass( oneToManyAnn.targetEntity() )
-				);
-				collectionBinder.setCascadeStrategy(
-						getCascadeStrategy( oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval()) );
-				collectionBinder.setOneToMany( true );
-			}
-			else if ( elementCollectionAnn != null
-					|| collectionOfElementsAnn != null //Hibernate legacy
-					) {
-				for (Ejb3JoinColumn column : joinColumns) {
-					if ( column.isSecondary() ) {
-						throw new NotYetImplementedException( "Collections having FK in secondary table" );
+				{
+					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: "
+									+ BinderHelper.getPath( propertyHolder, inferredData ) );
+						}
 					}
-				}
-				collectionBinder.setFkJoinColumns( joinColumns );
-				mappedBy = "";
-				final Class<?> targetElement = elementCollectionAnn != null ?
-						elementCollectionAnn.targetClass() :
-						collectionOfElementsAnn.targetElement();
-				collectionBinder.setTargetEntity(
-						mappings.getReflectionManager().toXClass( targetElement )
-				);
-				//collectionBinder.setCascadeStrategy( getCascadeStrategy( embeddedCollectionAnn.cascade(), hibernateCascade ) );
-				collectionBinder.setOneToMany( true );
-			}
-			else if ( manyToManyAnn != null ) {
-				mappedBy = manyToManyAnn.mappedBy();
-				collectionBinder.setTargetEntity(
-						mappings.getReflectionManager().toXClass( manyToManyAnn.targetEntity() )
-				);
-				collectionBinder.setCascadeStrategy( getCascadeStrategy( manyToManyAnn.cascade(), hibernateCascade, false) );
-				collectionBinder.setOneToMany( false );
-			}
-			else if ( property.isAnnotationPresent( ManyToAny.class ) ) {
-				mappedBy = "";
-				collectionBinder.setTargetEntity(
-						mappings.getReflectionManager().toXClass( void.class )
-				);
-				collectionBinder.setCascadeStrategy( getCascadeStrategy( null, hibernateCascade, false) );
-				collectionBinder.setOneToMany( false );
-			}
-			collectionBinder.setMappedBy( mappedBy );
+					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();
+					}
 
-			bindJoinedTableAssociation(
-					property, mappings, entityBinder, collectionBinder, propertyHolder, inferredData, mappedBy
-			);
+					//not explicitly legacy
+					if ( isJPA2 == null) {
+						isJPA2 = Boolean.TRUE;
+					}
 
-			OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
-			boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
-			collectionBinder.setCascadeDeleteEnabled( onDeleteCascade );
-			if ( isIdentifierMapper ) {
-				collectionBinder.setInsertable( false );
-				collectionBinder.setUpdatable( false );
-			}
-			if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary
-				HashMap<String, IdGenerator> localGenerators = (HashMap<String, IdGenerator>) classGenerators.clone();
-				localGenerators.putAll( buildLocalGenerators( property, mappings ) );
-				collectionBinder.setLocalGenerators( localGenerators );
+					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 );
+				}
 
-			}
-			collectionBinder.setInheritanceStatePerClass( inheritanceStatePerClass );
-			collectionBinder.setDeclaringClass( inferredData.getDeclaringClass() );
-			collectionBinder.bind();
+				//potential element
+				collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) );
+				collectionBinder.setElementColumns( elementColumns );
+				collectionBinder.setProperty( property );
 
-		}
-		//Either a regular property or a basic @Id or @EmbeddedId while not ignoring id annotations
-		else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) {
-			//define whether the type is a component or not
-			boolean isComponent;
-			isComponent = property.isAnnotationPresent( Embedded.class )
-					|| property.isAnnotationPresent( EmbeddedId.class )
-					|| returnedClass.isAnnotationPresent( Embeddable.class );
-
-			//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() ) {
-				Ejb3Column[] oldColumns = columns;
-				columns = columnsBuilder.overrideColumnFromMapsIdProperty(isId);
-				isOverridden = oldColumns != columns;
-			}
-			if ( isComponent ) {
-				String referencedEntityName = null;
-				if (isOverridden) {
-					final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
-							isId, propertyHolder, property.getName(), mappings
+				//TODO enhance exception with @ManyToAny and @CollectionOfElements
+				if ( oneToManyAnn != null && manyToManyAnn != null ) {
+					throw new AnnotationException(
+							"@OneToMany and @ManyToMany on the same property is not allowed: "
+									+ propertyHolder.getEntityName() + "." + inferredData.getPropertyName()
 					);
-					referencedEntityName = mapsIdProperty.getClassOrElementName();
 				}
-				AccessType propertyAccessor = entityBinder.getPropertyAccessor( property );
-				propertyBinder = bindComponent(
-						inferredData,
-						propertyHolder,
-						propertyAccessor,
-						entityBinder,
-						isIdentifierMapper,
-						mappings,
-						isComponentEmbedded,
-						isId,
-						inheritanceStatePerClass,
-						referencedEntityName,
-						isOverridden ? (Ejb3JoinColumn[]) columns : null
-				);
-			}
-			else {
-				//provide the basic property mapping
-				boolean optional = true;
-				boolean lazy = false;
-				if ( property.isAnnotationPresent( Basic.class ) ) {
-					Basic ann = property.getAnnotation( Basic.class );
-					optional = ann.optional();
-					lazy = ann.fetch() == FetchType.LAZY;
+				String mappedBy = null;
+				if ( oneToManyAnn != null ) {
+					for (Ejb3JoinColumn column : joinColumns) {
+						if ( column.isSecondary() ) {
+							throw new NotYetImplementedException( "Collections having FK in secondary table" );
+						}
+					}
+					collectionBinder.setFkJoinColumns( joinColumns );
+					mappedBy = oneToManyAnn.mappedBy();
+					collectionBinder.setTargetEntity(
+							mappings.getReflectionManager().toXClass( oneToManyAnn.targetEntity() )
+					);
+					collectionBinder.setCascadeStrategy(
+							getCascadeStrategy( oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval(), false) );
+					collectionBinder.setOneToMany( true );
 				}
-				//implicit type will check basic types and Serializable classes
-				if ( isId || ( !optional && nullability != Nullability.FORCED_NULL ) ) {
-					//force columns to not null
-					for (Ejb3Column col : columns) {
-						col.forceNotNull();
+				else if ( elementCollectionAnn != null
+						|| collectionOfElementsAnn != null //Hibernate legacy
+						) {
+					for (Ejb3JoinColumn column : joinColumns) {
+						if ( column.isSecondary() ) {
+							throw new NotYetImplementedException( "Collections having FK in secondary table" );
+						}
 					}
+					collectionBinder.setFkJoinColumns( joinColumns );
+					mappedBy = "";
+					final Class<?> targetElement = elementCollectionAnn != null ?
+							elementCollectionAnn.targetClass() :
+							collectionOfElementsAnn.targetElement();
+					collectionBinder.setTargetEntity(
+							mappings.getReflectionManager().toXClass( targetElement )
+					);
+					//collectionBinder.setCascadeStrategy( getCascadeStrategy( embeddedCollectionAnn.cascade(), hibernateCascade ) );
+					collectionBinder.setOneToMany( true );
 				}
-
-				propertyBinder.setLazy( lazy );
-				propertyBinder.setColumns( columns );
-				if (isOverridden) {
-					final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
-							isId, propertyHolder, property.getName(), mappings
+				else if ( manyToManyAnn != null ) {
+					mappedBy = manyToManyAnn.mappedBy();
+					collectionBinder.setTargetEntity(
+							mappings.getReflectionManager().toXClass( manyToManyAnn.targetEntity() )
 					);
-					propertyBinder.setReferencedEntityName( mapsIdProperty.getClassOrElementName() );
+					collectionBinder.setCascadeStrategy( getCascadeStrategy( manyToManyAnn.cascade(), hibernateCascade, false, false) );
+					collectionBinder.setOneToMany( false );
 				}
+				else if ( property.isAnnotationPresent( ManyToAny.class ) ) {
+					mappedBy = "";
+					collectionBinder.setTargetEntity(
+							mappings.getReflectionManager().toXClass( void.class )
+					);
+					collectionBinder.setCascadeStrategy( getCascadeStrategy( null, hibernateCascade, false, false) );
+					collectionBinder.setOneToMany( false );
+				}
+				collectionBinder.setMappedBy( mappedBy );
 
-				propertyBinder.makePropertyValueAndBind();
+				bindJoinedTableAssociation(
+						property, mappings, entityBinder, collectionBinder, propertyHolder, inferredData, mappedBy
+				);
 
-			}
-			if (isOverridden) {
-					final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
-							isId, propertyHolder, property.getName(), mappings
-					);
+				OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+				boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+				collectionBinder.setCascadeDeleteEnabled( onDeleteCascade );
+				if ( isIdentifierMapper ) {
+					collectionBinder.setInsertable( false );
+					collectionBinder.setUpdatable( false );
+				}
+				if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary
 					HashMap<String, IdGenerator> localGenerators = (HashMap<String, IdGenerator>) classGenerators.clone();
-					final IdGenerator foreignGenerator = new IdGenerator();
-					foreignGenerator.setIdentifierGeneratorStrategy( "assigned" );
-					foreignGenerator.setName( "Hibernate-local--foreign generator" );
-					foreignGenerator.setIdentifierGeneratorStrategy( "foreign" );
-					foreignGenerator.addParam( "property", mapsIdProperty.getPropertyName() );
-					localGenerators.put( foreignGenerator.getName(), foreignGenerator );
+					localGenerators.putAll( buildLocalGenerators( property, mappings ) );
+					collectionBinder.setLocalGenerators( localGenerators );
 
-					BinderHelper.makeIdGenerator(
-							(SimpleValue) propertyBinder.getValue(),
-							foreignGenerator.getIdentifierGeneratorStrategy(),
-							foreignGenerator.getName(),
-							mappings,
-							localGenerators
-					);
 				}
-			if (isId) {
-				//components and regular basic types create SimpleValue objects
-				final SimpleValue value = ( SimpleValue ) propertyBinder.getValue();
-				if ( !isOverridden ) {
-					processId(
+				collectionBinder.setInheritanceStatePerClass( inheritanceStatePerClass );
+				collectionBinder.setDeclaringClass( inferredData.getDeclaringClass() );
+				collectionBinder.bind();
+
+			}
+			//Either a regular property or a basic @Id or @EmbeddedId while not ignoring id annotations
+			else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) {
+				//define whether the type is a component or not
+				boolean isComponent;
+				isComponent = property.isAnnotationPresent( Embedded.class )
+						|| property.isAnnotationPresent( EmbeddedId.class )
+						|| returnedClass.isAnnotationPresent( Embeddable.class );
+
+				//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() ) {
+					Ejb3Column[] oldColumns = columns;
+					columns = columnsBuilder.overrideColumnFromMapsIdProperty(isId);
+					isOverridden = oldColumns != columns;
+				}
+				if ( isComponent ) {
+					String referencedEntityName = null;
+					if (isOverridden) {
+						final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
+								isId, propertyHolder, property.getName(), mappings
+						);
+						referencedEntityName = mapsIdProperty.getClassOrElementName();
+					}
+					AccessType propertyAccessor = entityBinder.getPropertyAccessor( property );
+					propertyBinder = bindComponent(
+							inferredData,
 							propertyHolder,
-							inferredData,
-							value,
-							classGenerators,
+							propertyAccessor,
+							entityBinder,
 							isIdentifierMapper,
-							mappings
+							mappings,
+							isComponentEmbedded,
+							isId,
+							inheritanceStatePerClass,
+							referencedEntityName,
+							isOverridden ? (Ejb3JoinColumn[]) columns : null
 					);
 				}
+				else {
+					//provide the basic property mapping
+					boolean optional = true;
+					boolean lazy = false;
+					if ( property.isAnnotationPresent( Basic.class ) ) {
+						Basic ann = property.getAnnotation( Basic.class );
+						optional = ann.optional();
+						lazy = ann.fetch() == FetchType.LAZY;
+					}
+					//implicit type will check basic types and Serializable classes
+					if ( isId || ( !optional && nullability != Nullability.FORCED_NULL ) ) {
+						//force columns to not null
+						for (Ejb3Column col : columns) {
+							col.forceNotNull();
+						}
+					}
+
+					propertyBinder.setLazy( lazy );
+					propertyBinder.setColumns( columns );
+					if (isOverridden) {
+						final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
+								isId, propertyHolder, property.getName(), mappings
+						);
+						propertyBinder.setReferencedEntityName( mapsIdProperty.getClassOrElementName() );
+					}
+
+					propertyBinder.makePropertyValueAndBind();
+
+				}
+				if (isOverridden) {
+						final PropertyData mapsIdProperty = BinderHelper.getPropertyAnnotatedWithMapsId(
+								isId, propertyHolder, property.getName(), mappings
+						);
+						HashMap<String, IdGenerator> localGenerators = (HashMap<String, IdGenerator>) classGenerators.clone();
+						final IdGenerator foreignGenerator = new IdGenerator();
+						foreignGenerator.setIdentifierGeneratorStrategy( "assigned" );
+						foreignGenerator.setName( "Hibernate-local--foreign generator" );
+						foreignGenerator.setIdentifierGeneratorStrategy( "foreign" );
+						foreignGenerator.addParam( "property", mapsIdProperty.getPropertyName() );
+						localGenerators.put( foreignGenerator.getName(), foreignGenerator );
+
+						BinderHelper.makeIdGenerator(
+								(SimpleValue) propertyBinder.getValue(),
+								foreignGenerator.getIdentifierGeneratorStrategy(),
+								foreignGenerator.getName(),
+								mappings,
+								localGenerators
+						);
+					}
+				if (isId) {
+					//components and regular basic types create SimpleValue objects
+					final SimpleValue value = ( SimpleValue ) propertyBinder.getValue();
+					if ( !isOverridden ) {
+						processId(
+								propertyHolder,
+								inferredData,
+								value,
+								classGenerators,
+								isIdentifierMapper,
+								mappings
+						);
+					}
+				}
 			}
 		}
 		//init index
@@ -2507,7 +2510,7 @@
 
 	private static String getCascadeStrategy(
 		javax.persistence.CascadeType[] ejbCascades, Cascade hibernateCascadeAnnotation,
-		boolean orphanRemoval) {
+		boolean orphanRemoval, boolean mapsId) {
 		EnumSet<CascadeType> hibernateCascadeSet = convertToHibernateCascadeType( ejbCascades );
 		CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ?
 				null :
@@ -2521,6 +2524,9 @@
 			hibernateCascadeSet.add(CascadeType.DELETE_ORPHAN);
 			hibernateCascadeSet.add(CascadeType.REMOVE);
 		}
+		if (mapsId) {
+			hibernateCascadeSet.add(CascadeType.PERSIST);
+		}
 
 		StringBuilder cascade = new StringBuilder();
 		for ( CascadeType aHibernateCascadeSet : hibernateCascadeSet ) {

Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/b/DerivedIdentitySimpleParentEmbeddedIdDepTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/b/DerivedIdentitySimpleParentEmbeddedIdDepTest.java	2010-01-27 18:46:51 UTC (rev 18655)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e1/b/DerivedIdentitySimpleParentEmbeddedIdDepTest.java	2010-01-27 18:58:28 UTC (rev 18656)
@@ -23,8 +23,8 @@
 		d.emp = e;
 		d.id = new DependentId();
 		d.id.name = "Doggy";
+		s.persist( d );
 		s.persist( e );
-		s.persist( d );
 		s.flush();
 		s.clear();
 		d = (Dependent) s.get( Dependent.class, d.id );



More information about the hibernate-commits mailing list