[hibernate-commits] Hibernate SVN: r11061 - in branches/Branch_3_2/Hibernate3: src/org/hibernate/id and 5 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Jan 19 07:55:08 EST 2007


Author: steve.ebersole at jboss.com
Date: 2007-01-19 07:55:07 -0500 (Fri, 19 Jan 2007)
New Revision: 11061

Added:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/ValueInclusion.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.hbm.xml
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java
Modified:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/id/SelectGenerator.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/mapping/PropertyGeneration.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/GeneratedPropertySuite.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java
Log:
HHH-1471 : components +partial generation

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/ValueInclusion.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/ValueInclusion.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/ValueInclusion.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -0,0 +1,51 @@
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.io.StreamCorruptedException;
+
+/**
+ * An enum of the different ways a value might be "included".
+ * <p/>
+ * This is really an expanded true/false notion with "PARTIAL" being the
+ * expansion.  PARTIAL deals with components in the cases where
+ * parts of the referenced component might define inclusion, but the
+ * component overall does not.
+ *
+ * @author Steve Ebersole
+ */
+public class ValueInclusion implements Serializable {
+
+	public static final ValueInclusion NONE = new ValueInclusion( "none" );
+	public static final ValueInclusion FULL = new ValueInclusion( "full" );
+	public static final ValueInclusion PARTIAL = new ValueInclusion( "partial" );
+
+	private final String name;
+
+	public ValueInclusion(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String toString() {
+		return "ValueInclusion[" + name + "]";
+	}
+
+	private Object readResolve() throws ObjectStreamException {
+		if ( name.equals( NONE.name ) ) {
+			return NONE;
+		}
+		else if ( name.equals( FULL.name ) ) {
+			return FULL;
+		}
+		else if ( name.equals( PARTIAL.name ) ) {
+			return PARTIAL;
+		}
+		else {
+			throw new StreamCorruptedException( "unrecognized value inclusion [" + name + "]" );
+		}
+	}
+}

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/id/SelectGenerator.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/id/SelectGenerator.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/id/SelectGenerator.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -14,6 +14,7 @@
 import org.hibernate.id.insert.AbstractSelectingDelegate;
 import org.hibernate.dialect.Dialect;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.ValueInclusion;
 import org.hibernate.type.Type;
 
 /**
@@ -26,7 +27,7 @@
  * @author Gavin King
  */
 public class SelectGenerator extends AbstractPostInsertGenerator implements Configurable {
-	
+
 	private String uniqueKeyPropertyName;
 
 	public void configure(Type type, Properties params, Dialect d) throws MappingException {
@@ -57,7 +58,8 @@
 					"natural-id properties; need to specify [key] in generator parameters"
 			);
 		}
-		if ( persister.getPropertyInsertGeneration() [ naturalIdPropertyIndices[0] ] ) {
+		ValueInclusion inclusion = persister.getPropertyInsertGenerationInclusions() [ naturalIdPropertyIndices[0] ];
+		if ( inclusion != ValueInclusion.NONE ) {
 			throw new IdentifierGenerationException(
 					"natural-id also defined as insert-generated; need to specify [key] " +
 					"in generator parameters"

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/mapping/PropertyGeneration.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/mapping/PropertyGeneration.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/mapping/PropertyGeneration.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -6,7 +6,7 @@
  * Indicates whether given properties are generated by the database and, if
  * so, at what time(s) they are generated.
  *
- * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ * @author Steve Ebersole
  */
 public class PropertyGeneration implements Serializable {
 

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -44,6 +44,7 @@
 import org.hibernate.engine.Versioning;
 import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
 import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.ValueInclusion;
 import org.hibernate.exception.JDBCExceptionHelper;
 import org.hibernate.id.IdentifierGenerator;
 import org.hibernate.id.PostInsertIdentifierGenerator;
@@ -301,9 +302,7 @@
 		}
 		String[] result = new String[getTableSpan()];
 		result[0] = sqlUpdateByRowIdString;
-		for ( int i = 1; i < getTableSpan(); i++ ) {
-			result[i] = sqlUpdateStrings[i];
-		}
+		System.arraycopy( sqlUpdateStrings, 1, result, 1, getTableSpan() );
 		return result;
 	}
 
@@ -345,6 +344,8 @@
 
 	/**
 	 * The query that inserts a row, letting the database generate an id
+	 *
+	 * @return The IDENTITY-based insertion query.
 	 */
 	protected String getSQLIdentityInsertString() {
 		return sqlIdentityInsertString;
@@ -379,7 +380,15 @@
 	}
 
 	/**
-	 * Decide which tables need to be updated
+	 * Decide which tables need to be updated.
+	 * <p/>
+	 * The return here is an array of boolean values with each index corresponding
+	 * to a given table in the scope of this persister.
+	 *
+	 * @param dirtyProperties The indices of all the entity properties considered dirty.
+	 * @param hasDirtyCollection Whether any collections owned by the entity which were considered dirty.
+	 *
+	 * @return Array of booleans indicating which table require updating.
 	 */
 	protected boolean[] getTableUpdateNeeded(final int[] dirtyProperties, boolean hasDirtyCollection) {
 
@@ -583,8 +592,8 @@
 			names.add( prop.getName() );
 			classes.add( prop.getPersistentClass().getEntityName() );
 			boolean isDefinedBySubclass = !thisClassProperties.contains( prop );
-			definedBySubclass.add( new Boolean(isDefinedBySubclass) );
-			propNullables.add( new Boolean( prop.isOptional() || isDefinedBySubclass) ); //TODO: is this completely correct?
+			definedBySubclass.add( Boolean.valueOf( isDefinedBySubclass ) );
+			propNullables.add( Boolean.valueOf( prop.isOptional() || isDefinedBySubclass ) ); //TODO: is this completely correct?
 			types.add( prop.getType() );
 
 			Iterator colIter = prop.getColumnIterator();
@@ -593,7 +602,7 @@
 			int[] colnos = new int[prop.getColumnSpan()];
 			int[] formnos = new int[prop.getColumnSpan()];
 			int l = 0;
-			Boolean lazy = new Boolean( prop.isLazy() && lazyAvailable );
+			Boolean lazy = Boolean.valueOf( prop.isLazy() && lazyAvailable );
 			while ( colIter.hasNext() ) {
 				Selectable thing = ( Selectable ) colIter.next();
 				if ( thing.isFormula() ) {
@@ -614,7 +623,7 @@
 					cols[l] = colName;
 					aliases.add( thing.getAlias( factory.getDialect(), prop.getValue().getTable() ) );
 					columnsLazy.add( lazy );
-					columnSelectables.add( new Boolean( prop.isSelectable() ) );
+					columnSelectables.add( Boolean.valueOf( prop.isSelectable() ) );
 				}
 				l++;
 			}
@@ -1066,14 +1075,14 @@
 	}
 
 	protected String generateInsertGeneratedValuesSelectString() {
-		return generateGeneratedValuesSelectString( getPropertyInsertGeneration() );
+		return generateGeneratedValuesSelectString( getPropertyInsertGenerationInclusions() );
 	}
 
 	protected String generateUpdateGeneratedValuesSelectString() {
-		return generateGeneratedValuesSelectString( getPropertyUpdateGeneration() );
+		return generateGeneratedValuesSelectString( getPropertyUpdateGenerationInclusions() );
 	}
 
-	private String generateGeneratedValuesSelectString(boolean[] inclusions) {
+	private String generateGeneratedValuesSelectString(ValueInclusion[] inclusions) {
 		Select select = new Select( getFactory().getDialect() );
 
 		if ( getFactory().getSettings().isCommentsEnabled() ) {
@@ -1082,6 +1091,9 @@
 
 		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
 
+		// Here we render the select column list based on the properties defined as being generated.
+		// For partial component generation, we currently just re-select the whole component
+		// rather than trying to handle the individual generated portions.
 		String selectClause = concretePropertySelectFragment( getRootAlias(), inclusions );
 		selectClause = selectClause.substring( 2 );
 
@@ -1101,22 +1113,52 @@
 				.toStatementString();
 	}
 
-	protected String concretePropertySelectFragment(String alias, boolean[] includeProperty) {
+	protected static interface InclusionChecker {
+		public boolean includeProperty(int propertyNumber);
+	}
+
+	protected String concretePropertySelectFragment(String alias, final ValueInclusion[] inclusions) {
+		return concretePropertySelectFragment(
+				alias,
+				new InclusionChecker() {
+					// TODO : currently we really do not handle ValueInclusion.PARTIAL...
+					// ValueInclusion.PARTIAL would indicate parts of a component need to
+					// be included in the select; currently we then just render the entire
+					// component into the select clause in that case.
+					public boolean includeProperty(int propertyNumber) {
+						return inclusions[propertyNumber] != ValueInclusion.NONE;
+					}
+				}
+		);
+	}
+
+	protected String concretePropertySelectFragment(String alias, final boolean[] includeProperty) {
+		return concretePropertySelectFragment(
+				alias,
+				new InclusionChecker() {
+					public boolean includeProperty(int propertyNumber) {
+						return includeProperty[propertyNumber];
+					}
+				}
+		);
+	}
+
+	protected String concretePropertySelectFragment(String alias, InclusionChecker inclusionChecker) {
 		int propertyCount = getPropertyNames().length;
 		int[] propertyTableNumbers = getPropertyTableNumbersInSelect();
 		SelectFragment frag = new SelectFragment();
 		for ( int i = 0; i < propertyCount; i++ ) {
-			if ( includeProperty[i] ) { //ie. updateable, not a formula
+			if ( inclusionChecker.includeProperty( i ) ) {
 				frag.addColumns(
 						generateTableAlias( alias, propertyTableNumbers[i] ),
 						propertyColumnNames[i],
 						propertyColumnAliases[i]
-					);
+				);
 				frag.addFormulas(
 						generateTableAlias( alias, propertyTableNumbers[i] ),
 						propertyColumnFormulaTemplates[i],
 						propertyColumnAliases[i]
-					);
+				);
 			}
 		}
 		return frag.toFragmentString();
@@ -1810,9 +1852,8 @@
 	}
 
 	private boolean checkVersion(final boolean[] includeProperty) {
-        boolean checkVersion = includeProperty[ getVersionProperty() ] ||
-				entityMetamodel.getPropertyUpdateGeneration()[ getVersionProperty() ];
-		return checkVersion;
+        return includeProperty[ getVersionProperty() ] ||
+				entityMetamodel.getPropertyUpdateGenerationInclusions()[ getVersionProperty() ] != ValueInclusion.NONE;
 	}
 
 	protected String generateInsertString(boolean[] includeProperty, int j) {
@@ -3430,15 +3471,15 @@
 	}
 
 	public boolean hasInsertGeneratedProperties() {
-		return !ArrayHelper.isAllFalse( getPropertyInsertGeneration() );
+		return entityMetamodel.hasInsertGeneratedValues();
 	}
 
 	public boolean hasUpdateGeneratedProperties() {
-		return !ArrayHelper.isAllFalse( getPropertyUpdateGeneration() );
+		return entityMetamodel.hasUpdateGeneratedValues();
 	}
 
 	public boolean isVersionPropertyGenerated() {
-		return isVersioned() && getPropertyUpdateGeneration() [ getVersionProperty() ];
+		return isVersioned() && ( getPropertyUpdateGenerationInclusions() [ getVersionProperty() ] != ValueInclusion.NONE );
 	}
 
 	public boolean isVersionPropertyInsertable() {
@@ -3477,12 +3518,12 @@
 		return entityMetamodel.getPropertyInsertability();
 	}
 
-	public boolean[] getPropertyInsertGeneration() {
-		return entityMetamodel.getPropertyInsertGeneration();
+	public ValueInclusion[] getPropertyInsertGenerationInclusions() {
+		return entityMetamodel.getPropertyInsertGenerationInclusions();
 	}
 
-	public boolean[] getPropertyUpdateGeneration() {
-		return entityMetamodel.getPropertyUpdateGeneration();
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions() {
+		return entityMetamodel.getPropertyUpdateGenerationInclusions();
 	}
 
 	public boolean[] getPropertyNullability() {
@@ -3625,14 +3666,14 @@
 		if ( !hasInsertGeneratedProperties() ) {
 			throw new AssertionFailure("no insert-generated properties");
 		}
-		processGeneratedProperties( id, entity, state, session, sqlInsertGeneratedValuesSelectString, getPropertyInsertGeneration() );
+		processGeneratedProperties( id, entity, state, session, sqlInsertGeneratedValuesSelectString, getPropertyInsertGenerationInclusions() );
 	}
 
 	public void processUpdateGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session) {
 		if ( !hasInsertGeneratedProperties() ) {
 			throw new AssertionFailure("no update-generated properties");
 		}
-		processGeneratedProperties( id, entity, state, session, sqlUpdateGeneratedValuesSelectString, getPropertyUpdateGeneration() );
+		processGeneratedProperties( id, entity, state, session, sqlUpdateGeneratedValuesSelectString, getPropertyUpdateGenerationInclusions() );
 	}
 
 	private void processGeneratedProperties(
@@ -3641,7 +3682,7 @@
 	        Object[] state,
 	        SessionImplementor session,
 	        String selectionSQL,
-	        boolean[] included ) {
+	        ValueInclusion[] includeds) {
 
 		session.getBatcher().executeBatch(); //force immediate execution of the insert
 
@@ -3658,8 +3699,9 @@
 							);
 					}
 					for ( int i = 0; i < getPropertySpan(); i++ ) {
-						if ( included[i] ) {
-							state[i] = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity );
+						if ( includeds[i] != ValueInclusion.NONE ) {
+							Object hydratedState = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity );
+							state[i] = getPropertyTypes()[i].resolve( hydratedState, session, entity );
 							setPropertyValue( entity, i, state[i], session.getEntityMode() );
 						}
 					}

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -15,6 +15,7 @@
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.ValueInclusion;
 import org.hibernate.id.IdentifierGenerator;
 import org.hibernate.metadata.ClassMetadata;
 import org.hibernate.type.Type;
@@ -128,14 +129,14 @@
 	 * @return True if the entity does contain persistent collections; false otherwise.
 	 */
 	public boolean hasCollections();
-	
+
 	/**
 	 * Determine whether any properties of this entity are considered mutable.
 	 *
 	 * @return True if any properties of the entity are mutable; false otherwise (meaning none are).
 	 */
 	public boolean hasMutableProperties();
-	
+
 	/**
 	 * Determine whether this entity contains references to persistent collections
 	 * which are fetchable by subselect?
@@ -255,7 +256,7 @@
 	 * @return The type of the version property; or -66, if not versioned.
 	 */
 	public int getVersionProperty();
-	
+
 	/**
 	 * Determine whether this entity defines a natural identifier.
 	 *
@@ -287,7 +288,7 @@
 	 * @return The identifier generation strategy.
 	 */
 	public IdentifierGenerator getIdentifierGenerator();
-	
+
 	/**
 	 * Determine whether this entity defines any lazy properties (ala
 	 * bytecode instrumentation).
@@ -295,7 +296,7 @@
 	 * @return True if the entity has properties mapped as lazy; false otherwise.
 	 */
 	public boolean hasLazyProperties();
-	
+
 	/**
 	 * Load an instance of the persistent class.
 	 */
@@ -361,19 +362,19 @@
 	/**
 	 * Which of the properties of this class are database generated values on insert?
 	 */
-	public boolean[] getPropertyInsertGeneration();
+	public ValueInclusion[] getPropertyInsertGenerationInclusions();
 
 	/**
 	 * Which of the properties of this class are database generated values on update?
 	 */
-	public boolean[] getPropertyUpdateGeneration();
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions();
 
 	/**
 	 * Get the "updateability" of the properties of this class
 	 * (does the property appear in an SQL UPDATE)
 	 */
 	public boolean[] getPropertyUpdateability();
-	
+
 	/**
 	 * Get the "checkability" of the properties of this class
 	 * (is the property dirty checked, does the cache need
@@ -468,7 +469,7 @@
 	 * Try to discover the entity mode from the entity instance
 	 */
 	public EntityMode guessEntityMode(Object object);
-	
+
 	/**
 	 * Has the class actually been bytecode instrumented?
 	 */
@@ -583,7 +584,7 @@
 	 */
 	public boolean implementsValidatable(EntityMode entityMode);
 	/**
-	 * Get the proxy interface that instances of <em>this</em> concrete class will be 
+	 * Get the proxy interface that instances of <em>this</em> concrete class will be
 	 * cast to (optional operation).
 	 */
 	public Class getConcreteProxyClass(EntityMode entityMode);
@@ -607,7 +608,7 @@
 	 * Get the value of a particular property
 	 */
 	public Object getPropertyValue(Object object, int i, EntityMode entityMode) throws HibernateException;
-	
+
 	/**
 	 * Get the value of a particular property
 	 */
@@ -617,7 +618,7 @@
 	 * Get the identifier of an instance (throw an exception if no identifier property)
 	 */
 	public Serializable getIdentifier(Object object, EntityMode entityMode) throws HibernateException;
-	
+
 	/**
 	 * Set the identifier of an instance (or do nothing if no identifier property)
 	 */
@@ -637,14 +638,14 @@
 	 * Is the given object an instance of this entity?
 	 */
 	public boolean isInstance(Object object, EntityMode entityMode);
-	
+
 	/**
 	 * Does the given instance have any uninitialized lazy properties?
 	 */
 	public boolean hasUninitializedLazyProperties(Object object, EntityMode entityMode);
-	
+
 	/**
-	 * Set the identifier and version of the given instance back 
+	 * Set the identifier and version of the given instance back
 	 * to its "unsaved" value, returning the id
 	 * @param currentId TODO
 	 * @param currentVersion TODO

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -23,9 +23,11 @@
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.Versioning;
+import org.hibernate.engine.ValueInclusion;
 import org.hibernate.mapping.Component;
 import org.hibernate.mapping.PersistentClass;
 import org.hibernate.mapping.Property;
+import org.hibernate.mapping.PropertyGeneration;
 import org.hibernate.type.AbstractComponentType;
 import org.hibernate.type.AssociationType;
 import org.hibernate.type.EntityType;
@@ -40,7 +42,7 @@
  * @author Steve Ebersole
  */
 public class EntityMetamodel implements Serializable {
-	
+
 	private static final Log log = LogFactory.getLog(EntityMetamodel.class);
 
 	private static final int NO_VERSION_INDX = -66;
@@ -65,15 +67,17 @@
 	private final boolean[] nonlazyPropertyUpdateability;
 	private final boolean[] propertyCheckability;
 	private final boolean[] propertyInsertability;
-	private final boolean[] propertyInsertGeneration;
-	private final boolean[] propertyUpdateGeneration;
+	private final ValueInclusion[] insertInclusions;
+	private final ValueInclusion[] updateInclusions;
 	private final boolean[] propertyNullability;
 	private final boolean[] propertyVersionability;
 	private final CascadeStyle[] cascadeStyles;
+	private final boolean hasInsertGeneratedValues;
+	private final boolean hasUpdateGeneratedValues;
 	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	private final Map propertyIndexes = new HashMap();
 	private final boolean hasCollections;
-	private final boolean hasMutableProperties; 
+	private final boolean hasMutableProperties;
 	private final boolean hasLazyProperties;
 	private final boolean hasNonIdentifierPropertyNamedId;
 
@@ -96,7 +100,7 @@
 	private final Set subclassEntityNames = new HashSet();
 
 	private final EntityEntityModeToTuplizerMapping tuplizerMapping;
-	
+
 	public EntityTuplizer getTuplizer(EntityMode entityMode) {
 		return (EntityTuplizer) tuplizerMapping.getTuplizer( entityMode );
 	}
@@ -104,7 +108,7 @@
 	public EntityTuplizer getTuplizerOrNull(EntityMode entityMode) {
 		return ( EntityTuplizer ) tuplizerMapping.getTuplizerOrNull( entityMode );
 	}
-	
+
 	public EntityMode guessEntityMode(Object object) {
 		return tuplizerMapping.guessEntityMode( object );
 	}
@@ -135,8 +139,8 @@
 		propertyTypes = new Type[propertySpan];
 		propertyUpdateability = new boolean[propertySpan];
 		propertyInsertability = new boolean[propertySpan];
-		propertyInsertGeneration = new boolean[propertySpan];
-		propertyUpdateGeneration = new boolean[propertySpan];
+		insertInclusions = new ValueInclusion[propertySpan];
+		updateInclusions = new ValueInclusion[propertySpan];
 		nonlazyPropertyUpdateability = new boolean[propertySpan];
 		propertyCheckability = new boolean[propertySpan];
 		propertyNullability = new boolean[propertySpan];
@@ -153,7 +157,9 @@
 		boolean foundCollection = false;
 		boolean foundMutable = false;
 		boolean foundNonIdentifierPropertyNamedId = false;
-		
+		boolean foundInsertGeneratedValue = false;
+		boolean foundUpdateGeneratedValue = false;
+
 		while ( iter.hasNext() ) {
 			Property prop = ( Property ) iter.next();
 
@@ -164,7 +170,7 @@
 			else {
 				properties[i] = PropertyFactory.buildStandardProperty( prop, lazyAvailable );
 			}
-			
+
 			if ( prop.isNaturalIdentifier() ) {
 				naturalIdNumbers.add( new Integer(i) );
 			}
@@ -183,11 +189,11 @@
 			propertyNullability[i] = properties[i].isNullable();
 			propertyUpdateability[i] = properties[i].isUpdateable();
 			propertyInsertability[i] = properties[i].isInsertable();
-			propertyInsertGeneration[i] = properties[i].isInsertGenerated();
-			propertyUpdateGeneration[i] = properties[i].isUpdateGenerated();
+			insertInclusions[i] = determineInsertValueGenerationType( prop, properties[i] );
+			updateInclusions[i] = determineUpdateValueGenerationType( prop, properties[i] );
 			propertyVersionability[i] = properties[i].isVersionable();
 			nonlazyPropertyUpdateability[i] = properties[i].isUpdateable() && !lazy;
-			propertyCheckability[i] = propertyUpdateability[i] || 
+			propertyCheckability[i] = propertyUpdateability[i] ||
 					( propertyTypes[i].isAssociationType() && ( (AssociationType) propertyTypes[i] ).isAlwaysDirtyChecked() );
 
 			cascadeStyles[i] = properties[i].getCascadeStyle();
@@ -204,15 +210,23 @@
 			if ( indicatesCollection( properties[i].getType() ) ) {
 				foundCollection = true;
 			}
-			
+
 			if ( propertyTypes[i].isMutable() && propertyCheckability[i] ) {
 				foundMutable = true;
 			}
 
+			if ( insertInclusions[i] != ValueInclusion.NONE ) {
+				foundInsertGeneratedValue = true;
+			}
+
+			if ( updateInclusions[i] != ValueInclusion.NONE ) {
+				foundUpdateGeneratedValue = true;
+			}
+
 			mapPropertyToIndex(prop, i);
 			i++;
 		}
-		
+
 		if (naturalIdNumbers.size()==0) {
 			naturalIdPropertyNumbers = null;
 		}
@@ -220,6 +234,9 @@
 			naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
 		}
 
+		hasInsertGeneratedValues = foundInsertGeneratedValue;
+		hasUpdateGeneratedValues = foundUpdateGeneratedValue;
+
 		hasCascades = foundCascade;
 		hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
 		versionPropertyIndex = tempVersionProperty;
@@ -232,7 +249,7 @@
 				// TODO: this disables laziness even in non-pojo entity modes:
 				!persistentClass.hasPojoRepresentation() ||
 				!ReflectHelper.isFinalClass( persistentClass.getProxyInterface() )
-			);
+		);
 		mutable = persistentClass.isMutable();
 		if ( persistentClass.isAbstract() == null ) {
 			// legacy behavior (with no abstract attribute specified)
@@ -278,28 +295,84 @@
 		tuplizerMapping = new EntityEntityModeToTuplizerMapping( persistentClass, this );
 	}
 
+	private ValueInclusion determineInsertValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) {
+		if ( runtimeProperty.isInsertGenerated() ) {
+			return ValueInclusion.FULL;
+		}
+		else if ( mappingProperty.getValue() instanceof Component ) {
+			if ( hasPartialInsertComponentGeneration( ( Component ) mappingProperty.getValue() ) ) {
+				return ValueInclusion.PARTIAL;
+			}
+		}
+		return ValueInclusion.NONE;
+	}
+
+	private boolean hasPartialInsertComponentGeneration(Component component) {
+		Iterator subProperties = component.getPropertyIterator();
+		while ( subProperties.hasNext() ) {
+			Property prop = ( Property ) subProperties.next();
+			if ( prop.getGeneration() == PropertyGeneration.ALWAYS || prop.getGeneration() == PropertyGeneration.INSERT ) {
+				return true;
+			}
+			else if ( prop.getValue() instanceof Component ) {
+				if ( hasPartialInsertComponentGeneration( ( Component ) prop.getValue() ) ) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	private ValueInclusion determineUpdateValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) {
+		if ( runtimeProperty.isUpdateGenerated() ) {
+			return ValueInclusion.FULL;
+		}
+		else if ( mappingProperty.getValue() instanceof Component ) {
+			if ( hasPartialUpdateComponentGeneration( ( Component ) mappingProperty.getValue() ) ) {
+				return ValueInclusion.PARTIAL;
+			}
+		}
+		return ValueInclusion.NONE;
+	}
+
+	private boolean hasPartialUpdateComponentGeneration(Component component) {
+		Iterator subProperties = component.getPropertyIterator();
+		while ( subProperties.hasNext() ) {
+			Property prop = ( Property ) subProperties.next();
+			if ( prop.getGeneration() == PropertyGeneration.ALWAYS ) {
+				return true;
+			}
+			else if ( prop.getValue() instanceof Component ) {
+				if ( hasPartialUpdateComponentGeneration( ( Component ) prop.getValue() ) ) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
 	private void mapPropertyToIndex(Property prop, int i) {
 		propertyIndexes.put( prop.getName(), new Integer(i) );
 		if ( prop.getValue() instanceof Component ) {
 			Iterator iter = ( (Component) prop.getValue() ).getPropertyIterator();
 			while ( iter.hasNext() ) {
 				Property subprop = (Property) iter.next();
-				propertyIndexes.put( 
-						prop.getName() + '.' + subprop.getName(), 
-						new Integer(i) 
+				propertyIndexes.put(
+						prop.getName() + '.' + subprop.getName(),
+						new Integer(i)
 					);
 			}
 		}
 	}
-	
+
 	public int[] getNaturalIdentifierProperties() {
 		return naturalIdPropertyNumbers;
 	}
-	
+
 	public boolean hasNaturalIdentifier() {
 		return naturalIdPropertyNumbers!=null;
 	}
-	
+
 	public Set getSubclassEntityNames() {
 		return subclassEntityNames;
 	}
@@ -367,7 +440,7 @@
 		}
 		return index.intValue();
 	}
-	
+
 	public Integer getPropertyIndexOrNull(String propertyName) {
 		return (Integer) propertyIndexes.get( propertyName );
 	}
@@ -375,7 +448,7 @@
 	public boolean hasCollections() {
 		return hasCollections;
 	}
-	
+
 	public boolean hasMutableProperties() {
 		return hasMutableProperties;
 	}
@@ -447,11 +520,11 @@
 	public boolean isAbstract() {
 		return isAbstract;
 	}
-	
+
 	public String toString() {
 		return "EntityMetamodel(" + name + ':' + ArrayHelper.toString(properties) + ')';
 	}
-	
+
 	// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	public String[] getPropertyNames() {
 		return propertyNames;
@@ -481,12 +554,12 @@
 		return propertyInsertability;
 	}
 
-	public boolean[] getPropertyInsertGeneration() {
-		return propertyInsertGeneration;
+	public ValueInclusion[] getPropertyInsertGenerationInclusions() {
+		return insertInclusions;
 	}
 
-	public boolean[] getPropertyUpdateGeneration() {
-		return propertyUpdateGeneration;
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions() {
+		return updateInclusions;
 	}
 
 	public boolean[] getPropertyNullability() {
@@ -500,5 +573,14 @@
 	public CascadeStyle[] getCascadeStyles() {
 		return cascadeStyles;
 	}
+
+	public boolean hasInsertGeneratedValues() {
+		return hasInsertGeneratedValues;
+	}
+
+	public boolean hasUpdateGeneratedValues() {
+		return hasUpdateGeneratedValues;
+	}
+
 	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 }

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.hbm.xml	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.hbm.xml	2007-01-19 12:55:07 UTC (rev 11061)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generated">
+
+    <class name="ComponentOwner" table="part_gen_comp">
+    	<id name="id">
+    		<generator class="increment"/>
+    	</id>
+        <property name="name" />
+        <component name="component" class="ComponentOwner$Component">
+            <property name="generated" type="int" generated="always" column="GENED"/>
+        </component>
+	</class>
+
+    <database-object>
+        <create>
+            <![CDATA[CREATE OR REPLACE TRIGGER t_iu_part_gen_comp
+            BEFORE INSERT OR UPDATE ON part_gen_comp
+            FOR EACH ROW
+            BEGIN
+                IF INSERTING THEN
+                    :new.gened := 1;
+                ELSE
+                    :new.gened := :old.gened + 1;
+                END IF;
+            END;]]>
+        </create>
+        <drop>
+            <![CDATA[DROP TRIGGER t_iu_part_gen_comp]]>
+        </drop>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+
+</hibernate-mapping>
\ No newline at end of file

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/ComponentOwner.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -0,0 +1,55 @@
+package org.hibernate.test.generated;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class ComponentOwner {
+	private Long id;
+	private String name;
+	private Component component;
+
+	public ComponentOwner() {
+	}
+
+	public ComponentOwner(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Component getComponent() {
+		return component;
+	}
+
+	public void setComponent(Component component) {
+		this.component = component;
+	}
+
+	public static class Component {
+		private int generated;
+
+		public int getGenerated() {
+			return generated;
+		}
+
+		public void setGenerated(int generated) {
+			this.generated = generated;
+		}
+	}
+}

Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/GeneratedPropertySuite.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/GeneratedPropertySuite.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/GeneratedPropertySuite.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -14,6 +14,7 @@
 		suite.addTest( TimestampGeneratedValuesWithCachingTest.suite() );
 		suite.addTest( TriggerGeneratedValuesWithCachingTest.suite() );
 		suite.addTest( TriggerGeneratedValuesWithoutCachingTest.suite() );
+		suite.addTest( PartiallyGeneratedComponentTest.suite() );
 		return suite;
 	}
 }

Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -0,0 +1,64 @@
+package org.hibernate.test.generated;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PartiallyGeneratedComponentTest extends DatabaseSpecificFunctionalTestCase {
+	public PartiallyGeneratedComponentTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "generated/ComponentOwner.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PartiallyGeneratedComponentTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect instanceof Oracle9Dialect;
+	}
+
+	public void testPartialComponentGeneration() {
+		ComponentOwner owner = new ComponentOwner( "initial" );
+		Session s = openSession();
+		s.beginTransaction();
+		s.save( owner );
+		s.getTransaction().commit();
+		s.close();
+
+		assertNotNull( "expecting insert value generation", owner.getComponent() );
+		int previousValue = owner.getComponent().getGenerated();
+		assertFalse( "expecting insert value generation", 0 == previousValue );
+
+		s = openSession();
+		s.beginTransaction();
+		owner = ( ComponentOwner ) s.get( ComponentOwner.class, owner.getId() );
+		assertEquals( "expecting insert value generation", previousValue, owner.getComponent().getGenerated() );
+		owner.setName( "subsequent" );
+		s.getTransaction().commit();
+		s.close();
+
+		assertNotNull( owner.getComponent() );
+		previousValue = owner.getComponent().getGenerated();
+
+		s = openSession();
+		s.beginTransaction();
+		owner = ( ComponentOwner ) s.get( ComponentOwner.class, owner.getId() );
+		assertEquals( "expecting update value generation", previousValue, owner.getComponent().getGenerated() );
+		s.delete( owner );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java	2007-01-19 12:51:31 UTC (rev 11060)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java	2007-01-19 12:55:07 UTC (rev 11061)
@@ -21,6 +21,7 @@
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.TwoPhaseLoad;
+import org.hibernate.engine.ValueInclusion;
 import org.hibernate.event.EventSource;
 import org.hibernate.event.PostLoadEvent;
 import org.hibernate.event.PreLoadEvent;
@@ -39,13 +40,13 @@
 
 	private static final Hashtable INSTANCES = new Hashtable();
 	private static final IdentifierGenerator GENERATOR = new UUIDHexGenerator();
-	
+
 	private SessionFactoryImplementor factory;
 
 	public CustomPersister(
-			PersistentClass model, 
-			CacheConcurrencyStrategy cache, 
-			SessionFactoryImplementor factory, 
+			PersistentClass model,
+			CacheConcurrencyStrategy cache,
+			SessionFactoryImplementor factory,
 			Mapping mapping) {
 		this.factory = factory;
 	}
@@ -63,7 +64,7 @@
 	public boolean isInherited() {
 		return false;
 	}
-	
+
 	public SessionFactoryImplementor getFactory() {
 		return factory;
 	}
@@ -97,7 +98,7 @@
 	public boolean isMutable() {
 		return true;
 	}
-	
+
 	public boolean isSelectBeforeUpdateRequired() {
 		return false;
 	}
@@ -293,29 +294,29 @@
 		Custom obj = (Custom) INSTANCES.get(id);
 		if (obj!=null) {
 			clone = (Custom) obj.clone();
-			TwoPhaseLoad.addUninitializedEntity( 
-					new EntityKey( id, this, session.getEntityMode() ), 
-					clone, 
-					this, 
-					LockMode.NONE, 
+			TwoPhaseLoad.addUninitializedEntity(
+					new EntityKey( id, this, session.getEntityMode() ),
+					clone,
+					this,
+					LockMode.NONE,
 					false,
 					session
 				);
 			TwoPhaseLoad.postHydrate(
-					this, id, 
-					new String[] { obj.getName() }, 
-					null, 
-					clone, 
-					LockMode.NONE, 
-					false, 
+					this, id,
+					new String[] { obj.getName() },
+					null,
+					clone,
+					LockMode.NONE,
+					false,
 					session
 				);
-			TwoPhaseLoad.initializeEntity( 
-					clone, 
-					false, 
-					session, 
-					new PreLoadEvent( (EventSource) session ), 
-					new PostLoadEvent( (EventSource) session ) 
+			TwoPhaseLoad.initializeEntity(
+					clone,
+					false,
+					session,
+					new PreLoadEvent( (EventSource) session ),
+					new PostLoadEvent( (EventSource) session )
 				);
 		}
 		return clone;
@@ -471,12 +472,12 @@
 		return MUTABILITY;
 	}
 
-	public boolean[] getPropertyInsertGeneration() {
-		return new boolean[0];
+	public ValueInclusion[] getPropertyInsertGenerationInclusions() {
+		return new ValueInclusion[0];
 	}
 
-	public boolean[] getPropertyUpdateGeneration() {
-		return new boolean[0];
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions() {
+		return new ValueInclusion[0];
 	}
 
 
@@ -541,19 +542,19 @@
 
 	public void applyFilters(Select select, String alias, Map filters) {
 	}
-	
-	
+
+
 	public void afterInitialize(Object entity, boolean fetched, SessionImplementor session) {
 	}
 
 	public void afterReassociate(Object entity, SessionImplementor session) {
 	}
 
-	public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session) 
+	public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session)
 	throws HibernateException {
 		return null;
 	}
-	
+
 	public boolean[] getPropertyVersionability() {
 		return MUTABILITY;
 	}




More information about the hibernate-commits mailing list