[hibernate-commits] Hibernate SVN: r14389 - in annotations/trunk/src: test/org/hibernate/test/annotations/manytoone and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Mar 4 16:22:12 EST 2008


Author: epbernard
Date: 2008-03-04 16:22:12 -0500 (Tue, 04 Mar 2008)
New Revision: 14389

Added:
   annotations/trunk/src/java/org/hibernate/cfg/RecoverableException.java
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/GenericObject.java
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Item.java
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ManyToOneReferencedColumnNameTest.java
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Vendor.java
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/WarehouseItem.java
   annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ZItemCost.java
Modified:
   annotations/trunk/src/java/org/hibernate/cfg/AnnotationConfiguration.java
   annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java
Log:
ANN-509 recover from Foreign Key Mapping exception when it's due to second pass ordering.

Modified: annotations/trunk/src/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/AnnotationConfiguration.java	2008-03-04 18:07:28 UTC (rev 14388)
+++ annotations/trunk/src/java/org/hibernate/cfg/AnnotationConfiguration.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -299,30 +299,35 @@
 			}
 		}
 		caches.clear();
-
-		inSecondPass = true;
-		processFkSecondPassInOrder();
-		Iterator iter = secondPasses.iterator();
-		while ( iter.hasNext() ) {
-			SecondPass sp = (SecondPass) iter.next();
-			//do the second pass of fk before the others and remove them
-			if ( sp instanceof CreateKeySecondPass ) {
-				sp.doSecondPass( classes );
-				iter.remove();
+		try {
+			inSecondPass = true;
+			processFkSecondPassInOrder();
+			Iterator iter = secondPasses.iterator();
+			while ( iter.hasNext() ) {
+				SecondPass sp = (SecondPass) iter.next();
+				//do the second pass of fk before the others and remove them
+				if ( sp instanceof CreateKeySecondPass ) {
+					sp.doSecondPass( classes );
+					iter.remove();
+				}
 			}
-		}
 
-		iter = secondPasses.iterator();
-		while ( iter.hasNext() ) {
-			SecondPass sp = (SecondPass) iter.next();
-			//do the SecondaryTable second pass before any association becasue associations can be built on joins 
-			if ( sp instanceof SecondaryTableSecondPass ) {
-				sp.doSecondPass( classes );
-				iter.remove();
+			iter = secondPasses.iterator();
+			while ( iter.hasNext() ) {
+				SecondPass sp = (SecondPass) iter.next();
+				//do the SecondaryTable second pass before any association becasue associations can be built on joins
+				if ( sp instanceof SecondaryTableSecondPass ) {
+					sp.doSecondPass( classes );
+					iter.remove();
+				}
 			}
+			super.secondPassCompile();
+			inSecondPass = false;
 		}
-		super.secondPassCompile();
-		inSecondPass = false;
+		catch (RecoverableException e) {
+			//the exception was not recoverable after all
+			throw (RuntimeException) e.getCause();
+		}
 		Iterator tables = tableUniqueConstraints.entrySet().iterator();
 		Table table;
 		Map.Entry entry;
@@ -476,10 +481,34 @@
 			while ( it.hasNext() ) {
 				( (SecondPass) it.next() ).doSecondPass( classes );
 			}
-			it = endOfQueueFkSecondPasses.listIterator();
-			while ( it.hasNext() ) {
-				( (SecondPass) it.next() ).doSecondPass( classes );
+
+			/*
+			 * If a second pass raises a recoverableException, queue it for next round
+			 * stop of no pass has to be processed or if the number of pass to processes
+			 * does not diminish between two rounds.
+			 * If some failing pass remain, raise the original exception
+			 */
+			boolean stopProcess = false;
+			RuntimeException originalException = null;
+			while ( ! stopProcess ) {
+				List failingSecondPasses = new ArrayList();
+				it = endOfQueueFkSecondPasses.listIterator();
+				while ( it.hasNext() ) {
+					final SecondPass pass = (SecondPass) it.next();
+					try {
+						pass.doSecondPass( classes );
+					}
+					catch (RecoverableException e) {
+						failingSecondPasses.add( pass );
+						if (originalException == null) originalException = (RuntimeException) e.getCause();
+					}
+				}
+				stopProcess = failingSecondPasses.size() == 0 || failingSecondPasses.size() == endOfQueueFkSecondPasses.size();
+				endOfQueueFkSecondPasses = failingSecondPasses;
 			}
+			if (endOfQueueFkSecondPasses.size() > 0) {
+				throw originalException;
+			}
 		}
 	}
 

Modified: annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java	2008-03-04 18:07:28 UTC (rev 14388)
+++ annotations/trunk/src/java/org/hibernate/cfg/Ejb3JoinColumn.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -391,11 +391,16 @@
 				referencedEntity, columns[0].getReferencedColumn(), mappings
 		);
 		if ( columnOwner == null ) {
-			throw new MappingException(
-					"Unable to find column with logical name: "
-							+ columns[0].getReferencedColumn() + " in " + referencedEntity.getTable() + " and its related "
-							+ "supertables and secondary tables"
-			);
+			try {
+				throw new MappingException(
+						"Unable to find column with logical name: "
+								+ columns[0].getReferencedColumn() + " in " + referencedEntity.getTable() + " and its related "
+								+ "supertables and secondary tables"
+				);
+			}
+			catch (MappingException e) {
+				throw new RecoverableException(e);
+			}
 		}
 		Table matchingTable = columnOwner instanceof PersistentClass ?
 				( (PersistentClass) columnOwner ).getTable() :

Added: annotations/trunk/src/java/org/hibernate/cfg/RecoverableException.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/RecoverableException.java	                        (rev 0)
+++ annotations/trunk/src/java/org/hibernate/cfg/RecoverableException.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,25 @@
+//$
+package org.hibernate.cfg;
+
+import org.hibernate.AnnotationException;
+
+/**
+ * Should neven be exposed to the client
+ * An exception that wrap an underlying exception whith the hope
+ * subsequent processing will recover from it.
+ *
+ * @author Emmanuel Bernard
+ */
+public class RecoverableException extends AnnotationException {
+	public RecoverableException(String msg, Throwable root) {
+		super( msg, root );
+	}
+
+	public RecoverableException(Throwable root) {
+		super( root );
+	}
+
+	public RecoverableException(String s) {
+		super( s );
+	}
+}

Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/GenericObject.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/GenericObject.java	                        (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/GenericObject.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,68 @@
+//$
+package org.hibernate.test.annotations.manytoone.referencedcolumnname;
+
+import java.io.Serializable;
+import java.rmi.server.UID;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Transient;
+import javax.persistence.Version;
+
+ at MappedSuperclass
+public class GenericObject implements Serializable {
+	protected int id;
+	protected int version;
+	protected UID uid = new UID();
+
+	@Id
+	@GeneratedValue( strategy = GenerationType.IDENTITY )
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+
+	@Version
+	public int getVersion() {
+		return version;
+	}
+
+	public void setVersion(int version) {
+		this.version = version;
+	}
+
+	public void incrementVersion() {
+		this.version++;
+	}
+
+	public boolean equals(Object other) {
+		if ( this == other )
+			return true;
+		if ( ( other == null ) || !( other.getClass().equals( this.getClass() ) ) )
+			return false;
+		GenericObject anObject = (GenericObject) other;
+		if ( this.id == 0 || anObject.id == 0 )
+			return false;
+
+		return ( this.id == anObject.id );
+	}
+
+	public int hashCode() {
+		if ( this.id == 0 )
+			return super.hashCode();
+		return this.id;
+	}
+
+	@Transient
+	public UID getUid() {
+		return uid;
+	}
+
+	public void setUid(UID uid) {
+		this.uid = uid;
+	}
+}

Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Item.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Item.java	                        (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Item.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,13 @@
+//$
+package org.hibernate.test.annotations.manytoone.referencedcolumnname;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.Transient;
+
+
+ at Entity
+public class Item extends GenericObject {
+}

Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ManyToOneReferencedColumnNameTest.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ManyToOneReferencedColumnNameTest.java	                        (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ManyToOneReferencedColumnNameTest.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,45 @@
+//$
+package org.hibernate.test.annotations.manytoone.referencedcolumnname;
+
+import java.math.BigDecimal;
+
+import org.hibernate.test.annotations.TestCase;
+import org.hibernate.Session;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ManyToOneReferencedColumnNameTest extends TestCase {
+	public void testReoverableExceptionInFkOrdering() throws Exception {
+		//SF should not blow up
+		Vendor v = new Vendor();
+		Item i = new Item();
+		ZItemCost ic = new ZItemCost();
+		ic.setCost( new BigDecimal(2) );
+		ic.setItem( i );
+		ic.setVendor( v );
+		WarehouseItem wi = new WarehouseItem();
+		wi.setDefaultCost( ic );
+		wi.setItem( i );
+		wi.setVendor( v );
+		wi.setQtyInStock( new BigDecimal(2) );
+		Session s = openSession(  );
+		s.getTransaction().begin();
+		s.save( i );
+		s.save( v );
+		s.save( ic );
+		s.save( wi );
+		s.flush();
+		s.getTransaction().rollback();
+		s.close();
+		
+	}
+	protected Class[] getMappings() {
+		return new Class[] {
+				Item.class,
+				Vendor.class,
+				WarehouseItem.class,
+				ZItemCost.class
+		};
+	}
+}

Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Vendor.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Vendor.java	                        (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/Vendor.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,12 @@
+//$
+package org.hibernate.test.annotations.manytoone.referencedcolumnname;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.Transient;
+
+ at Entity
+public class Vendor extends GenericObject {
+}
\ No newline at end of file

Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/WarehouseItem.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/WarehouseItem.java	                        (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/WarehouseItem.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,62 @@
+//$
+package org.hibernate.test.annotations.manytoone.referencedcolumnname;
+
+import java.math.BigDecimal;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.ManyToOne;
+
+ at Entity
+public class WarehouseItem extends GenericObject {
+
+
+	Item item;
+	Vendor vendor;
+	ZItemCost defaultCost;
+	BigDecimal qtyInStock;
+
+
+	public BigDecimal getQtyInStock() {
+		return qtyInStock;
+	}
+
+	public void setQtyInStock(BigDecimal qtyInStock) {
+		this.qtyInStock = qtyInStock;
+	}
+
+	@ManyToOne
+//(fetch=FetchType.LAZY)
+	@JoinColumn( name = "ITEM_ID", unique = false, nullable = false, insertable = true, updatable = true )
+	public Item getItem() {
+		return item;
+	}
+
+	public void setItem(Item item) {
+		this.item = item;
+	}
+
+	@ManyToOne( fetch = FetchType.LAZY )
+	@JoinColumn( name = "VENDOR_ID", unique = false, nullable = false, insertable = true, updatable = true )
+	public Vendor getVendor() {
+		return vendor;
+	}
+
+	public void setVendor(Vendor vendor) {
+		this.vendor = vendor;
+	}
+
+	@ManyToOne
+	@JoinColumns( {
+	@JoinColumn( name = "vendor_id", referencedColumnName = "vendor_id", insertable = false, updatable = false ),
+	@JoinColumn( name = "item_id", referencedColumnName = "item_id", insertable = false, updatable = false )
+			} )
+	public ZItemCost getDefaultCost() {
+		return defaultCost;
+	}
+
+	public void setDefaultCost(ZItemCost defaultCost) {
+		this.defaultCost = defaultCost;
+	}
+}

Added: annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ZItemCost.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ZItemCost.java	                        (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/manytoone/referencedcolumnname/ZItemCost.java	2008-03-04 21:22:12 UTC (rev 14389)
@@ -0,0 +1,46 @@
+//$
+package org.hibernate.test.annotations.manytoone.referencedcolumnname;
+
+import java.math.BigDecimal;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.ManyToOne;
+import javax.persistence.Transient;
+import javax.persistence.JoinColumn;
+
+ at Entity
+public class ZItemCost extends GenericObject {
+
+	Item item;
+	Vendor vendor;
+	BigDecimal cost;
+
+	@ManyToOne( fetch = FetchType.LAZY )
+	//@JoinColumn(name="ITEM_ID", unique=false, nullable=false, insertable=true, updatable=true)
+	public Item getItem() {
+		return item;
+	}
+
+	public void setItem(Item item) {
+		this.item = item;
+	}
+
+	@ManyToOne( fetch = FetchType.LAZY )
+	//@JoinColumn(name="VENDOR_ID", unique=false, nullable=false, insertable=true, updatable=true)
+	public Vendor getVendor() {
+		return vendor;
+	}
+
+	public void setVendor(Vendor vendor) {
+		this.vendor = vendor;
+	}
+
+	public BigDecimal getCost() {
+		return cost;
+	}
+
+	public void setCost(BigDecimal cost) {
+		this.cost = cost;
+	}
+}
+




More information about the hibernate-commits mailing list