|
From: <hib...@li...> - 2006-08-04 08:42:04
|
Author: max...@jb...
Date: 2006-08-04 04:41:47 -0400 (Fri, 04 Aug 2006)
New Revision: 10211
Added:
trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/ManyToManyTest.java
Modified:
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/JDBCBinder.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DefaultReverseEngineeringStrategy.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DelegatingReverseEngineeringStrategy.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringSettings.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringStrategy.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/AbstractExporter.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/BasicPOJOClass.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/POJOClass.java
trunk/HibernateExt/tools/src/templates/pojo/PojoConstructors.ftl
trunk/HibernateExt/tools/src/test/org/hibernate/tool/BaseTestCase.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/SeamAntTest.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Constructors.hbm.xml
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2JavaConstructorTest.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/hbm2hbmxml/ManyToManyTest.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/OverrideBinderTest.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/foreignkeytest.reveng.xml
trunk/HibernateExt/tools/src/testsupport/NoopReverseEngineeringStrategy.java
Log:
HBX-132 support many-to-many (core impl, not exposed in ui/reveng.xml/ant)
HBX-584 single field constructor problem + reveng primarykey handling
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/JDBCBinder.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/JDBCBinder.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/JDBCBinder.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -4,6 +4,7 @@
*/
package org.hibernate.cfg;
+import java.beans.Introspector;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
@@ -137,6 +138,12 @@
continue;
// TODO: just create one big embedded composite id instead.
}*/
+
+ if(revengStrategy.isManyToManyTable(table)) {
+ log.debug( "Ignoring " + table + " as class since rev.eng. says it is a many-to-many" );
+ continue;
+ }
+
RootClass rc = new RootClass();
TableIdentifier tableIdentifier = TableIdentifier.create(table);
String className = revengStrategy.tableToClassName( tableIdentifier );
@@ -169,11 +176,12 @@
}
+ // bind collections.
private void bindIncomingForeignKeys(PersistentClass rc, Set processed, List foreignKeys, Mapping mapping) {
if(foreignKeys!=null) {
for (Iterator iter = foreignKeys.iterator(); iter.hasNext();) {
ForeignKey foreignKey = (ForeignKey) iter.next();
-
+
if(revengStrategy.excludeForeignKeyAsCollection(
foreignKey.getName(),
TableIdentifier.create(foreignKey.getTable() ),
@@ -182,6 +190,7 @@
foreignKey.getReferencedColumns())) {
log.debug("Rev.eng excluded one-to-many for foreignkey " + foreignKey.getName());
} else {
+
Property property = bindOneToMany(rc, foreignKey, processed, mapping);
rc.addProperty(property);
}
@@ -222,46 +231,54 @@
Table collectionTable = foreignKey.getTable();
Collection collection = new org.hibernate.mapping.Set(rc); // MASTER TODO: allow overriding collection type
-
+
collection.setCollectionTable(collectionTable); // CHILD+
- boolean b = isUniqueReference(foreignKey);
- TableIdentifier foreignKeyTable = TableIdentifier.create( foreignKey.getTable() );
- TableIdentifier foreignKeyReferencedTable = TableIdentifier.create( foreignKey.getReferencedTable() );
- String collectionRole = revengStrategy.foreignKeyToCollectionName(
- foreignKey.getName(),
- foreignKeyTable,
- foreignKey.getColumns(),
- foreignKeyReferencedTable,
- foreignKey.getReferencedColumns(),
- b
- );
- collectionRole = makeUnique(rc,collectionRole);
+
+ boolean manyToMany = revengStrategy.isManyToManyTable( collectionTable );
+ if(manyToMany) {
+ log.debug("Rev.eng said here is a many-to-many");
+ // TODO: handle "the other side should influence the name"
+ }
- String fullRolePath = StringHelper.qualify(rc.getEntityName(), collectionRole);
- if (mappings.getCollection(fullRolePath)!=null) {
- log.debug(fullRolePath + " found twice!");
+
+
+ if(manyToMany) {
+
+ ManyToOne element = new ManyToOne( collection.getCollectionTable() );
+ //TODO: find the other foreignkey and choose the other side.
+ Iterator foreignKeyIterator = foreignKey.getTable().getForeignKeyIterator();
+ List keys = new ArrayList();
+ while ( foreignKeyIterator.hasNext() ) {
+ Object next = foreignKeyIterator.next();
+ if(next!=foreignKey) {
+ keys.add(next);
+ }
+ }
+
+ if(keys.size()>1) {
+ throw new JDBCBinderException("more than one other foreign key to choose from!"); // todo: hande better ?
+ }
+
+ ForeignKey fk = (ForeignKey) keys.get( 0 );
+
+ String tableToClassName = bindCollection( rc, foreignKey, fk, collection );
+
+ element.setReferencedEntityName( tableToClassName );
+ element.addColumn( fk.getColumn( 0 ) );
+ collection.setElement( element );
+
+ } else {
+ String tableToClassName = bindCollection( rc, foreignKey, null, collection );
+
+ OneToMany oneToMany = new OneToMany( collection.getOwner() );
+
+ oneToMany.setReferencedEntityName( tableToClassName ); // Child
+ mappings.addSecondPass( new JDBCCollectionSecondPass(mappings, collection) );
+
+ collection.setElement(oneToMany);
}
- collection.setRole(fullRolePath); // Master.setOfChildren+
- collection.setInverse(revengStrategy.isForeignKeyCollectionInverse(foreignKey.getName(),
- foreignKeyTable,
- foreignKey.getColumns(),
- foreignKeyReferencedTable,
- foreignKey.getReferencedColumns())); // TODO: allow overriding this
- collection.setLazy(revengStrategy.isForeignKeyCollectionLazy(foreignKey.getName(),
- foreignKeyTable,
- foreignKey.getColumns(),
- foreignKeyReferencedTable,
- foreignKey.getReferencedColumns()));
- collection.setFetchMode(FetchMode.SELECT);
-
- OneToMany oneToMany = new OneToMany( collection.getOwner() );
- oneToMany.setReferencedEntityName( revengStrategy.tableToClassName( foreignKeyTable ) ); // Child
-
- mappings.addSecondPass( new JDBCCollectionSecondPass(mappings, collection) );
- collection.setElement(oneToMany);
-
// bind keyvalue
KeyValue referencedKeyValue;
String propRef = collection.getReferencedPropertyName();
@@ -289,10 +306,74 @@
mappings.addCollection(collection);
- return makeProperty(collectionRole, collection, true, true, true, "all", null);
+ return makeProperty(StringHelper.unqualify( collection.getRole() ), collection, true, true, true, "all", null); // TODO: cascade isn't all by default
}
+ private String bindCollection(PersistentClass rc, ForeignKey fromForeignKey, ForeignKey toForeignKey, Collection collection) {
+ ForeignKey targetKey = fromForeignKey;
+ String collectionRole = null;
+ boolean collectionLazy = false;
+ boolean collectionInverse = false;
+ TableIdentifier foreignKeyTable = null;
+ String tableToClassName;
+
+ if(toForeignKey!=null) {
+ targetKey = toForeignKey;
+ }
+
+ boolean uniqueReference = isUniqueReference(targetKey);
+ foreignKeyTable = TableIdentifier.create( targetKey.getTable() );
+ TableIdentifier foreignKeyReferencedTable = TableIdentifier.create( targetKey.getReferencedTable() );
+
+ if(toForeignKey==null) {
+
+ collectionRole = revengStrategy.foreignKeyToCollectionName(
+ fromForeignKey.getName(),
+ foreignKeyTable,
+ fromForeignKey.getColumns(),
+ foreignKeyReferencedTable,
+ fromForeignKey.getReferencedColumns(),
+ uniqueReference
+ );
+
+ tableToClassName = revengStrategy.tableToClassName( foreignKeyTable );
+ } else {
+
+ collectionRole = revengStrategy.foreignKeyToManyToManyName(
+ fromForeignKey, TableIdentifier.create( fromForeignKey.getTable()), toForeignKey, uniqueReference );
+
+ tableToClassName = revengStrategy.tableToClassName( foreignKeyReferencedTable );
+ }
+
+ collectionInverse = revengStrategy.isForeignKeyCollectionInverse(targetKey.getName(),
+ foreignKeyTable,
+ targetKey.getColumns(),
+ foreignKeyReferencedTable,
+ targetKey.getReferencedColumns());
+
+ collectionLazy = revengStrategy.isForeignKeyCollectionLazy(targetKey.getName(),
+ foreignKeyTable,
+ targetKey.getColumns(),
+ foreignKeyReferencedTable,
+ targetKey.getReferencedColumns());
+
+ collectionRole = makeUnique(rc,collectionRole);
+
+ String fullRolePath = StringHelper.qualify(rc.getEntityName(), collectionRole);
+ if (mappings.getCollection(fullRolePath)!=null) {
+ log.debug(fullRolePath + " found twice!");
+ }
+
+ collection.setRole(fullRolePath); // Master.setOfChildren+
+ collection.setInverse(collectionInverse); // TODO: allow overriding this
+ collection.setLazy(collectionLazy);
+ collection.setFetchMode(FetchMode.SELECT);
+
+
+ return tableToClassName;
+ }
+
/** return true if this foreignkey is the only reference from this table to the same foreign table */
private boolean isUniqueReference(ForeignKey foreignKey) {
@@ -326,10 +407,14 @@
final TableIdentifier tableIdentifier = TableIdentifier.create(table);
- String tableIdentifierStrategyName = revengStrategy.getTableIdentifierStrategyName(tableIdentifier);
- boolean naturalId = "assigned".equals(tableIdentifierStrategyName);
+ String tableIdentifierStrategyName = null;
+ boolean naturalId;
+
if (keyColumns.size()>1) {
+ tableIdentifierStrategyName = "assigned";
+ naturalId = true;
+
id = handleCompositeKey(rc, processed, keyColumns, mapping);
idPropertyname = revengStrategy.tableToIdentifierPropertyName(tableIdentifier);
if(idPropertyname==null) {
@@ -337,6 +422,8 @@
}
}
else {
+ tableIdentifierStrategyName = revengStrategy.getTableIdentifierStrategyName(tableIdentifier);
+ naturalId = "assigned".equals( tableIdentifierStrategyName );
Column pkc = (Column) keyColumns.get(0);
checkColumn(pkc);
@@ -363,6 +450,7 @@
}
/**
+ * bind many-to-ones
* @param table
* @param rc
* @param primaryKey
@@ -784,7 +872,7 @@
PersistentClass persistentClass = mappings.getClass(oneToMany.getReferencedEntityName() );
if (persistentClass==null) throw new MappingException(
- "Association references unmapped class: " + oneToMany.getReferencedEntityName()
+ "Association " + collection.getRole() + " references unmapped class: " + oneToMany.getReferencedEntityName()
);
oneToMany.setAssociatedClass(persistentClass); // Child
@@ -809,4 +897,5 @@
JDBCBinder.bindCollectionSecondPass(collection, persistentClasses, mappings, inheritedMetas);
}
}
+
}
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DefaultReverseEngineeringStrategy.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DefaultReverseEngineeringStrategy.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DefaultReverseEngineeringStrategy.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -1,8 +1,10 @@
package org.hibernate.cfg.reveng;
import java.beans.Introspector;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -12,6 +14,9 @@
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.mapping.Column;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.PrimaryKey;
+import org.hibernate.mapping.Table;
import org.hibernate.util.StringHelper;
public class DefaultReverseEngineeringStrategy implements ReverseEngineeringStrategy {
@@ -193,5 +198,53 @@
public void setSettings(ReverseEngineeringSettings settings) {
this.settings = settings;
}
+
+ public boolean isManyToManyTable(Table table) {
+ if(settings.getAutoManyToManyDetection()) {
+ Iterator foreignKeyIterator = table.getForeignKeyIterator();
+ List foreignKeys = new ArrayList();
+ while ( foreignKeyIterator.hasNext() ) {
+ ForeignKey fkey = (ForeignKey) foreignKeyIterator.next();
+ foreignKeys.add( fkey );
+ if(foreignKeys.size()>2) {
+ return false; // early exit if we have more than one fk.
+ }
+ }
+
+ Set columns = new HashSet();
+ Iterator columnIterator = table.getColumnIterator();
+ while ( columnIterator.hasNext() ) {
+ Column column = (Column) columnIterator.next();
+ columns.add(column);
+ }
+
+ foreignKeyIterator = table.getForeignKeyIterator();
+ while ( !columns.isEmpty() && foreignKeyIterator.hasNext() ) {
+ ForeignKey element = (ForeignKey) foreignKeyIterator.next();
+ columns.removeAll( element.getColumns() );
+ }
+ // what if one of the columns is not the primary key?
+ return columns.isEmpty();
+ } else {
+ return false;
+ }
+ }
+
+ public String foreignKeyToManyToManyName(ForeignKey fromKey, TableIdentifier middleTable, ForeignKey toKey, boolean uniqueReference) {
+ String propertyName = Introspector.decapitalize( StringHelper.unqualify( tableToClassName(TableIdentifier.create( toKey.getReferencedTable()) )) );
+ propertyName = pluralize( propertyName );
+
+ if(!uniqueReference) {
+ //TODO: maybe use the middleTable name here ?
+ if(toKey.getColumns()!=null && toKey.getColumns().size()==1) {
+ String columnName = ( (Column) toKey.getColumns().get(0) ).getName();
+ propertyName = propertyName + "For" + toUpperCamelCase(columnName);
+ }
+ else { // composite key or no columns at all safeguard
+ propertyName = propertyName + "For" + toUpperCamelCase(toKey.getName());
+ }
+ }
+ return propertyName;
+ }
}
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DelegatingReverseEngineeringStrategy.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DelegatingReverseEngineeringStrategy.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/DelegatingReverseEngineeringStrategy.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -5,6 +5,8 @@
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.Table;
public class DelegatingReverseEngineeringStrategy implements ReverseEngineeringStrategy {
@@ -108,6 +110,14 @@
public void setSettings(ReverseEngineeringSettings settings) {
if(delegate!=null) delegate.setSettings(settings);
- }
+ }
+
+ public boolean isManyToManyTable(Table table) {
+ return delegate==null?true:delegate.isManyToManyTable( table );
+ }
+
+ public String foreignKeyToManyToManyName(ForeignKey fromKey, TableIdentifier middleTable, ForeignKey toKey, boolean uniqueReference) {
+ return delegate==null?null:delegate.foreignKeyToManyToManyName( fromKey, middleTable, toKey, uniqueReference );
+ }
}
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -16,7 +16,6 @@
import org.apache.commons.logging.LogFactory;
import org.hibernate.JDBCException;
import org.hibernate.MappingException;
-import org.hibernate.cfg.JDBCBinder;
import org.hibernate.cfg.JDBCBinderException;
import org.hibernate.cfg.reveng.dialect.MetaDataDialect;
import org.hibernate.connection.ConnectionProvider;
@@ -84,17 +83,24 @@
}
tables = dbs.iterateTables();
- Map oneToManyCandidates = new HashMap();
+ List fks = new ArrayList();
while ( tables.hasNext() ) {
Table table = (Table) tables.next();
// Done here after the basic process of collections as we might not have touched
// all referenced tables (this ensure the columns are the same instances througout the basic JDBC derived model.
// after this stage it should be "ok" to divert from keeping columns in sync as it can be required if the same
//column is used with different aliases in the ORM mapping.
- Map foreignKeys = processForeignKeys(dbs, table, progress);
- mergeMultiMap(oneToManyCandidates, foreignKeys);
+ ForeignKeysInfo foreignKeys = processForeignKeys(dbs, table, progress);
+ fks.add( foreignKeys );
}
+ Map oneToManyCandidates = new HashMap();
+ for (Iterator iter = fks.iterator(); iter.hasNext();) {
+ ForeignKeysInfo element = (ForeignKeysInfo) iter.next();
+ Map map = element.process( revengStrategy );
+ mergeMultiMap( oneToManyCandidates, map );
+ }
+
dbs.setOneToManyCandidates(oneToManyCandidates);
return dbs;
@@ -104,8 +110,43 @@
}
}
+ static class ForeignKeysInfo {
+
+ final Map dependentTables;
+ final Map dependentColumns;
+ final Map referencedColumns;
+ private final Table referencedTable;
+
+ public ForeignKeysInfo(Table referencedTable, Map tables, Map columns, Map refColumns) {
+ this.referencedTable = referencedTable;
+ this.dependentTables = tables;
+ this.dependentColumns = columns;
+ this.referencedColumns = refColumns;
+ }
+
+ Map process(ReverseEngineeringStrategy revengStrategy) {
+ Map oneToManyCandidates = new HashMap();
+ Iterator iterator = dependentTables.entrySet().iterator();
+ while (iterator.hasNext() ) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String fkName = (String) entry.getKey();
+ Table fkTable = (Table) entry.getValue();
+ List columns = (List) dependentColumns.get(fkName);
+ List refColumns = (List) referencedColumns.get(fkName);
+
+ String className = revengStrategy.tableToClassName(TableIdentifier.create(referencedTable) );
+
+ ForeignKey key = fkTable.createForeignKey(fkName, columns, className, refColumns);
+ key.setReferencedTable(referencedTable);
+
+ addToMultiMap(oneToManyCandidates, className, key);
+ }
+ // map<className, foreignkey>
+ return oneToManyCandidates;
+ }
+ }
- protected Map processForeignKeys(DatabaseCollector dbs, Table referencedTable, ProgressListener progress) throws JDBCBinderException {
+ protected ForeignKeysInfo processForeignKeys(DatabaseCollector dbs, Table referencedTable, ProgressListener progress) throws JDBCBinderException {
// foreign key name to list of columns
Map dependentColumns = new HashMap();
// foreign key name to Table
@@ -250,26 +291,9 @@
}
- Map oneToManyCandidates = new HashMap();
- Iterator iterator = dependentTables.entrySet().iterator();
- while (iterator.hasNext() ) {
- Map.Entry entry = (Map.Entry) iterator.next();
- String fkName = (String) entry.getKey();
- Table fkTable = (Table) entry.getValue();
- List columns = (List) dependentColumns.get(fkName);
- List refColumns = (List) referencedColumns.get(fkName);
-
- String className = revengStrategy.tableToClassName(TableIdentifier.create(referencedTable) );
-
- ForeignKey key = fkTable.createForeignKey(fkName, columns, className, refColumns);
- key.setReferencedTable(referencedTable);
-
-
- addToMultiMap(oneToManyCandidates, className, key);
- }
- // map<className, foreignkey>
- return oneToManyCandidates;
- }
+ return new ForeignKeysInfo(referencedTable, dependentTables, dependentColumns, referencedColumns);
+
+ }
/**
@@ -755,7 +779,7 @@
return false;
}
- private void addToMultiMap(Map multimap, String key, Object item) {
+ static private void addToMultiMap(Map multimap, String key, Object item) {
List existing = (List) multimap.get(key);
if(existing == null) {
existing = new ArrayList();
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringSettings.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringSettings.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringSettings.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -9,6 +9,7 @@
private boolean autoOptimisticLockDetection = true;
private boolean createCollectionForForeignKey = true;
private boolean createManyToOneForForeignKey = true;
+ private boolean autoManyToManyDetection;
//public ReverseEngineeringSettings(ReverseEngineeringStrategy rootStrategy) {
// this.rootStrategy = rootStrategy;
@@ -60,7 +61,16 @@
this.createManyToOneForForeignKey = createManyToOneForForeignKey;
return this;
}
+
+ public ReverseEngineeringSettings setAutoManyToManyDetection(boolean b) {
+ this.autoManyToManyDetection = b;
+ return this;
+ }
+ public boolean getAutoManyToManyDetection() {
+ return autoManyToManyDetection;
+ }
+
/** return the top/root strategy. Allows a lower strategy to ask another question. Dangerous to do since recursive loops can easily occur! */
/*public ReverseEngineeringStrategy getRootStrategy() {
return rootStrategy;
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringStrategy.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringStrategy.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/ReverseEngineeringStrategy.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -5,6 +5,8 @@
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.Table;
public interface ReverseEngineeringStrategy {
@@ -33,7 +35,7 @@
/**
*
- * @return a fully-qualified class name (must be aligned with tableToPackageName and tableToSimpleClassName)
+ * @return a fully-qualified class name
*/
public String tableToClassName(TableIdentifier tableIdentifier);
@@ -43,37 +45,7 @@
* @return a property name
*/
public String columnToPropertyName(TableIdentifier table, String column);
-
- /** Should this foreignkey be excluded as a oneToMany */
- public boolean excludeForeignKeyAsCollection(String keyname, TableIdentifier fromTable, List fromColumns, TableIdentifier referencedTable, List referencedColumns);
-
- /** Should this foreignkey be excluded as a many-to-one */
- public boolean excludeForeignKeyAsManytoOne(String keyname, TableIdentifier fromTable, List fromColumns, TableIdentifier referencedTable, List referencedColumns);
-
- /** is the collection inverse or not ? */
- public boolean isForeignKeyCollectionInverse(String name, TableIdentifier foreignKeyTable, List columns, TableIdentifier foreignKeyReferencedTable, List referencedColumns);
-
- /** is the collection lazy or not ? */
- public boolean isForeignKeyCollectionLazy(String name, TableIdentifier foreignKeyTable, List columns, TableIdentifier foreignKeyReferencedTable, List referencedColumns);
-
- /**
- * Return a collection role name for a Collection based on the foreignkey.
- * @param fromColumns list of Column instances on the fromTable. Only col.getName() should be assumed to be correct
- * @param referencedColumns list of Column instances on the referenced Table. Only col.getName() should be assumed to be correct
- * @param uniqueReference true if there is no other references to the same table
- * @return
- */
- public String foreignKeyToCollectionName(String keyname, TableIdentifier fromTable, List fromColumns, TableIdentifier referencedTable, List referencedColumns, boolean uniqueReference);
-
- /**
- *
- * @param fromColumns list of Column instances on the fromTable. Only col.getName() should be assumed to be correct
- * @param referencedColumns list of Column instances on the referenced Table. Only col.getName() should be assumed to be correct
- * @param uniqueReference true if there is no other references to the same table
- * @return
- */
- public String foreignKeyToEntityName(String keyname, TableIdentifier fromTable, List fromColumnNames, TableIdentifier referencedTable, List referencedColumnNames, boolean uniqueReference);
-
+
public boolean excludeTable(TableIdentifier ti);
public boolean excludeColumn(TableIdentifier identifier, String columnName);
@@ -135,8 +107,50 @@
public String tableToCompositeIdName(TableIdentifier identifier);
+ /** Should this foreignkey be excluded as a oneToMany */
+ public boolean excludeForeignKeyAsCollection(String keyname, TableIdentifier fromTable, List fromColumns, TableIdentifier referencedTable, List referencedColumns);
+ /** Should this foreignkey be excluded as a many-to-one */
+ public boolean excludeForeignKeyAsManytoOne(String keyname, TableIdentifier fromTable, List fromColumns, TableIdentifier referencedTable, List referencedColumns);
+ /** is the collection inverse or not ? */
+ public boolean isForeignKeyCollectionInverse(String name, TableIdentifier foreignKeyTable, List columns, TableIdentifier foreignKeyReferencedTable, List referencedColumns);
+
+ /** is the collection lazy or not ? */
+ public boolean isForeignKeyCollectionLazy(String name, TableIdentifier foreignKeyTable, List columns, TableIdentifier foreignKeyReferencedTable, List referencedColumns);
+
+ /**
+ * Return a collection role name for a Collection based on the foreignkey.
+ * @param fromColumns list of Column instances on the fromTable. Only col.getName() should be assumed to be correct
+ * @param referencedColumns list of Column instances on the referenced Table. Only col.getName() should be assumed to be correct
+ * @param uniqueReference true if there is no other references to the same table
+ * @return
+ */
+ public String foreignKeyToCollectionName(String keyname, TableIdentifier fromTable, List fromColumns, TableIdentifier referencedTable, List referencedColumns, boolean uniqueReference);
+
+ /**
+ *
+ * @param fromColumns list of Column instances on the fromTable. Only col.getName() should be assumed to be correct
+ * @param referencedColumns list of Column instances on the referenced Table. Only col.getName() should be assumed to be correct
+ * @param uniqueReference true if there is no other references to the same table
+ * @return
+ */
+ public String foreignKeyToEntityName(String keyname, TableIdentifier fromTable, List fromColumnNames, TableIdentifier referencedTable, List referencedColumnNames, boolean uniqueReference);
-
+ /**
+ * @param table
+ * @return true if this table is considered to be a many-to-many table.
+ */
+ public boolean isManyToManyTable(Table table);
+
+ /**
+ *
+ * @param middleTable
+ * @param uniqueReference true if there is no other references to the same table
+ * @param fromColumns list of Column instances on the fromTable. Only col.getName() should be assumed to be correct
+ * @param referencedColumns list of Column instances on the referenced Table. Only col.getName() should be assumed to be correct
+ * @return
+ */
+ public String foreignKeyToManyToManyName(ForeignKey fromKey, TableIdentifier middleTable, ForeignKey toKey, boolean uniqueReference);
+
}
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/AbstractExporter.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/AbstractExporter.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/AbstractExporter.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -96,7 +96,7 @@
getArtifactCollector().formatFiles();
}
- abstract public void doStart();
+ abstract protected void doStart();
public String[] getTemplatePaths() {
return templatePaths;
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -60,7 +60,7 @@
}
}
- public void doStart() {
+ protected void doStart() {
if(filePattern==null) throw new ExporterException("File pattern not set on GenericExporter");
if(templateName==null) throw new ExporterException("Template pattern not set on GenericExporter");
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/BasicPOJOClass.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/BasicPOJOClass.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/BasicPOJOClass.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -804,10 +804,13 @@
List propClosure = getPropertyClosureForMinimalConstructor();
if(propClosure.isEmpty()) return false; // minimal=default
if(propClosure.equals(getPropertyClosureForFullConstructor())) return false; // minimal=full
-
return true;
}
+ public boolean needsFullConstructor() {
+ return !getPropertyClosureForFullConstructor().isEmpty();
+ }
+
public String getJavaTypeName(Property p, boolean useGenerics) {
return c2j.getJavaTypeName(p, useGenerics, this);
}
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/POJOClass.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/POJOClass.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/POJOClass.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -94,6 +94,7 @@
public List getPropertyClosureForSuperclassFullConstructor();
public boolean needsMinimalConstructor();
+ public boolean needsFullConstructor();
public List getPropertiesForMinimalConstructor();
public List getPropertyClosureForMinimalConstructor();
public List getPropertyClosureForSuperclassMinimalConstructor();
Modified: trunk/HibernateExt/tools/src/templates/pojo/PojoConstructors.ftl
===================================================================
--- trunk/HibernateExt/tools/src/templates/pojo/PojoConstructors.ftl 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/templates/pojo/PojoConstructors.ftl 2006-08-04 08:41:47 UTC (rev 10211)
@@ -14,6 +14,7 @@
</#foreach>
}
</#if>
+<#if pojo.needsFullConstructor()>
/** full constructor */
public ${pojo.getDeclarationName()}(${c2j.asParameterList(pojo.getPropertyClosureForFullConstructor(), jdk5, pojo)}) {
<#if pojo.isSubclass() && !pojo.getPropertyClosureForSuperclassFullConstructor().isEmpty()>
@@ -23,4 +24,4 @@
this.${field.name} = ${field.name};
</#foreach>
}
-
+</#if>
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/BaseTestCase.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/BaseTestCase.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/BaseTestCase.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -49,7 +49,7 @@
}
- protected void assertFileAndExists(File file) {
+ static protected void assertFileAndExists(File file) {
assertTrue(file + " does not exist", file.exists() );
assertTrue(file + " not a file", file.isFile() );
assertTrue(file + " does not have any contents", file.length()>0);
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/SeamAntTest.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/SeamAntTest.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/SeamAntTest.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -117,10 +117,5 @@
assertNotNull(document);
return document;
}
-
- protected void assertFileAndExists(File file) {
- assertTrue(file + " does not exist", file.exists() );
- assertTrue(file + " not a file", file.isFile() );
- assertTrue(file + " does not have any contents", file.length()>0);
- }
+
}
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Constructors.hbm.xml
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Constructors.hbm.xml 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Constructors.hbm.xml 2006-08-04 08:41:47 UTC (rev 10211)
@@ -59,5 +59,13 @@
<version name="aVersion" type="long"/>
<property name="name" type="string"/>
</class>
+
+ <!-- HBX-584 -->
+ <class name="SingleFieldClass">
+ <id name="id" type="string">
+ <generator class="native"/>
+ </id>
+ </class>
+
</hibernate-mapping>
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2JavaConstructorTest.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2JavaConstructorTest.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2JavaConstructorTest.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -108,6 +108,12 @@
}
+ public void testSingleFieldLogic() {
+
+
+ }
+
+
public void testMinimal() {
POJOClass bp = new EntityPOJOClass(getCfg().getClassMapping("BrandProduct"), new Cfg2JavaTool());
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/hbm2hbmxml/ManyToManyTest.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/hbm2hbmxml/ManyToManyTest.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/hbm2hbmxml/ManyToManyTest.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -17,7 +17,6 @@
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
-import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.hibernate.cfg.Configuration;
Added: trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/ManyToManyTest.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/ManyToManyTest.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/ManyToManyTest.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -0,0 +1,161 @@
+/*
+ * Created on 2004-12-01
+ *
+ */
+package org.hibernate.tool.test.jdbc2cfg;
+
+import java.io.File;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.MappingException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.JDBCMetaDataConfiguration;
+import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
+import org.hibernate.cfg.reveng.ReverseEngineeringSettings;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.tool.JDBCMetaDataBinderTestCase;
+import org.hibernate.tool.hbm2x.HibernateMappingExporter;
+
+/**
+ * @author max
+ *
+ */
+public class ManyToManyTest extends JDBCMetaDataBinderTestCase {
+
+ public static Test suite() {
+ return new TestSuite(ManyToManyTest.class);
+ }
+
+ private JDBCMetaDataConfiguration localCfg;
+
+ protected void configure(JDBCMetaDataConfiguration cfg) {
+ super.configure( cfg );
+
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ localCfg = new JDBCMetaDataConfiguration();
+
+ DefaultReverseEngineeringStrategy c = new DefaultReverseEngineeringStrategy();
+ c.setSettings(new ReverseEngineeringSettings().setAutoManyToManyDetection(true));
+ localCfg.setReverseEngineeringStrategy(c);
+ localCfg.readFromJDBC();
+ }
+ protected void tearDown() throws Exception {
+ localCfg = null;
+
+ super.tearDown();
+ }
+
+ public void testDefaultBiDirectional() {
+
+ PersistentClass project = cfg.getClassMapping("Project");
+
+ assertNotNull(project.getProperty("worksOns"));
+ //assertNotNull(project.getProperty("employee"));
+ assertEquals(3, project.getPropertyClosureSpan());
+ assertEquals("projectId", project.getIdentifierProperty().getName());
+
+ PersistentClass employee = cfg.getClassMapping("Employee");
+
+ assertNotNull(employee.getProperty("worksOns"));
+ assertNotNull(employee.getProperty("employees"));
+ assertNotNull(employee.getProperty("employee"));
+ //assertNotNull(employee.getProperty("projects"));
+ assertEquals(6, employee.getPropertyClosureSpan());
+ assertEquals("id", employee.getIdentifierProperty().getName());
+
+ PersistentClass worksOn = cfg.getClassMapping("WorksOn");
+
+ assertNotNull(worksOn.getProperty("project"));
+ assertNotNull(worksOn.getProperty("employee"));
+ assertEquals(2, worksOn.getPropertyClosureSpan());
+ assertEquals("id", worksOn.getIdentifierProperty().getName());
+ }
+
+ public void testAutoCreation() {
+
+ assertNull("No middle class should be generated.", localCfg.getClassMapping( "WorksOn" ));
+
+ assertNotNull("Should create worksontext since one of the foreign keys is not part of pk", localCfg.getClassMapping( "WorksOnContext" ));
+
+ PersistentClass projectClass = localCfg.getClassMapping("Project");
+ assertNotNull( projectClass );
+
+ PersistentClass employeeClass = localCfg.getClassMapping("Employee");
+ assertNotNull( employeeClass );
+
+ assertPropertyNotExist( projectClass, "worksOns" );
+ assertPropertyNotExist( employeeClass, "worksOns" );
+
+ Property property = employeeClass.getProperty( "projects" );
+ assertNotNull( property);
+ assertNotNull( projectClass.getProperty( "employees" ));
+
+ }
+
+ public void testBuildMappings() {
+
+ localCfg.buildMappings();
+ }
+
+ public void testGenerateAndReadable() {
+
+ localCfg.buildMappings();
+
+ HibernateMappingExporter hme = new HibernateMappingExporter(localCfg, getOutputDir());
+ hme.start();
+
+ assertFileAndExists( new File(getOutputDir(), "Employee.hbm.xml") );
+ assertFileAndExists( new File(getOutputDir(), "Project.hbm.xml") );
+ assertFileAndExists( new File(getOutputDir(), "WorksOnContext.hbm.xml") );
+
+ assertFalse(new File(getOutputDir(), "WorksOn.hbm.xml").exists() );
+
+ assertEquals(3, getOutputDir().listFiles().length);
+
+ Configuration configuration = new Configuration()
+ .addFile( new File(getOutputDir(), "Employee.hbm.xml") )
+ .addFile( new File(getOutputDir(), "Project.hbm.xml") )
+ .addFile( new File(getOutputDir(), "WorksOnContext.hbm.xml") );
+
+ configuration.buildMappings();
+
+ }
+
+
+ private void assertPropertyNotExist(PersistentClass projectClass, String prop) {
+ try {
+ projectClass.getProperty(prop);
+ fail("property " + prop + " should not exist on " + projectClass);
+ } catch(MappingException e) {
+ // expected
+ }
+ }
+
+ protected String[] getCreateSQL() {
+ return new String[] {
+ "create table PROJECT ( project_id integer not null, name varchar(50), primary key (project_id) )",
+ "create table EMPLOYEE ( id integer not null, name varchar(50), manager_id integer, primary key (id), constraint employee_manager foreign key (manager_id) references EMPLOYEE)",
+ "create table WORKS_ON ( project_id integer not null, employee_id integer not null, primary key (project_id, employee_id), constraint workson_employee foreign key (employee_id) references EMPLOYEE, foreign key (project_id) references PROJECT )",
+ "create table WORKS_ON_CONTEXT ( project_id integer not null, employee_id integer not null, created_by integer, primary key (project_id, employee_id), constraint workson_ctx_employee foreign key (employee_id) references EMPLOYEE, foreign key (project_id) references PROJECT, foreign key (created_by) references EMPLOYEE )",
+ //"alter table PROJECT add constraint project_manager foreign key (team_lead) references EMPLOYEE"
+ };
+ }
+
+ protected String[] getDropSQL() {
+ return new String[] {
+ //"alter table PROJECT drop constraint project_manager",
+ "drop table WORKS_ON_CONTEXT",
+ "drop table WORKS_ON",
+ "drop table EMPLOYEE",
+ "drop table PROJECT",
+ };
+ }
+
+}
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/OverrideBinderTest.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/OverrideBinderTest.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/OverrideBinderTest.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -184,8 +184,6 @@
assertNull(repository.getTableIdentifierProperties(new TableIdentifier("blah")));
TableIdentifier ordersTable = new TableIdentifier(null,null, "ORDERS");
-
-
assertEquals("customOrderId", repository.tableToIdentifierPropertyName(ordersTable));
assertEquals(null, repository.tableToIdentifierPropertyName(new TableIdentifier("blah")));
@@ -219,7 +217,6 @@
assertNotNull(sv.getIdentifierGeneratorProperties());
assertEquals("seq_table", sv.getIdentifierGeneratorProperties().getProperty("table"));
-
}
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/foreignkeytest.reveng.xml
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/foreignkeytest.reveng.xml 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/foreignkeytest.reveng.xml 2006-08-04 08:41:47 UTC (rev 10211)
@@ -16,5 +16,6 @@
<set property="managedProjects"/>
</foreign-key>
</table>
-
+
+
</hibernate-reverse-engineering>
\ No newline at end of file
Modified: trunk/HibernateExt/tools/src/testsupport/NoopReverseEngineeringStrategy.java
===================================================================
--- trunk/HibernateExt/tools/src/testsupport/NoopReverseEngineeringStrategy.java 2006-08-03 20:42:49 UTC (rev 10210)
+++ trunk/HibernateExt/tools/src/testsupport/NoopReverseEngineeringStrategy.java 2006-08-04 08:41:47 UTC (rev 10211)
@@ -6,6 +6,8 @@
import org.hibernate.cfg.reveng.TableIdentifier;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.Table;
/**
* noop naming strategy for testing validation of parameters in ant test.
@@ -140,4 +142,14 @@
// TODO Auto-generated method stub
}
+
+ public boolean isManyToManyTable(Table table) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public String foreignKeyToManyToManyName(ForeignKey fromKey, TableIdentifier middleTable, ForeignKey toKey, boolean uniqueReference) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
|