[hibernate-commits] Hibernate SVN: r18601 - in core/trunk/core/src/main/java/org/hibernate: id and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Jan 21 14:37:02 EST 2010


Author: steve.ebersole at jboss.com
Date: 2010-01-21 14:37:01 -0500 (Thu, 21 Jan 2010)
New Revision: 18601

Added:
   core/trunk/core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java
Modified:
   core/trunk/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java
   core/trunk/core/src/main/java/org/hibernate/mapping/Component.java
   core/trunk/core/src/main/java/org/hibernate/mapping/SimpleValue.java
Log:
HHH-4552 - Support generated value within composite keys


Modified: core/trunk/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java	2010-01-21 17:51:09 UTC (rev 18600)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java	2010-01-21 19:37:01 UTC (rev 18601)
@@ -38,6 +38,7 @@
 import org.hibernate.engine.EntityEntry;
 import org.hibernate.engine.EntityKey;
 import org.hibernate.engine.Nullability;
+import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.Status;
 import org.hibernate.engine.Versioning;
@@ -62,8 +63,12 @@
 	/**
 	 * make sure user didn't mangle the id
 	 */
-	public void checkId(Object object, EntityPersister persister, Serializable id, EntityMode entityMode)
-	throws HibernateException {
+	public void checkId(
+			Object object,
+			EntityPersister persister,
+			Serializable id,
+			EntityMode entityMode,
+			SessionFactoryImplementor factory) throws HibernateException {
 
 		if ( id != null && id instanceof DelayedPostInsertIdentifier ) {
 			// this is a situation where the entity id is assigned by a post-insert generator
@@ -77,7 +82,7 @@
 			if (id==null) {
 				throw new AssertionFailure("null id in " + persister.getEntityName() + " entry (don't flush the Session after an exception occurs)");
 			}
-			if ( !persister.getIdentifierType().isEqual(id, oid, entityMode) ) {
+			if ( !persister.getIdentifierType().isEqual( id, oid, entityMode, factory ) ) {
 				throw new HibernateException(
 						"identifier of an instance of " +
 						persister.getEntityName() +
@@ -184,7 +189,7 @@
 			values = loadedState;
 		}
 		else {
-			checkId( entity, persister, entry.getId(), entityMode );
+			checkId( entity, persister, entry.getId(), entityMode, session.getFactory() );
 
 			// grab its current state
 			values = persister.getPropertyValues( entity, entityMode );

Added: core/trunk/core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java	2010-01-21 19:37:01 UTC (rev 18601)
@@ -0,0 +1,96 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * For composite identifiers, defines a number of "nested" generations that
+ * need to happen to "fill" the identifier property(s).
+ * <p/>
+ * This generator is used implicitly for all composite identifier scenarios if an
+ * explicit generator is not in place.  So it make sense to discuss the various 
+ * potential scenarios:<ul>
+ * <li>
+ * <i>"embedded" composite identifier</i> - this is possible only in HBM mappings
+ * as {@code <composite-id/>} (notice the lack of both a name and class attribute
+ * declarations).  The term {@link org.hibernate.mapping.Component#isEmbedded() "embedded"}
+ * here refers to the Hibernate usage which is actually the exact opposite of the JPA
+ * meaning of "embedded".  Essentially this means that the entity class itself holds
+ * the named composite pk properties.  This is very similar to the JPA {@code @IdClass}
+ * usage, though without a separate pk-class for loading.
+ * </li>
+ * <li>
+ * <i>pk-class as entity attribute</i> - this is possible in both annotations ({@code @EmbeddedId})
+ * and HBM mappings ({@code <composite-id name="idAttributeName" class="PkClassName"/>})
+ * </li>
+ * <li>
+ * <i>"embedded" composite identifier with a pk-class</i> - this is the JPA {@code @IdClass} use case
+ * and is only possible in annotations
+ * </li>
+ * </ul>
+ * <p/>
+ * Most of the grunt work is done in {@link org.hibernate.mapping.Component}.
+ *
+ * @author Steve Ebersole
+ */
+public class CompositeNestedGeneratedValueGenerator implements IdentifierGenerator, Serializable {
+	public static interface GenerationContextLocator {
+		public Serializable locateGenerationContext(SessionImplementor session, Object incomingObject);
+	}
+
+	public static interface GenerationPlan {
+		public void execute(SessionImplementor session, Object incomingObject);
+	}
+
+	private final GenerationContextLocator generationContextLocator;
+	private List generationPlans = new ArrayList();
+
+	public CompositeNestedGeneratedValueGenerator(GenerationContextLocator generationContextLocator) {
+		this.generationContextLocator = generationContextLocator;
+	}
+
+	public void addGeneratedValuePlan(GenerationPlan plan) {
+		generationPlans.add( plan );
+	}
+
+	public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
+		final Serializable context = generationContextLocator.locateGenerationContext( session, object );
+
+		Iterator itr = generationPlans.iterator();
+		while ( itr.hasNext() ) {
+			final GenerationPlan plan = (GenerationPlan) itr.next();
+			plan.execute( session, context );
+		}
+
+		return context;
+	}
+
+}

Modified: core/trunk/core/src/main/java/org/hibernate/mapping/Component.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/Component.java	2010-01-21 17:51:09 UTC (rev 18600)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/Component.java	2010-01-21 19:37:01 UTC (rev 18601)
@@ -1,10 +1,10 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
  * indicated by the @author tags or express copyright attribution
  * statements applied by the authors.  All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
  *
  * This copyrighted material is made available to anyone wishing to use, modify,
  * copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,17 +20,30 @@
  * Free Software Foundation, Inc.
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
- *
  */
 package org.hibernate.mapping;
 
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.factory.IdentifierGeneratorFactory;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.Setter;
 import org.hibernate.tuple.component.ComponentMetamodel;
 import org.hibernate.type.ComponentType;
 import org.hibernate.type.EmbeddedComponentType;
@@ -41,10 +54,11 @@
 /**
  * The mapping for a component, composite element,
  * composite identifier, etc.
+ *
  * @author Gavin King
+ * @author Steve Ebersole
  */
 public class Component extends SimpleValue implements MetaAttributable {
-
 	private ArrayList properties = new ArrayList();
 	private String componentClassName;
 	private boolean embedded;
@@ -295,4 +309,135 @@
 		return getClass().getName() + '(' + properties.toString() + ')';
 	}
 
+	private IdentifierGenerator builtIdentifierGenerator;
+
+	public IdentifierGenerator createIdentifierGenerator(
+			IdentifierGeneratorFactory identifierGeneratorFactory,
+			Dialect dialect,
+			String defaultCatalog,
+			String defaultSchema,
+			RootClass rootClass) throws MappingException {
+		if ( builtIdentifierGenerator == null ) {
+			builtIdentifierGenerator = buildIdentifierGenerator(
+					identifierGeneratorFactory,
+					dialect,
+					defaultCatalog,
+					defaultSchema,
+					rootClass
+			);
+		}
+		return builtIdentifierGenerator;
+	}
+
+	private IdentifierGenerator buildIdentifierGenerator(
+			IdentifierGeneratorFactory identifierGeneratorFactory,
+			Dialect dialect,
+			String defaultCatalog,
+			String defaultSchema,
+			RootClass rootClass) throws MappingException {
+		final boolean hasCustomGenerator = ! DEFAULT_ID_GEN_STRATEGY.equals( getIdentifierGeneratorStrategy() );
+		if ( hasCustomGenerator ) {
+			return super.createIdentifierGenerator(
+					identifierGeneratorFactory, dialect, defaultCatalog, defaultSchema, rootClass
+			);
+		}
+
+		final Class entityClass = rootClass.getMappedClass();
+		final Class attributeDeclarer; // what class is the declarer of the composite pk attributes
+		CompositeNestedGeneratedValueGenerator.GenerationContextLocator locator;
+
+		// IMPL NOTE : See the javadoc discussion on CompositeNestedGeneratedValueGenerator wrt the
+		//		various scenarios for which we need to account here
+		if ( isEmbedded() ) {
+			// we have the "straight up" embedded (again the hibernate term) component identifier
+			attributeDeclarer = entityClass;
+		}
+		else if ( rootClass.getIdentifierProperty() != null ) {
+			// we have the "@EmbeddedId" / <composite-id name="idName"/> case
+			attributeDeclarer = resolveComponentClass();
+		}
+		else {
+			// we have the @IdClass / <composite-id mapped="true"/> case
+			attributeDeclarer = resolveComponentClass();
+		}
+
+		locator = new StandardGenerationContextLocator( rootClass.getEntityName() );
+		final CompositeNestedGeneratedValueGenerator generator = new CompositeNestedGeneratedValueGenerator( locator );
+
+		Iterator itr = getPropertyIterator();
+		while ( itr.hasNext() ) {
+			final Property property = (Property) itr.next();
+			if ( property.getValue().isSimpleValue() ) {
+				final SimpleValue value = (SimpleValue) property.getValue();
+
+				if ( DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) ) {
+					// skip any 'assigned' generators, they would have been handled by
+					// the StandardGenerationContextLocator
+					continue;
+				}
+
+				final IdentifierGenerator valueGenerator = value.createIdentifierGenerator(
+						identifierGeneratorFactory,
+						dialect,
+						defaultCatalog,
+						defaultSchema,
+						rootClass
+				);
+				final Setter injector = property.getPropertyAccessor( attributeDeclarer )
+						.getSetter( attributeDeclarer, property.getName() );
+				generator.addGeneratedValuePlan(
+						new ValueGenerationPlan(
+								property.getName(),
+								valueGenerator,
+								injector
+						)
+				);
+			}
+		}
+		return generator;
+	}
+
+	private Class resolveComponentClass() {
+		try {
+			return getComponentClass();
+		}
+		catch ( Exception e ) {
+			return null;
+		}
+	}
+
+	public static class StandardGenerationContextLocator
+			implements CompositeNestedGeneratedValueGenerator.GenerationContextLocator {
+		private final String entityName;
+
+		public StandardGenerationContextLocator(String entityName) {
+			this.entityName = entityName;
+		}
+
+		public Serializable locateGenerationContext(SessionImplementor session, Object incomingObject) {
+			return session.getEntityPersister( entityName, incomingObject )
+					.getIdentifier( incomingObject, session.getEntityMode() );
+		}
+	}
+
+	public static class ValueGenerationPlan implements CompositeNestedGeneratedValueGenerator.GenerationPlan {
+		private final String propertyName;
+		private final IdentifierGenerator subGenerator;
+		private final Setter injector;
+
+		public ValueGenerationPlan(
+				String propertyName,
+				IdentifierGenerator subGenerator,
+				Setter injector) {
+			this.propertyName = propertyName;
+			this.subGenerator = subGenerator;
+			this.injector = injector;
+		}
+
+		public void execute(SessionImplementor session, Object incomingObject) {
+			final Object generatedValue = subGenerator.generate( session, incomingObject );
+			injector.set( incomingObject, generatedValue, session.getFactory() );
+		}
+	}
+
 }

Modified: core/trunk/core/src/main/java/org/hibernate/mapping/SimpleValue.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/SimpleValue.java	2010-01-21 17:51:09 UTC (rev 18600)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/SimpleValue.java	2010-01-21 19:37:01 UTC (rev 18601)
@@ -46,11 +46,12 @@
  * @author Gavin King
  */
 public class SimpleValue implements KeyValue {
+	public static final String DEFAULT_ID_GEN_STRATEGY = "assigned";
 
 	private final List columns = new ArrayList();
 	private String typeName;
 	private Properties identifierGeneratorProperties;
-	private String identifierGeneratorStrategy = "assigned";
+	private String identifierGeneratorStrategy = DEFAULT_ID_GEN_STRATEGY;
 	private String nullValue;
 	private Table table;
 	private String foreignKeyName;
@@ -124,8 +125,7 @@
 			Dialect dialect, 
 			String defaultCatalog, 
 			String defaultSchema, 
-			RootClass rootClass) 
-	throws MappingException {
+			RootClass rootClass) throws MappingException {
 		
 		Properties params = new Properties();
 		



More information about the hibernate-commits mailing list