You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(22) |
Nov
(308) |
Dec
(131) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(369) |
Feb
(171) |
Mar
(236) |
Apr
(187) |
May
(218) |
Jun
(217) |
Jul
(127) |
Aug
(448) |
Sep
(270) |
Oct
(231) |
Nov
(422) |
Dec
(255) |
2004 |
Jan
(111) |
Feb
(73) |
Mar
(338) |
Apr
(351) |
May
(349) |
Jun
(495) |
Jul
(394) |
Aug
(1048) |
Sep
(499) |
Oct
(142) |
Nov
(269) |
Dec
(638) |
2005 |
Jan
(825) |
Feb
(1272) |
Mar
(593) |
Apr
(690) |
May
(950) |
Jun
(958) |
Jul
(767) |
Aug
(839) |
Sep
(525) |
Oct
(449) |
Nov
(585) |
Dec
(455) |
2006 |
Jan
(603) |
Feb
(656) |
Mar
(195) |
Apr
(114) |
May
(136) |
Jun
(100) |
Jul
(128) |
Aug
(68) |
Sep
(7) |
Oct
(1) |
Nov
(1) |
Dec
(8) |
2007 |
Jan
(4) |
Feb
(3) |
Mar
(8) |
Apr
(16) |
May
(5) |
Jun
(4) |
Jul
(6) |
Aug
(23) |
Sep
(15) |
Oct
(5) |
Nov
(7) |
Dec
(5) |
2008 |
Jan
(5) |
Feb
(1) |
Mar
(1) |
Apr
(5) |
May
(1) |
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2012 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
(1) |
Jul
(1) |
Aug
(1) |
Sep
|
Oct
(2) |
Nov
(3) |
Dec
(2) |
2013 |
Jan
(1) |
Feb
|
Mar
(2) |
Apr
(1) |
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(2) |
Jun
(1) |
Jul
|
Aug
(1) |
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
2016 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2017 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <hib...@li...> - 2006-08-04 13:00:53
|
Author: ste...@jb... Date: 2006-08-04 09:00:30 -0400 (Fri, 04 Aug 2006) New Revision: 10212 Modified: trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java Log: cleanup Modified: trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java 2006-08-04 08:41:47 UTC (rev 10211) +++ trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java 2006-08-04 13:00:30 UTC (rev 10212) @@ -14,10 +14,8 @@ */ public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends AbstractClassLoaderIsolatedTestCase { - private BytecodeProvider provider; - protected ClassLoader buildIsolatedClassLoader(ClassLoader parent) { - provider = buildBytecodeProvider(); + BytecodeProvider provider = buildBytecodeProvider(); return new InstrumentedClassLoader( parent, provider.getTransformer( @@ -36,7 +34,6 @@ } protected void releaseIsolatedClassLoader(ClassLoader isolatedLoader) { - provider = null; } protected abstract BytecodeProvider buildBytecodeProvider(); |
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; + } } |
From: <hib...@li...> - 2006-08-03 20:43:22
|
Author: ste...@jb... Date: 2006-08-03 16:42:49 -0400 (Thu, 03 Aug 2006) New Revision: 10210 Removed: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java Log: ported fix forHHH-1968 to 3.2 branch Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java =================================================================== --- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java 2006-08-03 20:35:26 UTC (rev 10209) +++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java 2006-08-03 20:42:49 UTC (rev 10210) @@ -4,6 +4,9 @@ import org.hibernate.HibernateException; import org.hibernate.bytecode.BytecodeProvider; +import org.hibernate.bytecode.InstrumentedClassLoader; +import org.hibernate.bytecode.util.BasicClassFilter; +import org.hibernate.bytecode.util.FieldFilter; import org.hibernate.test.AbstractClassLoaderIsolatedTestCase; /** @@ -11,25 +14,26 @@ */ public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends AbstractClassLoaderIsolatedTestCase { - private BytecodeProvider provider; - protected ClassLoader buildIsolatedClassLoader(ClassLoader parent) { -// String myFileName = AbstractTransformingClassLoaderInstrumentTestCase.class.getName().replace( '.', '/' ) + ".class"; -// URL fileURL = this.getClass().getClassLoader().getResource( myFileName ); -// String filePath = fileURL.getPath(); -// String classPath = filePath.substring( 0, filePath.length() - myFileName.length() ); - provider = buildBytecodeProvider(); + BytecodeProvider provider = buildBytecodeProvider(); return new InstrumentedClassLoader( parent, - provider.getEntityClassTransformer( - new String[] { "org.hibernate.test.instrument" }, - null) ); + provider.getTransformer( + new BasicClassFilter( new String[] { "org.hibernate.test.instrument" }, null ), + new FieldFilter() { + public boolean shouldInstrumentField(String className, String fieldName) { + return true; + } + public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName) { + return true; + } + } + ) + ); } protected void releaseIsolatedClassLoader(ClassLoader isolatedLoader) { - provider.releaseDynamicFieldInterceptionClassLoader( isolatedLoader ); - provider = null; } protected abstract BytecodeProvider buildBytecodeProvider(); Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java =================================================================== --- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java 2006-08-03 20:35:26 UTC (rev 10209) +++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java 2006-08-03 20:42:49 UTC (rev 10210) @@ -1,80 +0,0 @@ -//$Id: $ -package org.hibernate.test.instrument.runtime; - -import java.io.IOException; -import java.io.InputStream; - -import org.hibernate.HibernateException; -import org.hibernate.bytecode.ClassTransformer; - -/** - * @author Emmanuel Bernard - */ -public class InstrumentedClassLoader extends ClassLoader { - - private ClassTransformer classTransformer; - - public InstrumentedClassLoader(ClassLoader parent, ClassTransformer classTransformer) { - super( parent ); - this.classTransformer = classTransformer; - } - - public Class loadClass(String name) throws ClassNotFoundException { - if ( name.startsWith( "java" ) ) return getParent().loadClass( name ); - Class c = findLoadedClass( name ); - if ( c != null ) return c; - InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" ); - if ( is == null ) throw new ClassNotFoundException( name ); - byte[] buffer = new byte[409600]; - byte[] originalClass = new byte[0]; - int r = 0; - try { - r = is.read( buffer ); - } - catch (IOException e) { - throw new ClassNotFoundException( name + " not found", e ); - } - while ( r >= buffer.length ) { - byte[] temp = new byte[ originalClass.length + buffer.length ]; - System.arraycopy( originalClass, 0, temp, 0, originalClass.length ); - System.arraycopy( buffer, 0, temp, originalClass.length, buffer.length ); - originalClass = temp; - } - if ( r != -1 ) { - byte[] temp = new byte[ originalClass.length + r ]; - System.arraycopy( originalClass, 0, temp, 0, originalClass.length ); - System.arraycopy( buffer, 0, temp, originalClass.length, r ); - originalClass = temp; - } - try { - is.close(); - } - catch (IOException e) { - throw new ClassNotFoundException( name + " not found", e ); - } - if (classTransformer != null) { - byte[] transformed = new byte[0]; - try { - transformed = classTransformer.transform( - getParent(), - name, - null, - null, - originalClass - ); - if ( originalClass == transformed) { - return getParent().loadClass(name); - } - else { - return defineClass( name, transformed, 0, transformed.length ); - } - } - catch (HibernateException e) { - throw new ClassNotFoundException( name + " not found", e ); - } - } - else { - return getParent().loadClass(name); - } - } -} |
Author: ste...@jb... Date: 2006-08-03 16:35:26 -0400 (Thu, 03 Aug 2006) New Revision: 10209 Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java Removed: branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldFilter.java branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandled.java branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandler.java branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldTransformer.java Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/InstrumentTask.java Log: ported fix forHHH-1968 to 3.2 branch Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -1,30 +1,23 @@ //$Id: $ package org.hibernate.bytecode; +import org.hibernate.bytecode.util.ClassFilter; +import org.hibernate.bytecode.util.FieldFilter; + import java.security.ProtectionDomain; -import java.util.HashSet; -import java.util.Set; /** * @author Emmanuel Bernard + * @author Steve Ebersole */ public abstract class AbstractClassTransformerImpl implements ClassTransformer { - final private Set entities; - final private String[] packages; + protected final ClassFilter classFilter; + protected final FieldFilter fieldFilter; - - public AbstractClassTransformerImpl(String[] packages, String[] classes) { - this.packages = packages; - if (classes == null) { - this.entities = null; - } - else { - this.entities = new HashSet(); - for ( int i = 0; i < classes.length; i++ ) { - entities.add( classes[i] ); - } - } + protected AbstractClassTransformerImpl(ClassFilter classFilter, FieldFilter fieldFilter) { + this.classFilter = classFilter; + this.fieldFilter = fieldFilter; } public byte[] transform( @@ -33,25 +26,14 @@ Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { - boolean enhance = false; - String safeClassName = className.replace( '/', '.' ); - if ( entities == null && packages == null ) { - enhance = true; + // to be safe... + className = className.replace( '/', '.' ); + if ( classFilter.shouldInstrumentClass( className ) ) { + return doTransform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer ); } - if ( ! enhance && entities != null && entities.contains( safeClassName ) ) { - enhance = true; + else { + return classfileBuffer; } - if ( ! enhance && packages != null ) { - for ( int i = 0; i < packages.length; i++ ) { - if ( safeClassName.startsWith( packages[i] ) ) { - enhance = true; - break; - } - } - } - if ( ! enhance ) return classfileBuffer; - - return doTransform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer ); } protected abstract byte[] doTransform( Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -1,15 +1,16 @@ package org.hibernate.bytecode; +import org.hibernate.bytecode.util.ClassFilter; +import org.hibernate.bytecode.util.FieldFilter; + /** * Contract for providers of bytecode services to Hibernate. * <p/> - * Bytecode requirements break down into basically 4 areas<ol> + * Bytecode requirements break down into basically 3 areas<ol> * <li>proxy generation (both for runtime-lazy-loading and basic proxy generation) * {@link #getProxyFactoryFactory()} * <li>bean relection optimization {@link #getReflectionOptimizer} - * <li>build-time instumentation (not covered by this contract) - * <li>class-load intrumentation {@link #generateDynamicFieldInterceptionClassLoader}; - * (currently only used in the test suite). + * <li>field-access instumentation {@link #getTransformer} * </ol> * * @author Steve Ebersole @@ -36,41 +37,13 @@ public ReflectionOptimizer getReflectionOptimizer(Class clazz, String[] getterNames, String[] setterNames, Class[] types); /** - * Generate a ClassLoader capable of performing dynamic bytecode manipulation - * on classes as they are loaded for the purpose of field-level interception. - * The returned ClassLoader is used for run-time bytecode manipulation as - * opposed to the more common build-time manipulation, since here we get - * into SecurityManager issues and such. - * <p/> - * Currently used only from the Hibernate test suite, although conceivably - * (SecurityManager concerns aside) could be used somehow in running systems. + * Generate a ClassTransformer capable of performing bytecode manipulation. * - * @param parent The parent classloader - * @param classpath The classpath to be searched - * @param packages can be null; use to limit the packages to be loaded - * via this classloader (and transformed). - * @return The appropriate ClassLoader. - */ - public ClassLoader generateDynamicFieldInterceptionClassLoader(ClassLoader parent, String[] classpath, String[] packages); - - /** - * Generate a ClassTransformer capable of performing dynamic bytecode manipulation - * on classes as they are loaded for the purpose of field-level interception. - * The returned ClassTransformer can be combined to an appropriate ClassLoader - * is used for run-time bytecode manipulation as - * opposed to the more common build-time manipulation, since here we get - * into SecurityManager issues and such. - * <p/> - * - * @param packages can be null; use to limit the packages to be transformed - * via this classtransformer. - * @param classes can be null; use to limit the classes to be transformed - * via this class transformer. + * @param classFilter filter used to limit which classes are to be instrumented + * via this ClassTransformer. + * @param fieldFilter filter used to limit which fields are to be instrumented + * via this ClassTransformer. * @return The appropriate ClassTransformer. */ - public ClassTransformer getEntityClassTransformer( - String[] packages, String[] classes - ); - - public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader); + public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter); } Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,54 @@ +package org.hibernate.bytecode; + +import org.hibernate.bytecode.util.ByteCodeHelper; + +import java.io.InputStream; + +/** + * A specialized classloader which performs bytecode enhancement on class + * definitions as they are loaded into the classloader scope. + * + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public class InstrumentedClassLoader extends ClassLoader { + + private ClassTransformer classTransformer; + + public InstrumentedClassLoader(ClassLoader parent, ClassTransformer classTransformer) { + super( parent ); + this.classTransformer = classTransformer; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if ( name.startsWith( "java." ) || classTransformer == null ) { + return getParent().loadClass( name ); + } + + Class c = findLoadedClass( name ); + if ( c != null ) { + return c; + } + + InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" ); + if ( is == null ) { + throw new ClassNotFoundException( name + " not found" ); + } + + try { + byte[] originalBytecode = ByteCodeHelper.readByteCode( is ); + byte[] transformedBytecode = classTransformer.transform( getParent(), name, null, null, originalBytecode ); + if ( originalBytecode == transformedBytecode ) { + // no transformations took place, so handle it as we would a + // non-instrumented class + return getParent().loadClass( name ); + } + else { + return defineClass( name, transformedBytecode, 0, transformedBytecode.length ); + } + } + catch( Throwable t ) { + throw new ClassNotFoundException( name + " not found", t ); + } + } +} Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -16,6 +16,7 @@ import org.hibernate.bytecode.BytecodeProvider; import org.hibernate.bytecode.ProxyFactoryFactory; import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.bytecode.util.FieldFilter; import org.hibernate.util.StringHelper; import org.objectweb.asm.Type; @@ -84,58 +85,8 @@ } } - public ClassLoader generateDynamicFieldInterceptionClassLoader( - ClassLoader parent, - String[] classpath, - String[] packages) { - return new TransformingClassLoader( - parent, - new ClassLoaderClassFilter( packages ), - new ClassTransformerFactory() { - public ClassTransformer newInstance() { - return new InterceptFieldTransformer( - new InterceptFieldFilter() { - public boolean acceptRead(Type owner, String name) { - return true; - } - public boolean acceptWrite(Type owner, String name) { - return true; - } - } - ); - } - } - ); + public org.hibernate.bytecode.ClassTransformer getTransformer(org.hibernate.bytecode.util.ClassFilter classFilter, FieldFilter fieldFilter) { + return new CglibClassTransformer( classFilter, fieldFilter ); } - public org.hibernate.bytecode.ClassTransformer getEntityClassTransformer( - String[] packages, String[] classes - ) { - return new CglibClassTransformer( packages, classes ); - } - - public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader) { - } - - private static class ClassLoaderClassFilter implements ClassFilter { - private final String[] packages; - - public ClassLoaderClassFilter(String[] packages) { - this.packages = packages; - } - - public boolean accept(String className) { - if ( packages == null ) { - return true; - } - else { - for ( int i = 0; i < packages.length; i++ ) { - if ( className.startsWith( packages[i] ) ) { - return true; - } - } - return false; - } - } - } } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -2,7 +2,6 @@ package org.hibernate.bytecode.cglib; import java.security.ProtectionDomain; -import java.util.Arrays; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ByteArrayOutputStream; @@ -18,6 +17,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.bytecode.AbstractClassTransformerImpl; +import org.hibernate.bytecode.util.FieldFilter; +import org.hibernate.bytecode.util.ClassFilter; import org.hibernate.HibernateException; import org.objectweb.asm.Attribute; import org.objectweb.asm.Type; @@ -30,13 +31,14 @@ * This interface is then used by Hibernate for some optimizations. * * @author Emmanuel Bernard + * @author Steve Ebersole */ public class CglibClassTransformer extends AbstractClassTransformerImpl { private static Log log = LogFactory.getLog( CglibClassTransformer.class.getName() ); - public CglibClassTransformer(String[] packages, String[] classes) { - super(packages, classes); + public CglibClassTransformer(ClassFilter classFilter, FieldFilter fieldFilter) { + super( classFilter, fieldFilter ); } protected byte[] doTransform( @@ -91,22 +93,29 @@ return false; } - private ClassTransformer getClassTransformer(String[] classInfo) { - if ( Arrays.asList( classInfo ).contains( InterceptFieldEnabled.class.getName() ) ) { + private ClassTransformer getClassTransformer(final String[] classInfo) { + if ( isAlreadyInstrumented( classInfo ) ) { return null; } - else { - return new InterceptFieldTransformer( - new InterceptFieldFilter() { - public boolean acceptRead(Type owner, String name) { - return true; - } + return new InterceptFieldTransformer( + new InterceptFieldFilter() { + public boolean acceptRead(Type owner, String name) { + return fieldFilter.shouldTransformFieldAccess( classInfo[0], owner.getClassName(), name ); + } - public boolean acceptWrite(Type owner, String name) { - return true; - } + public boolean acceptWrite(Type owner, String name) { + return fieldFilter.shouldTransformFieldAccess( classInfo[0], owner.getClassName(), name ); } - ); + } + ); + } + + private boolean isAlreadyInstrumented(String[] classInfo) { + for ( int i = 1; i < classInfo.length; i++ ) { + if ( InterceptFieldEnabled.class.getName().equals( classInfo[i] ) ) { + return true; + } } + return false; } } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -8,6 +8,8 @@ import org.hibernate.bytecode.ClassTransformer; import org.hibernate.bytecode.ProxyFactoryFactory; import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.bytecode.util.ClassFilter; +import org.hibernate.bytecode.util.FieldFilter; import org.hibernate.util.StringHelper; /** @@ -75,20 +77,8 @@ } } - public ClassLoader generateDynamicFieldInterceptionClassLoader(ClassLoader parent, String[] classpath, String[] packages) { - return new TransformingClassLoader( parent, classpath ); + public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter) { + return new JavassistClassTransformer( classFilter, fieldFilter ); } - public ClassTransformer getEntityClassTransformer( - String[] packages, String[] classes - ) { - return new JavassistClassTransformer( packages, classes ); - } - - public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader) { - if ( ! TransformingClassLoader.class.isAssignableFrom( classLoader.getClass() ) ) { - return; - } - ( ( TransformingClassLoader ) classLoader ).release(); - } } Copied: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java (from rev 10206, branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldFilter.java) =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldFilter.java 2006-08-03 19:59:42 UTC (rev 10206) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,28 @@ +package org.hibernate.bytecode.javassist; + +/** + * Contract for deciding whether fields should be read and/or write intercepted. + * + * @author Muga Nishizawa + */ +public interface FieldFilter { + /** + * Should the given field be read intercepted? + * + * @param desc + * @param name + * @return true if the given field should be read intercepted; otherwise + * false. + */ + boolean handleRead(String desc, String name); + + /** + * Should the given field be write intercepted? + * + * @param desc + * @param name + * @return true if the given field should be write intercepted; otherwise + * false. + */ + boolean handleWrite(String desc, String name); +} Property changes on: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Copied: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java (from rev 10206, branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandled.java) =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandled.java 2006-08-03 19:59:42 UTC (rev 10206) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,23 @@ +package org.hibernate.bytecode.javassist; + +/** + * Interface introduced to the enhanced class in order to be able to + * inject a {@link FieldHandler} to define the interception behavior. + * + * @author Muga Nishizawa + */ +public interface FieldHandled { + /** + * Inject the field interception handler to be used. + * + * @param handler The field interception handler. + */ + public void setFieldHandler(FieldHandler handler); + + /** + * Access to the current field interception handler. + * + * @return The current field interception handler. + */ + public FieldHandler getFieldHandler(); +} Property changes on: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Copied: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java (from rev 10206, branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandler.java) =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandler.java 2006-08-03 19:59:42 UTC (rev 10206) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,56 @@ +package org.hibernate.bytecode.javassist; + +/** + * The interface defining how interception of a field should be handled. + * + * @author Muga Nishizawa + */ +public interface FieldHandler { + + /** + * Called to handle writing an int value to a given field. + * + * @param obj ? + * @param name The name of the field being written + * @param oldValue The old field value + * @param newValue The new field value. + * @return ? + */ + int writeInt(Object obj, String name, int oldValue, int newValue); + + char writeChar(Object obj, String name, char oldValue, char newValue); + + byte writeByte(Object obj, String name, byte oldValue, byte newValue); + + boolean writeBoolean(Object obj, String name, boolean oldValue, + boolean newValue); + + short writeShort(Object obj, String name, short oldValue, short newValue); + + float writeFloat(Object obj, String name, float oldValue, float newValue); + + double writeDouble(Object obj, String name, double oldValue, double newValue); + + long writeLong(Object obj, String name, long oldValue, long newValue); + + Object writeObject(Object obj, String name, Object oldValue, Object newValue); + + int readInt(Object obj, String name, int oldValue); + + char readChar(Object obj, String name, char oldValue); + + byte readByte(Object obj, String name, byte oldValue); + + boolean readBoolean(Object obj, String name, boolean oldValue); + + short readShort(Object obj, String name, short oldValue); + + float readFloat(Object obj, String name, float oldValue); + + double readDouble(Object obj, String name, double oldValue); + + long readLong(Object obj, String name, long oldValue); + + Object readObject(Object obj, String name, Object oldValue); + +} Property changes on: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Copied: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java (from rev 10206, branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldTransformer.java) =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldTransformer.java 2006-08-03 19:59:42 UTC (rev 10206) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,592 @@ +package org.hibernate.bytecode.javassist; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import javassist.CannotCompileException; +import javassist.bytecode.AccessFlag; +import javassist.bytecode.BadBytecode; +import javassist.bytecode.Bytecode; +import javassist.bytecode.ClassFile; +import javassist.bytecode.CodeAttribute; +import javassist.bytecode.CodeIterator; +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import javassist.bytecode.FieldInfo; +import javassist.bytecode.MethodInfo; +import javassist.bytecode.Opcode; +import org.hibernate.bytecode.javassist.FieldFilter; +import org.hibernate.bytecode.javassist.FieldHandled; +import org.hibernate.bytecode.javassist.FieldHandler; + +/** + * The thing that handles actual class enhancement in regards to + * intercepting field accesses. + * + * @author Muga Nishizawa + */ +public class FieldTransformer { + + private static final String EACH_READ_METHOD_PREFIX = "$javassist_read_"; + + private static final String EACH_WRITE_METHOD_PREFIX = "$javassist_write_"; + + private static final String FIELD_HANDLED_TYPE_NAME = FieldHandled.class + .getName(); + + private static final String HANDLER_FIELD_NAME = "$JAVASSIST_READ_WRITE_HANDLER"; + + private static final String FIELD_HANDLER_TYPE_NAME = FieldHandler.class + .getName(); + + private static final String HANDLER_FIELD_DESCRIPTOR = 'L' + FIELD_HANDLER_TYPE_NAME + .replace('.', '/') + ';'; + + private static final String GETFIELDHANDLER_METHOD_NAME = "getFieldHandler"; + + private static final String SETFIELDHANDLER_METHOD_NAME = "setFieldHandler"; + + private static final String GETFIELDHANDLER_METHOD_DESCRIPTOR = "()" + + HANDLER_FIELD_DESCRIPTOR; + + private static final String SETFIELDHANDLER_METHOD_DESCRIPTOR = "(" + + HANDLER_FIELD_DESCRIPTOR + ")V"; + + private FieldFilter filter; + + private HashMap readableFields; + + private HashMap writableFields; + + public FieldTransformer() { + this(null); + } + + public FieldTransformer(FieldFilter f) { + filter = f; + readableFields = new HashMap(); + writableFields = new HashMap(); + } + + public void setFieldFilter(FieldFilter f) { + filter = f; + } + + public void transform(File file) throws Exception { + DataInputStream in = new DataInputStream(new FileInputStream(file)); + ClassFile classfile = new ClassFile(in); + transform(classfile); + DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); + try { + classfile.write(out); + } finally { + out.close(); + } + } + + public void transform(ClassFile classfile) throws Exception { + if (classfile.isInterface()) { + return; + } + try { + addFieldHandlerField(classfile); + addGetFieldHandlerMethod(classfile); + addSetFieldHandlerMethod(classfile); + addFieldHandledInterface(classfile); + addReadWriteMethods(classfile); + transformInvokevirtualsIntoPutAndGetfields(classfile); + } catch (CannotCompileException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + private void addFieldHandlerField(ClassFile classfile) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + FieldInfo finfo = new FieldInfo(cp, HANDLER_FIELD_NAME, + HANDLER_FIELD_DESCRIPTOR); + finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.TRANSIENT); + classfile.addField(finfo); + } + + private void addGetFieldHandlerMethod(ClassFile classfile) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + MethodInfo minfo = new MethodInfo(cp, GETFIELDHANDLER_METHOD_NAME, + GETFIELDHANDLER_METHOD_DESCRIPTOR); + /* local variable | this | */ + Bytecode code = new Bytecode(cp, 2, 1); + // aload_0 // load this + code.addAload(0); + // getfield // get field "$JAVASSIST_CALLBACK" defined already + code.addOpcode(Opcode.GETFIELD); + int field_index = cp.addFieldrefInfo(this_class_index, + HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); + code.addIndex(field_index); + // areturn // return the value of the field + code.addOpcode(Opcode.ARETURN); + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void addSetFieldHandlerMethod(ClassFile classfile) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + MethodInfo minfo = new MethodInfo(cp, SETFIELDHANDLER_METHOD_NAME, + SETFIELDHANDLER_METHOD_DESCRIPTOR); + /* local variables | this | callback | */ + Bytecode code = new Bytecode(cp, 3, 3); + // aload_0 // load this + code.addAload(0); + // aload_1 // load callback + code.addAload(1); + // putfield // put field "$JAVASSIST_CALLBACK" defined already + code.addOpcode(Opcode.PUTFIELD); + int field_index = cp.addFieldrefInfo(this_class_index, + HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); + code.addIndex(field_index); + // return + code.addOpcode(Opcode.RETURN); + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void addFieldHandledInterface(ClassFile classfile) { + String[] interfaceNames = classfile.getInterfaces(); + String[] newInterfaceNames = new String[interfaceNames.length + 1]; + System.arraycopy(interfaceNames, 0, newInterfaceNames, 0, + interfaceNames.length); + newInterfaceNames[newInterfaceNames.length - 1] = FIELD_HANDLED_TYPE_NAME; + classfile.setInterfaces(newInterfaceNames); + } + + private void addReadWriteMethods(ClassFile classfile) + throws CannotCompileException { + List fields = classfile.getFields(); + for (Iterator field_iter = fields.iterator(); field_iter.hasNext();) { + FieldInfo finfo = (FieldInfo) field_iter.next(); + if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0 + && (!finfo.getName().equals(HANDLER_FIELD_NAME))) { + // case of non-static field + if (filter.handleRead(finfo.getDescriptor(), finfo + .getName())) { + addReadMethod(classfile, finfo); + readableFields.put(finfo.getName(), finfo + .getDescriptor()); + } + if (filter.handleWrite(finfo.getDescriptor(), finfo + .getName())) { + addWriteMethod(classfile, finfo); + writableFields.put(finfo.getName(), finfo + .getDescriptor()); + } + } + } + } + + private void addReadMethod(ClassFile classfile, FieldInfo finfo) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + String desc = "()" + finfo.getDescriptor(); + MethodInfo minfo = new MethodInfo(cp, EACH_READ_METHOD_PREFIX + + finfo.getName(), desc); + /* local variables | target obj | each oldvalue | */ + Bytecode code = new Bytecode(cp, 5, 3); + // aload_0 + code.addAload(0); + // getfield // get each field + code.addOpcode(Opcode.GETFIELD); + int base_field_index = cp.addFieldrefInfo(this_class_index, finfo + .getName(), finfo.getDescriptor()); + code.addIndex(base_field_index); + // aload_0 + code.addAload(0); + // invokeinterface // invoke Enabled.getInterceptFieldCallback() + int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME); + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // ifnonnull + code.addOpcode(Opcode.IFNONNULL); + code.addIndex(4); + // *return // each type + addTypeDependDataReturn(code, finfo.getDescriptor()); + // *store_1 // each type + addTypeDependDataStore(code, finfo.getDescriptor(), 1); + // aload_0 + code.addAload(0); + // invokeinterface // invoke Enabled.getInterceptFieldCallback() + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // aload_0 + code.addAload(0); + // ldc // name of the field + code.addLdc(finfo.getName()); + // *load_1 // each type + addTypeDependDataLoad(code, finfo.getDescriptor(), 1); + // invokeinterface // invoke Callback.read*() // each type + addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(), + true); + // *return // each type + addTypeDependDataReturn(code, finfo.getDescriptor()); + + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void addWriteMethod(ClassFile classfile, FieldInfo finfo) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + String desc = "(" + finfo.getDescriptor() + ")V"; + MethodInfo minfo = new MethodInfo(cp, EACH_WRITE_METHOD_PREFIX + + finfo.getName(), desc); + /* local variables | target obj | each oldvalue | */ + Bytecode code = new Bytecode(cp, 6, 3); + // aload_0 + code.addAload(0); + // invokeinterface // enabled.getInterceptFieldCallback() + int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME); + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // ifnonnull (label1) + code.addOpcode(Opcode.IFNONNULL); + code.addIndex(9); + // aload_0 + code.addAload(0); + // *load_1 + addTypeDependDataLoad(code, finfo.getDescriptor(), 1); + // putfield + code.addOpcode(Opcode.PUTFIELD); + int base_field_index = cp.addFieldrefInfo(this_class_index, finfo + .getName(), finfo.getDescriptor()); + code.addIndex(base_field_index); + code.growStack(-Descriptor.dataSize(finfo.getDescriptor())); + // return ; + code.addOpcode(Opcode.RETURN); + // aload_0 + code.addAload(0); + // dup + code.addOpcode(Opcode.DUP); + // invokeinterface // enabled.getInterceptFieldCallback() + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // aload_0 + code.addAload(0); + // ldc // field name + code.addLdc(finfo.getName()); + // aload_0 + code.addAload(0); + // getfield // old value of the field + code.addOpcode(Opcode.GETFIELD); + code.addIndex(base_field_index); + code.growStack(Descriptor.dataSize(finfo.getDescriptor()) - 1); + // *load_1 + addTypeDependDataLoad(code, finfo.getDescriptor(), 1); + // invokeinterface // callback.write*(..) + addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(), + false); + // putfield // new value of the field + code.addOpcode(Opcode.PUTFIELD); + code.addIndex(base_field_index); + code.growStack(-Descriptor.dataSize(finfo.getDescriptor())); + // return + code.addOpcode(Opcode.RETURN); + + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void transformInvokevirtualsIntoPutAndGetfields(ClassFile classfile) + throws CannotCompileException { + List methods = classfile.getMethods(); + for (Iterator method_iter = methods.iterator(); method_iter.hasNext();) { + MethodInfo minfo = (MethodInfo) method_iter.next(); + String methodName = minfo.getName(); + if (methodName.startsWith(EACH_READ_METHOD_PREFIX) + || methodName.startsWith(EACH_WRITE_METHOD_PREFIX) + || methodName.equals(GETFIELDHANDLER_METHOD_NAME) + || methodName.equals(SETFIELDHANDLER_METHOD_NAME)) { + continue; + } + CodeAttribute codeAttr = minfo.getCodeAttribute(); + if (codeAttr == null) { + return; + } + CodeIterator iter = codeAttr.iterator(); + while (iter.hasNext()) { + try { + int pos = iter.next(); + pos = transformInvokevirtualsIntoGetfields(classfile, iter, + pos); + pos = transformInvokevirtualsIntoPutfields(classfile, iter, + pos); + + } catch (BadBytecode e) { + throw new CannotCompileException(e); + } + } + } + } + + private int transformInvokevirtualsIntoGetfields(ClassFile classfile, + CodeIterator iter, int pos) { + ConstPool cp = classfile.getConstPool(); + int c = iter.byteAt(pos); + if (c != Opcode.GETFIELD) { + return pos; + } + int index = iter.u16bitAt(pos + 1); + String fieldName = cp.getFieldrefName(index); + String className = cp.getFieldrefClassName(index); + if ((!classfile.getName().equals(className)) + || (!readableFields.containsKey(fieldName))) { + return pos; + } + String desc = "()" + (String) readableFields.get(fieldName); + int read_method_index = cp.addMethodrefInfo(cp.getThisClassInfo(), + EACH_READ_METHOD_PREFIX + fieldName, desc); + iter.writeByte(Opcode.INVOKEVIRTUAL, pos); + iter.write16bit(read_method_index, pos + 1); + return pos; + } + + private int transformInvokevirtualsIntoPutfields(ClassFile classfile, + CodeIterator iter, int pos) { + ConstPool cp = classfile.getConstPool(); + int c = iter.byteAt(pos); + if (c != Opcode.PUTFIELD) { + return pos; + } + int index = iter.u16bitAt(pos + 1); + String fieldName = cp.getFieldrefName(index); + String className = cp.getFieldrefClassName(index); + if ((!classfile.getName().equals(className)) + || (!writableFields.containsKey(fieldName))) { + return pos; + } + String desc = "(" + (String) writableFields.get(fieldName) + ")V"; + int write_method_index = cp.addMethodrefInfo(cp.getThisClassInfo(), + EACH_WRITE_METHOD_PREFIX + fieldName, desc); + iter.writeByte(Opcode.INVOKEVIRTUAL, pos); + iter.write16bit(write_method_index, pos + 1); + return pos; + } + + private static void addInvokeFieldHandlerMethod(ClassFile classfile, + Bytecode code, String typeName, boolean isReadMethod) { + ConstPool cp = classfile.getConstPool(); + // invokeinterface + int callback_type_index = cp.addClassInfo(FIELD_HANDLER_TYPE_NAME); + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + int indexOfL = typeName.indexOf('L'); + String type; + if (indexOfL == 0) { + // not array + type = typeName.substring(1, typeName.length() - 1); + type = type.replace('/', '.'); + } else if (indexOfL == -1) { + // array of primitive type + // do nothing + type = typeName; + } else { + // array of reference type + type = typeName.replace('/', '.'); + } + if (isReadMethod) { + code + .addInvokeinterface( + callback_type_index, + "readObject", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", + 4); + // checkcast + code.addCheckcast(type); + } else { + code + .addInvokeinterface( + callback_type_index, + "writeObject", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + 5); + // checkcast + code.addCheckcast(type); + } + } else if (typeName.equals("Z")) { + // boolean + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readBoolean", + "(Ljava/lang/Object;Ljava/lang/String;Z)Z", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeBoolean", + "(Ljava/lang/Object;Ljava/lang/String;ZZ)Z", 5); + } + } else if (typeName.equals("B")) { + // byte + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readByte", + "(Ljava/lang/Object;Ljava/lang/String;B)B", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeByte", + "(Ljava/lang/Object;Ljava/lang/String;BB)B", 5); + } + } else if (typeName.equals("C")) { + // char + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readChar", + "(Ljava/lang/Object;Ljava/lang/String;C)C", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeChar", + "(Ljava/lang/Object;Ljava/lang/String;CC)C", 5); + } + } else if (typeName.equals("I")) { + // int + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readInt", + "(Ljava/lang/Object;Ljava/lang/String;I)I", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeInt", + "(Ljava/lang/Object;Ljava/lang/String;II)I", 5); + } + } else if (typeName.equals("S")) { + // short + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readShort", + "(Ljava/lang/Object;Ljava/lang/String;S)S", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeShort", + "(Ljava/lang/Object;Ljava/lang/String;SS)S", 5); + } + } else if (typeName.equals("D")) { + // double + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readDouble", + "(Ljava/lang/Object;Ljava/lang/String;D)D", 5); + } else { + code.addInvokeinterface(callback_type_index, "writeDouble", + "(Ljava/lang/Object;Ljava/lang/String;DD)D", 7); + } + } else if (typeName.equals("F")) { + // float + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readFloat", + "(Ljava/lang/Object;Ljava/lang/String;F)F", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeFloat", + "(Ljava/lang/Object;Ljava/lang/String;FF)F", 5); + } + } else if (typeName.equals("J")) { + // long + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readLong", + "(Ljava/lang/Object;Ljava/lang/String;J)J", 5); + } else { + code.addInvokeinterface(callback_type_index, "writeLong", + "(Ljava/lang/Object;Ljava/lang/String;JJ)J", 7); + } + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + + private static void addTypeDependDataLoad(Bytecode code, String typeName, + int i) { + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + code.addAload(i); + } else if (typeName.equals("Z") || typeName.equals("B") + || typeName.equals("C") || typeName.equals("I") + || typeName.equals("S")) { + // boolean, byte, char, int, short + code.addIload(i); + } else if (typeName.equals("D")) { + // double + code.addDload(i); + } else if (typeName.equals("F")) { + // float + code.addFload(i); + } else if (typeName.equals("J")) { + // long + code.addLload(i); + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + + private static void addTypeDependDataStore(Bytecode code, String typeName, + int i) { + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + code.addAstore(i); + } else if (typeName.equals("Z") || typeName.equals("B") + || typeName.equals("C") || typeName.equals("I") + || typeName.equals("S")) { + // boolean, byte, char, int, short + code.addIstore(i); + } else if (typeName.equals("D")) { + // double + code.addDstore(i); + } else if (typeName.equals("F")) { + // float + code.addFstore(i); + } else if (typeName.equals("J")) { + // long + code.addLstore(i); + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + + private static void addTypeDependDataReturn(Bytecode code, String typeName) { + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + code.addOpcode(Opcode.ARETURN); + } else if (typeName.equals("Z") || typeName.equals("B") + || typeName.equals("C") || typeName.equals("I") + || typeName.equals("S")) { + // boolean, byte, char, int, short + code.addOpcode(Opcode.IRETURN); + } else if (typeName.equals("D")) { + // double + code.addOpcode(Opcode.DRETURN); + } else if (typeName.equals("F")) { + // float + code.addOpcode(Opcode.FRETURN); + } else if (typeName.equals("J")) { + // long + code.addOpcode(Opcode.LRETURN); + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + +} Property changes on: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -13,22 +13,21 @@ import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.bytecode.AbstractClassTransformerImpl; -import org.hibernate.tool.instrument.javassist.FieldFilter; -import org.hibernate.tool.instrument.javassist.FieldHandled; -import org.hibernate.tool.instrument.javassist.FieldTransformer; +import org.hibernate.bytecode.util.ClassFilter; /** * Enhance the classes allowing them to implements InterceptFieldEnabled * This interface is then used by Hibernate for some optimizations. * * @author Emmanuel Bernard + * @author Steve Ebersole */ public class JavassistClassTransformer extends AbstractClassTransformerImpl { private static Log log = LogFactory.getLog( JavassistClassTransformer.class.getName() ); - public JavassistClassTransformer(String[] packages, String[] classes) { - super(packages, classes); + public JavassistClassTransformer(ClassFilter classFilter, org.hibernate.bytecode.util.FieldFilter fieldFilter) { + super( classFilter, fieldFilter ); } protected byte[] doTransform( @@ -75,23 +74,29 @@ return classfileBuffer; } - protected FieldTransformer getFieldTransformer(ClassFile classfile) { + protected FieldTransformer getFieldTransformer(final ClassFile classfile) { if ( alreadyInstrumented( classfile ) ) { return null; } - else { - return new FieldTransformer( - new FieldFilter() { - public boolean handleRead(String desc, String name) { - return true; - } + return new FieldTransformer( + new FieldFilter() { + public boolean handleRead(String desc, String name) { + return fieldFilter.shouldInstrumentField( classfile.getName(), name ); + } - public boolean handleWrite(String desc, String name) { - return true; - } + public boolean handleWrite(String desc, String name) { + return fieldFilter.shouldInstrumentField( classfile.getName(), name ); } - ); - } + + public boolean handleReadAccess(String fieldOwnerClassName, String fieldName) { + return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName ); + } + + public boolean handleWriteAccess(String fieldOwnerClassName, String fieldName) { + return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName ); + } + } + ); } private boolean alreadyInstrumented(ClassFile classfile) { Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,59 @@ +package org.hibernate.bytecode.util; + +import java.util.Set; +import java.util.HashSet; + +/** + * BasicClassFilter provides class filtering based on a series of packages to + * be included and/or a series of explicit class names to be included. If + * neither is specified, then no restrictions are applied. + * + * @author Steve Ebersole + */ +public class BasicClassFilter implements ClassFilter { + private final String[] includedPackages; + private final Set includedClassNames = new HashSet(); + private final boolean isAllEmpty; + + public BasicClassFilter() { + this( null, null ); + } + + public BasicClassFilter(String[] includedPackages, String[] includedClassNames) { + this.includedPackages = includedPackages; + if ( includedClassNames != null ) { + for ( int i = 0; i < includedClassNames.length; i++ ) { + this.includedClassNames.add( includedClassNames[i] ); + } + } + + isAllEmpty = ( this.includedPackages == null || this.includedPackages.length == 0 ) + && ( this.includedClassNames.isEmpty() ); + } + + public boolean shouldInstrumentClass(String className) { + if ( isAllEmpty ) { + return true; + } + else if ( includedClassNames.contains( className ) ) { + return true; + } + else if ( isInIncludedPackage( className ) ) { + return true; + } + else { + return false; + } + } + + private boolean isInIncludedPackage(String className) { + if ( includedPackages != null ) { + for ( int i = 0; i < includedPackages.length; i++ ) { + if ( className.startsWith( includedPackages[i] ) ) { + return true; + } + } + } + return false; + } +} Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,78 @@ +package org.hibernate.bytecode.util; + +import java.io.InputStream; +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.util.zip.ZipInputStream; + +/** + * A helper for reading byte code from various input sources. + * + * @author Steve Ebersole + */ +public class ByteCodeHelper { + private ByteCodeHelper() { + } + + /** + * Reads class byte array info from the given input stream. + * <p/> + * The stream is closed within this method! + * + * @param inputStream + * @return + * @throws IOException + */ + public static byte[] readByteCode(InputStream inputStream) throws IOException { + if ( inputStream == null ) { + throw new IOException( "null input stream" ); + } + + byte[] buffer = new byte[409600]; + byte[] classBytes = new byte[0]; + int r = 0; + + try { + r = inputStream.read( buffer ); + while ( r >= buffer.length ) { + byte[] temp = new byte[ classBytes.length + buffer.length ]; + System.arraycopy( classBytes, 0, temp, 0, classBytes.length ); + System.arraycopy( buffer, 0, temp, classBytes.length, buffer.length ); + classBytes = temp; + } + if ( r != -1 ) { + byte[] temp = new byte[ classBytes.length + r ]; + System.arraycopy( classBytes, 0, temp, 0, classBytes.length ); + System.arraycopy( buffer, 0, temp, classBytes.length, r ); + classBytes = temp; + } + } + finally { + try { + inputStream.close(); + } + catch (IOException ignore) { + // intentionally empty + } + } + + return classBytes; + } + + public static byte[] readByteCode(File file) throws IOException { + return ByteCodeHelper.readByteCode( new FileInputStream( file ) ); + } + + public static byte[] readByteCode(ZipInputStream zip) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + InputStream in = new BufferedInputStream( zip ); + int b; + while ( ( b = in.read() ) != -1 ) { + bout.write( b ); + } + return bout.toByteArray(); + } +} Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,30 @@ +package org.hibernate.bytecode.util; + +/** + * Contract describing the information Hibernate needs in terms of instrumenting + * a class, either via ant task or dynamic classloader. + * + * @author Steve Ebersole + */ +public interface ClassDescriptor { + /** + * The name of the class. + * + * @return The class name. + */ + public String getName(); + + /** + * Determine if the class is already instrumented. + * + * @return True if already instrumented; false otherwise. + */ + public boolean isInstrumented(); + + /** + * The bytes making up the class' bytecode. + * + * @return The bytecode bytes. + */ + public byte[] getBytes(); +} Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,10 @@ +package org.hibernate.bytecode.util; + +/** + * Used to determine whether a class should be instrumented. + * + * @author Steve Ebersole + */ +public interface ClassFilter { + public boolean shouldInstrumentClass(String className); +} Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,29 @@ +package org.hibernate.bytecode.util; + +/** + * Used to determine whether a field reference should be instrumented. + * + * @author Steve Ebersole + */ +public interface FieldFilter { + /** + * Should this field definition be instrumented? + * + * @param className The name of the class currently being processed + * @param fieldName The name of the field being checked. + * @return True if we should instrument this field. + */ + public boolean shouldInstrumentField(String className, String fieldName); + + /** + * Should we instrument *access to* the given field. This differs from + * {@link #shouldInstrumentField} in that here we are talking about a particular usage of + * a field. + * + * @param transformingClassName The class currently being transformed. + * @param fieldOwnerClassName The name of the class owning this field being checked. + * @param fieldName The name of the field being checked. + * @return True if this access should be transformed. + */ + public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName); +} Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -27,7 +27,7 @@ Class[] definedInterfaces = entityClass.getInterfaces(); for ( int i = 0; i < definedInterfaces.length; i++ ) { if ( "net.sf.cglib.transform.impl.InterceptFieldEnabled".equals( definedInterfaces[i].getName() ) - || "org.hibernate.tool.instrument.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { + || "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { return true; } } @@ -48,7 +48,7 @@ // we have a CGLIB enhanced entity return CGLIBHelper.extractFieldInterceptor( entity ); } - else if ( "org.hibernate.tool.instrument.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { + else if ( "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { // we have a Javassist enhanced entity return JavassistHelper.extractFieldInterceptor( entity ); } @@ -68,7 +68,7 @@ // we have a CGLIB enhanced entity return CGLIBHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session ); } - else if ( "org.hibernate.tool.instrument.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { + else if ( "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { // we have a Javassist enhanced entity return JavassistHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session ); } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -4,7 +4,7 @@ import java.io.Serializable; import java.util.Set; -import org.hibernate.tool.instrument.javassist.FieldHandler; +import org.hibernate.bytecode.javassist.FieldHandler; import org.hibernate.intercept.AbstractFieldInterceptor; import org.hibernate.engine.SessionImplementor; import org.hibernate.proxy.HibernateProxy; Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -2,7 +2,7 @@ import org.hibernate.intercept.FieldInterceptor; import org.hibernate.engine.SessionImplementor; -import org.hibernate.tool.instrument.javassist.FieldHandled; +import org.hibernate.bytecode.javassist.FieldHandled; import java.util.Set; Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java 2006-08-03 20:16:18 UTC (rev 10208) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java 2006-08-03 20:35:26 UTC (rev 10209) @@ -0,0 +1,383 @@ +package org.hibernate.tool.instrument; + +import org.apache.tools.ant.Task; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.FileSet; +import org.hibernate.bytecode.util.ClassDescriptor; +import org.hibernate.bytecode.util.ByteCodeHelper; +import org.hibernate.bytecode.util.FieldFilter; +import org.hibernate.bytecode.ClassTransformer; + +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Set; +import java.util.HashSet; +import java.util.zip.ZipInputStream; +im... [truncated message content] |
From: <hib...@li...> - 2006-08-03 20:16:51
|
Author: ste...@jb... Date: 2006-08-03 16:16:18 -0400 (Thu, 03 Aug 2006) New Revision: 10208 Removed: trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java Modified: trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java Log: HHH-1968 : unify bytecode instrumentation Modified: trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java 2006-08-03 20:15:36 UTC (rev 10207) +++ trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java 2006-08-03 20:16:18 UTC (rev 10208) @@ -4,6 +4,9 @@ import org.hibernate.HibernateException; import org.hibernate.bytecode.BytecodeProvider; +import org.hibernate.bytecode.InstrumentedClassLoader; +import org.hibernate.bytecode.util.BasicClassFilter; +import org.hibernate.bytecode.util.FieldFilter; import org.hibernate.test.AbstractClassLoaderIsolatedTestCase; /** @@ -14,21 +17,25 @@ private BytecodeProvider provider; protected ClassLoader buildIsolatedClassLoader(ClassLoader parent) { -// String myFileName = AbstractTransformingClassLoaderInstrumentTestCase.class.getName().replace( '.', '/' ) + ".class"; -// URL fileURL = this.getClass().getClassLoader().getResource( myFileName ); -// String filePath = fileURL.getPath(); -// String classPath = filePath.substring( 0, filePath.length() - myFileName.length() ); provider = buildBytecodeProvider(); return new InstrumentedClassLoader( parent, - provider.getEntityClassTransformer( - new String[] { "org.hibernate.test.instrument" }, - null) ); + provider.getTransformer( + new BasicClassFilter( new String[] { "org.hibernate.test.instrument" }, null ), + new FieldFilter() { + public boolean shouldInstrumentField(String className, String fieldName) { + return true; + } + public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName) { + return true; + } + } + ) + ); } protected void releaseIsolatedClassLoader(ClassLoader isolatedLoader) { - provider.releaseDynamicFieldInterceptionClassLoader( isolatedLoader ); provider = null; } Deleted: trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java 2006-08-03 20:15:36 UTC (rev 10207) +++ trunk/Hibernate3/test/org/hibernate/test/instrument/runtime/InstrumentedClassLoader.java 2006-08-03 20:16:18 UTC (rev 10208) @@ -1,80 +0,0 @@ -//$Id: $ -package org.hibernate.test.instrument.runtime; - -import java.io.IOException; -import java.io.InputStream; - -import org.hibernate.HibernateException; -import org.hibernate.bytecode.ClassTransformer; - -/** - * @author Emmanuel Bernard - */ -public class InstrumentedClassLoader extends ClassLoader { - - private ClassTransformer classTransformer; - - public InstrumentedClassLoader(ClassLoader parent, ClassTransformer classTransformer) { - super( parent ); - this.classTransformer = classTransformer; - } - - public Class loadClass(String name) throws ClassNotFoundException { - if ( name.startsWith( "java" ) ) return getParent().loadClass( name ); - Class c = findLoadedClass( name ); - if ( c != null ) return c; - InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" ); - if ( is == null ) throw new ClassNotFoundException( name ); - byte[] buffer = new byte[409600]; - byte[] originalClass = new byte[0]; - int r = 0; - try { - r = is.read( buffer ); - } - catch (IOException e) { - throw new ClassNotFoundException( name + " not found", e ); - } - while ( r >= buffer.length ) { - byte[] temp = new byte[ originalClass.length + buffer.length ]; - System.arraycopy( originalClass, 0, temp, 0, originalClass.length ); - System.arraycopy( buffer, 0, temp, originalClass.length, buffer.length ); - originalClass = temp; - } - if ( r != -1 ) { - byte[] temp = new byte[ originalClass.length + r ]; - System.arraycopy( originalClass, 0, temp, 0, originalClass.length ); - System.arraycopy( buffer, 0, temp, originalClass.length, r ); - originalClass = temp; - } - try { - is.close(); - } - catch (IOException e) { - throw new ClassNotFoundException( name + " not found", e ); - } - if (classTransformer != null) { - byte[] transformed = new byte[0]; - try { - transformed = classTransformer.transform( - getParent(), - name, - null, - null, - originalClass - ); - if ( originalClass == transformed) { - return getParent().loadClass(name); - } - else { - return defineClass( name, transformed, 0, transformed.length ); - } - } - catch (HibernateException e) { - throw new ClassNotFoundException( name + " not found", e ); - } - } - else { - return getParent().loadClass(name); - } - } -} |
From: <hib...@li...> - 2006-08-03 20:15:43
|
Author: ste...@jb... Date: 2006-08-03 16:15:36 -0400 (Thu, 03 Aug 2006) New Revision: 10207 Added: trunk/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java Log: HHH-1968 : unify bytecode instrumentation Added: trunk/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java 2006-08-03 19:59:42 UTC (rev 10206) +++ trunk/Hibernate3/src/org/hibernate/tool/instrument/BasicInstrumentationTask.java 2006-08-03 20:15:36 UTC (rev 10207) @@ -0,0 +1,383 @@ +package org.hibernate.tool.instrument; + +import org.apache.tools.ant.Task; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.FileSet; +import org.hibernate.bytecode.util.ClassDescriptor; +import org.hibernate.bytecode.util.ByteCodeHelper; +import org.hibernate.bytecode.util.FieldFilter; +import org.hibernate.bytecode.ClassTransformer; + +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Set; +import java.util.HashSet; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.CRC32; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.FileInputStream; +import java.io.DataInputStream; +import java.io.ByteArrayInputStream; + +/** + * Super class for all Hibernate instrumentation tasks. Provides the basic + * templating of how instrumentation should occur. + * + * @author Steve Ebersole + */ +public abstract class BasicInstrumentationTask extends Task { + + private static final int ZIP_MAGIC = 0x504B0304; + private static final int CLASS_MAGIC = 0xCAFEBABE; + + protected final Logger logger = new Logger(); + private List filesets = new ArrayList(); + private Set classNames = new HashSet(); + private boolean extended; + private boolean verbose; + + public void addFileset(FileSet set) { + this.filesets.add( set ); + } + + protected final Iterator filesets() { + return filesets.iterator(); + } + + public boolean isExtended() { + return extended; + } + + public void setExtended(boolean extended) { + this.extended = extended; + } + + public boolean isVerbose() { + return verbose; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public void execute() throws BuildException { + if ( isExtended() ) { + collectClassNames(); + } + logger.info( "starting instrumentation" ); + Project project = getProject(); + Iterator filesets = filesets(); + while ( filesets.hasNext() ) { + FileSet fs = ( FileSet ) filesets.next(); + DirectoryScanner ds = fs.getDirectoryScanner( project ); + String[] includedFiles = ds.getIncludedFiles(); + File d = fs.getDir( project ); + for ( int i = 0; i < includedFiles.length; ++i ) { + File file = new File( d, includedFiles[i] ); + try { + processFile( file ); + } + catch ( Exception e ) { + throw new BuildException( e ); + } + } + } + } + + private void collectClassNames() { + logger.info( "collecting class names for extended instrumentation determination" ); + Project project = getProject(); + Iterator filesets = filesets(); + while ( filesets.hasNext() ) { + FileSet fs = ( FileSet ) filesets.next(); + DirectoryScanner ds = fs.getDirectoryScanner( project ); + String[] includedFiles = ds.getIncludedFiles(); + File d = fs.getDir( project ); + for ( int i = 0; i < includedFiles.length; ++i ) { + File file = new File( d, includedFiles[i] ); + try { + collectClassNames( file ); + } + catch ( Exception e ) { + throw new BuildException( e ); + } + } + } + logger.info( classNames.size() + " class(es) being checked" ); + } + + private void collectClassNames(File file) throws Exception { + if ( isClassFile( file ) ) { + byte[] bytes = ByteCodeHelper.readByteCode( file ); + ClassDescriptor descriptor = getClassDescriptor( bytes ); + classNames.add( descriptor.getName() ); + } + else if ( isJarFile( file ) ) { + ZipEntryHandler collector = new ZipEntryHandler() { + public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception { + if ( !entry.isDirectory() ) { + // see if the entry represents a class file + DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) ); + if ( din.readInt() == CLASS_MAGIC ) { + classNames.add( getClassDescriptor( byteCode ).getName() ); + } + } + } + }; + ZipFileProcessor processor = new ZipFileProcessor( collector ); + processor.process( file ); + } + } + + protected void processFile(File file) throws Exception { + if ( isClassFile( file ) ) { + processClassFile(file); + } + else if ( isJarFile( file ) ) { + processJarFile(file); + } + else { + logger.verbose( "ignoring " + file.toURL() ); + + } + } + + protected final boolean isClassFile(File file) throws IOException { + return checkMagic( file, CLASS_MAGIC ); + } + + protected final boolean isJarFile(File file) throws IOException { + return checkMagic(file, ZIP_MAGIC); + } + + protected final boolean checkMagic(File file, long magic) throws IOException { + DataInputStream in = new DataInputStream( new FileInputStream( file ) ); + try { + int m = in.readInt(); + return magic == m; + } + finally { + in.close(); + } + } + + protected void processClassFile(File file) throws Exception { + logger.verbose( "Starting class file : " + file.toURL() ); + byte[] bytes = ByteCodeHelper.readByteCode( file ); + ClassDescriptor descriptor = getClassDescriptor( bytes ); + ClassTransformer transformer = getClassTransformer( descriptor ); + if ( transformer == null ) { + logger.verbose( "skipping file : " + file.toURL() ); + return; + } + + logger.info( "processing class [" + descriptor.getName() + "]; file = " + file.toURL() ); + byte[] transformedBytes = transformer.transform( + getClass().getClassLoader(), + descriptor.getName(), + null, + null, + descriptor.getBytes() + ); + + OutputStream out = new FileOutputStream( file ); + try { + out.write( transformedBytes ); + out.flush(); + } + finally { + try { + out.close(); + } + catch ( IOException ignore) { + // intentionally empty + } + } + } + + protected void processJarFile(final File file) throws Exception { + logger.verbose( "starting jar file : " + file.toURL() ); + + File tempFile = File.createTempFile( + file.getName(), + null, + new File( file.getAbsoluteFile().getParent() ) + ); + + try { + FileOutputStream fout = new FileOutputStream( tempFile, false ); + try { + final ZipOutputStream out = new ZipOutputStream( fout ); + ZipEntryHandler transformer = new ZipEntryHandler() { + public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception { + logger.verbose( "starting entry : " + entry.toString() ); + if ( !entry.isDirectory() ) { + // see if the entry represents a class file + DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) ); + if ( din.readInt() == CLASS_MAGIC ) { + ClassDescriptor descriptor = getClassDescriptor( byteCode ); + ClassTransformer transformer = getClassTransformer( descriptor ); + if ( transformer == null ) { + logger.verbose( "skipping entry : " + entry.toString() ); + } + else { + logger.info( "processing class [" + descriptor.getName() + "]; entry = " + file.toURL() ); + byteCode = transformer.transform( + getClass().getClassLoader(), + descriptor.getName(), + null, + null, + descriptor.getBytes() + ); + } + } + else { + logger.verbose( "ignoring zip entry : " + entry.toString() ); + } + } + + ZipEntry outEntry = new ZipEntry( entry.getName() ); + outEntry.setMethod( entry.getMethod() ); + outEntry.setComment( entry.getComment() ); + outEntry.setSize( byteCode.length ); + + if ( outEntry.getMethod() == ZipEntry.STORED ){ + CRC32 crc = new CRC32(); + crc.update( byteCode ); + outEntry.setCrc( crc.getValue() ); + outEntry.setCompressedSize( byteCode.length ); + } + out.putNextEntry( outEntry ); + out.write( byteCode ); + out.closeEntry(); + } + }; + ZipFileProcessor processor = new ZipFileProcessor( transformer ); + processor.process( file ); + out.close(); + } + finally{ + fout.close(); + } + + if ( file.delete() ) { + File newFile = new File( tempFile.getAbsolutePath() ); + if( !newFile.renameTo( file ) ) { + throw new IOException( "can not rename " + tempFile + " to " + file ); + } + } + else { + throw new IOException("can not delete " + file); + } + } + finally { + tempFile.delete(); + } + } + + protected boolean isBeingIntrumented(String className) { + logger.verbose( "checking to see if class [" + className + "] is set to be instrumented" ); + return classNames.contains( className ); + } + + protected abstract ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception; + + protected abstract ClassTransformer getClassTransformer(ClassDescriptor descriptor); + + protected class CustomFieldFilter implements FieldFilter { + private final ClassDescriptor descriptor; + + public CustomFieldFilter(ClassDescriptor descriptor) { + this.descriptor = descriptor; + } + + public boolean shouldInstrumentField(String className, String fieldName) { + if ( descriptor.getName().equals( className ) ) { + logger.verbose( "accepting transformation of field [" + className + "." + fieldName + "]" ); + return true; + } + else { + logger.verbose( "not accepting transformation of field [" + className + "." + fieldName + "]" ); + return false; + } + } + + public boolean shouldTransformFieldAccess( + String transformingClassName, + String fieldOwnerClassName, + String fieldName) { + if ( descriptor.getName().equals( fieldOwnerClassName ) ) { + logger.verbose( "accepting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" ); + return true; + } + else if ( isExtended() && isBeingIntrumented( fieldOwnerClassName ) ) { + logger.verbose( "accepting extended transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" ); + return true; + } + else { + logger.verbose( "not accepting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" ); + return false; + } + } + } + + protected class Logger { + public void verbose(String message) { + if ( verbose ) { + System.out.println( message ); + } + else { + log( message, Project.MSG_VERBOSE ); + } + } + + public void debug(String message) { + log( message, Project.MSG_DEBUG ); + } + + public void info(String message) { + log( message, Project.MSG_INFO ); + } + + public void warn(String message) { + log( message, Project.MSG_WARN ); + } + } + + + private static interface ZipEntryHandler { + public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception; + } + + private static class ZipFileProcessor { + private final ZipEntryHandler entryHandler; + + public ZipFileProcessor(ZipEntryHandler entryHandler) { + this.entryHandler = entryHandler; + } + + public void process(File file) throws Exception { + ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) ); + + try { + ZipEntry entry; + while ( (entry = zip.getNextEntry()) != null ) { + byte bytes[] = ByteCodeHelper.readByteCode( zip ); + entryHandler.handleEntry( entry, bytes ); + zip.closeEntry(); + } + } + finally { + zip.close(); + } + } + } +} |
Author: ste...@jb... Date: 2006-08-03 15:59:42 -0400 (Thu, 03 Aug 2006) New Revision: 10206 Added: trunk/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java trunk/Hibernate3/src/org/hibernate/bytecode/util/ trunk/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java trunk/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java trunk/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java Removed: trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldFilter.java trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandled.java trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandler.java trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldTransformer.java Modified: trunk/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java trunk/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java trunk/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java trunk/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java trunk/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java trunk/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java trunk/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/InstrumentTask.java Log: HHH-1968 : unify bytecode instrumentation Modified: trunk/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/AbstractClassTransformerImpl.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -1,30 +1,23 @@ //$Id: $ package org.hibernate.bytecode; +import org.hibernate.bytecode.util.ClassFilter; +import org.hibernate.bytecode.util.FieldFilter; + import java.security.ProtectionDomain; -import java.util.HashSet; -import java.util.Set; /** * @author Emmanuel Bernard + * @author Steve Ebersole */ public abstract class AbstractClassTransformerImpl implements ClassTransformer { - final private Set entities; - final private String[] packages; + protected final ClassFilter classFilter; + protected final FieldFilter fieldFilter; - - public AbstractClassTransformerImpl(String[] packages, String[] classes) { - this.packages = packages; - if (classes == null) { - this.entities = null; - } - else { - this.entities = new HashSet(); - for ( int i = 0; i < classes.length; i++ ) { - entities.add( classes[i] ); - } - } + protected AbstractClassTransformerImpl(ClassFilter classFilter, FieldFilter fieldFilter) { + this.classFilter = classFilter; + this.fieldFilter = fieldFilter; } public byte[] transform( @@ -33,25 +26,14 @@ Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { - boolean enhance = false; - String safeClassName = className.replace( '/', '.' ); - if ( entities == null && packages == null ) { - enhance = true; + // to be safe... + className = className.replace( '/', '.' ); + if ( classFilter.shouldInstrumentClass( className ) ) { + return doTransform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer ); } - if ( ! enhance && entities != null && entities.contains( safeClassName ) ) { - enhance = true; + else { + return classfileBuffer; } - if ( ! enhance && packages != null ) { - for ( int i = 0; i < packages.length; i++ ) { - if ( safeClassName.startsWith( packages[i] ) ) { - enhance = true; - break; - } - } - } - if ( ! enhance ) return classfileBuffer; - - return doTransform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer ); } protected abstract byte[] doTransform( Modified: trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/BytecodeProvider.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -1,15 +1,16 @@ package org.hibernate.bytecode; +import org.hibernate.bytecode.util.ClassFilter; +import org.hibernate.bytecode.util.FieldFilter; + /** * Contract for providers of bytecode services to Hibernate. * <p/> - * Bytecode requirements break down into basically 4 areas<ol> + * Bytecode requirements break down into basically 3 areas<ol> * <li>proxy generation (both for runtime-lazy-loading and basic proxy generation) * {@link #getProxyFactoryFactory()} * <li>bean relection optimization {@link #getReflectionOptimizer} - * <li>build-time instumentation (not covered by this contract) - * <li>class-load intrumentation {@link #generateDynamicFieldInterceptionClassLoader}; - * (currently only used in the test suite). + * <li>field-access instumentation {@link #getTransformer} * </ol> * * @author Steve Ebersole @@ -36,41 +37,13 @@ public ReflectionOptimizer getReflectionOptimizer(Class clazz, String[] getterNames, String[] setterNames, Class[] types); /** - * Generate a ClassLoader capable of performing dynamic bytecode manipulation - * on classes as they are loaded for the purpose of field-level interception. - * The returned ClassLoader is used for run-time bytecode manipulation as - * opposed to the more common build-time manipulation, since here we get - * into SecurityManager issues and such. - * <p/> - * Currently used only from the Hibernate test suite, although conceivably - * (SecurityManager concerns aside) could be used somehow in running systems. + * Generate a ClassTransformer capable of performing bytecode manipulation. * - * @param parent The parent classloader - * @param classpath The classpath to be searched - * @param packages can be null; use to limit the packages to be loaded - * via this classloader (and transformed). - * @return The appropriate ClassLoader. - */ - public ClassLoader generateDynamicFieldInterceptionClassLoader(ClassLoader parent, String[] classpath, String[] packages); - - /** - * Generate a ClassTransformer capable of performing dynamic bytecode manipulation - * on classes as they are loaded for the purpose of field-level interception. - * The returned ClassTransformer can be combined to an appropriate ClassLoader - * is used for run-time bytecode manipulation as - * opposed to the more common build-time manipulation, since here we get - * into SecurityManager issues and such. - * <p/> - * - * @param packages can be null; use to limit the packages to be transformed - * via this classtransformer. - * @param classes can be null; use to limit the classes to be transformed - * via this class transformer. + * @param classFilter filter used to limit which classes are to be instrumented + * via this ClassTransformer. + * @param fieldFilter filter used to limit which fields are to be instrumented + * via this ClassTransformer. * @return The appropriate ClassTransformer. */ - public ClassTransformer getEntityClassTransformer( - String[] packages, String[] classes - ); - - public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader); + public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter); } Added: trunk/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/InstrumentedClassLoader.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,54 @@ +package org.hibernate.bytecode; + +import org.hibernate.bytecode.util.ByteCodeHelper; + +import java.io.InputStream; + +/** + * A specialized classloader which performs bytecode enhancement on class + * definitions as they are loaded into the classloader scope. + * + * @author Emmanuel Bernard + * @author Steve Ebersole + */ +public class InstrumentedClassLoader extends ClassLoader { + + private ClassTransformer classTransformer; + + public InstrumentedClassLoader(ClassLoader parent, ClassTransformer classTransformer) { + super( parent ); + this.classTransformer = classTransformer; + } + + public Class loadClass(String name) throws ClassNotFoundException { + if ( name.startsWith( "java." ) || classTransformer == null ) { + return getParent().loadClass( name ); + } + + Class c = findLoadedClass( name ); + if ( c != null ) { + return c; + } + + InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" ); + if ( is == null ) { + throw new ClassNotFoundException( name + " not found" ); + } + + try { + byte[] originalBytecode = ByteCodeHelper.readByteCode( is ); + byte[] transformedBytecode = classTransformer.transform( getParent(), name, null, null, originalBytecode ); + if ( originalBytecode == transformedBytecode ) { + // no transformations took place, so handle it as we would a + // non-instrumented class + return getParent().loadClass( name ); + } + else { + return defineClass( name, transformedBytecode, 0, transformedBytecode.length ); + } + } + catch( Throwable t ) { + throw new ClassNotFoundException( name + " not found", t ); + } + } +} Modified: trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -16,6 +16,7 @@ import org.hibernate.bytecode.BytecodeProvider; import org.hibernate.bytecode.ProxyFactoryFactory; import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.bytecode.util.FieldFilter; import org.hibernate.util.StringHelper; import org.objectweb.asm.Type; @@ -84,58 +85,8 @@ } } - public ClassLoader generateDynamicFieldInterceptionClassLoader( - ClassLoader parent, - String[] classpath, - String[] packages) { - return new TransformingClassLoader( - parent, - new ClassLoaderClassFilter( packages ), - new ClassTransformerFactory() { - public ClassTransformer newInstance() { - return new InterceptFieldTransformer( - new InterceptFieldFilter() { - public boolean acceptRead(Type owner, String name) { - return true; - } - public boolean acceptWrite(Type owner, String name) { - return true; - } - } - ); - } - } - ); + public org.hibernate.bytecode.ClassTransformer getTransformer(org.hibernate.bytecode.util.ClassFilter classFilter, FieldFilter fieldFilter) { + return new CglibClassTransformer( classFilter, fieldFilter ); } - public org.hibernate.bytecode.ClassTransformer getEntityClassTransformer( - String[] packages, String[] classes - ) { - return new CglibClassTransformer( packages, classes ); - } - - public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader) { - } - - private static class ClassLoaderClassFilter implements ClassFilter { - private final String[] packages; - - public ClassLoaderClassFilter(String[] packages) { - this.packages = packages; - } - - public boolean accept(String className) { - if ( packages == null ) { - return true; - } - else { - for ( int i = 0; i < packages.length; i++ ) { - if ( className.startsWith( packages[i] ) ) { - return true; - } - } - return false; - } - } - } } Modified: trunk/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/cglib/CglibClassTransformer.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -2,7 +2,6 @@ package org.hibernate.bytecode.cglib; import java.security.ProtectionDomain; -import java.util.Arrays; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ByteArrayOutputStream; @@ -18,6 +17,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.bytecode.AbstractClassTransformerImpl; +import org.hibernate.bytecode.util.FieldFilter; +import org.hibernate.bytecode.util.ClassFilter; import org.hibernate.HibernateException; import org.objectweb.asm.Attribute; import org.objectweb.asm.Type; @@ -35,8 +36,8 @@ private static Log log = LogFactory.getLog( CglibClassTransformer.class.getName() ); - public CglibClassTransformer(String[] packages, String[] classes) { - super(packages, classes); + public CglibClassTransformer(ClassFilter classFilter, FieldFilter fieldFilter) { + super( classFilter, fieldFilter ); } protected byte[] doTransform( @@ -91,22 +92,29 @@ return false; } - private ClassTransformer getClassTransformer(String[] classInfo) { - if ( Arrays.asList( classInfo ).contains( InterceptFieldEnabled.class.getName() ) ) { + private ClassTransformer getClassTransformer(final String[] classInfo) { + if ( isAlreadyInstrumented( classInfo ) ) { return null; } - else { - return new InterceptFieldTransformer( - new InterceptFieldFilter() { - public boolean acceptRead(Type owner, String name) { - return true; - } + return new InterceptFieldTransformer( + new InterceptFieldFilter() { + public boolean acceptRead(Type owner, String name) { + return fieldFilter.shouldTransformFieldAccess( classInfo[0], owner.getClassName(), name ); + } - public boolean acceptWrite(Type owner, String name) { - return true; - } + public boolean acceptWrite(Type owner, String name) { + return fieldFilter.shouldTransformFieldAccess( classInfo[0], owner.getClassName(), name ); } - ); + } + ); + } + + private boolean isAlreadyInstrumented(String[] classInfo) { + for ( int i = 1; i < classInfo.length; i++ ) { + if ( InterceptFieldEnabled.class.getName().equals( classInfo[i] ) ) { + return true; + } } + return false; } } Modified: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -8,6 +8,8 @@ import org.hibernate.bytecode.ClassTransformer; import org.hibernate.bytecode.ProxyFactoryFactory; import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.bytecode.util.ClassFilter; +import org.hibernate.bytecode.util.FieldFilter; import org.hibernate.util.StringHelper; /** @@ -75,20 +77,8 @@ } } - public ClassLoader generateDynamicFieldInterceptionClassLoader(ClassLoader parent, String[] classpath, String[] packages) { - return new TransformingClassLoader( parent, classpath ); + public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter) { + return new JavassistClassTransformer( classFilter, fieldFilter ); } - public ClassTransformer getEntityClassTransformer( - String[] packages, String[] classes - ) { - return new JavassistClassTransformer( packages, classes ); - } - - public void releaseDynamicFieldInterceptionClassLoader(ClassLoader classLoader) { - if ( ! TransformingClassLoader.class.isAssignableFrom( classLoader.getClass() ) ) { - return; - } - ( ( TransformingClassLoader ) classLoader ).release(); - } } Copied: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java (from rev 10190, trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldFilter.java) =================================================================== --- trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldFilter.java 2006-08-02 13:41:02 UTC (rev 10190) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,33 @@ +package org.hibernate.bytecode.javassist; + +/** + * Contract for deciding whether fields should be read and/or write intercepted. + * + * @author Muga Nishizawa + * @author Steve Ebersole + */ +public interface FieldFilter { + /** + * Should the given field be read intercepted? + * + * @param desc + * @param name + * @return true if the given field should be read intercepted; otherwise + * false. + */ + boolean handleRead(String desc, String name); + + /** + * Should the given field be write intercepted? + * + * @param desc + * @param name + * @return true if the given field should be write intercepted; otherwise + * false. + */ + boolean handleWrite(String desc, String name); + + boolean handleReadAccess(String fieldOwnerClassName, String fieldName); + + boolean handleWriteAccess(String fieldOwnerClassName, String fieldName); +} Property changes on: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldFilter.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Copied: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java (from rev 10190, trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandled.java) =================================================================== --- trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandled.java 2006-08-02 13:41:02 UTC (rev 10190) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,23 @@ +package org.hibernate.bytecode.javassist; + +/** + * Interface introduced to the enhanced class in order to be able to + * inject a {@link FieldHandler} to define the interception behavior. + * + * @author Muga Nishizawa + */ +public interface FieldHandled { + /** + * Inject the field interception handler to be used. + * + * @param handler The field interception handler. + */ + public void setFieldHandler(FieldHandler handler); + + /** + * Access to the current field interception handler. + * + * @return The current field interception handler. + */ + public FieldHandler getFieldHandler(); +} Property changes on: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandled.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Copied: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java (from rev 10190, trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandler.java) =================================================================== --- trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldHandler.java 2006-08-02 13:41:02 UTC (rev 10190) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,56 @@ +package org.hibernate.bytecode.javassist; + +/** + * The interface defining how interception of a field should be handled. + * + * @author Muga Nishizawa + */ +public interface FieldHandler { + + /** + * Called to handle writing an int value to a given field. + * + * @param obj ? + * @param name The name of the field being written + * @param oldValue The old field value + * @param newValue The new field value. + * @return ? + */ + int writeInt(Object obj, String name, int oldValue, int newValue); + + char writeChar(Object obj, String name, char oldValue, char newValue); + + byte writeByte(Object obj, String name, byte oldValue, byte newValue); + + boolean writeBoolean(Object obj, String name, boolean oldValue, + boolean newValue); + + short writeShort(Object obj, String name, short oldValue, short newValue); + + float writeFloat(Object obj, String name, float oldValue, float newValue); + + double writeDouble(Object obj, String name, double oldValue, double newValue); + + long writeLong(Object obj, String name, long oldValue, long newValue); + + Object writeObject(Object obj, String name, Object oldValue, Object newValue); + + int readInt(Object obj, String name, int oldValue); + + char readChar(Object obj, String name, char oldValue); + + byte readByte(Object obj, String name, byte oldValue); + + boolean readBoolean(Object obj, String name, boolean oldValue); + + short readShort(Object obj, String name, short oldValue); + + float readFloat(Object obj, String name, float oldValue); + + double readDouble(Object obj, String name, double oldValue); + + long readLong(Object obj, String name, long oldValue); + + Object readObject(Object obj, String name, Object oldValue); + +} Property changes on: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldHandler.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Copied: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java (from rev 10190, trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldTransformer.java) =================================================================== --- trunk/Hibernate3/src/org/hibernate/tool/instrument/javassist/FieldTransformer.java 2006-08-02 13:41:02 UTC (rev 10190) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,581 @@ +package org.hibernate.bytecode.javassist; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.Iterator; +import java.util.List; + +import javassist.CannotCompileException; +import javassist.bytecode.AccessFlag; +import javassist.bytecode.BadBytecode; +import javassist.bytecode.Bytecode; +import javassist.bytecode.ClassFile; +import javassist.bytecode.CodeAttribute; +import javassist.bytecode.CodeIterator; +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import javassist.bytecode.FieldInfo; +import javassist.bytecode.MethodInfo; +import javassist.bytecode.Opcode; + +/** + * The thing that handles actual class enhancement in regards to + * intercepting field accesses. + * + * @author Muga Nishizawa + * @author Steve Ebersole + */ +public class FieldTransformer { + + private static final String EACH_READ_METHOD_PREFIX = "$javassist_read_"; + + private static final String EACH_WRITE_METHOD_PREFIX = "$javassist_write_"; + + private static final String FIELD_HANDLED_TYPE_NAME = FieldHandled.class + .getName(); + + private static final String HANDLER_FIELD_NAME = "$JAVASSIST_READ_WRITE_HANDLER"; + + private static final String FIELD_HANDLER_TYPE_NAME = FieldHandler.class + .getName(); + + private static final String HANDLER_FIELD_DESCRIPTOR = 'L' + FIELD_HANDLER_TYPE_NAME + .replace('.', '/') + ';'; + + private static final String GETFIELDHANDLER_METHOD_NAME = "getFieldHandler"; + + private static final String SETFIELDHANDLER_METHOD_NAME = "setFieldHandler"; + + private static final String GETFIELDHANDLER_METHOD_DESCRIPTOR = "()" + + HANDLER_FIELD_DESCRIPTOR; + + private static final String SETFIELDHANDLER_METHOD_DESCRIPTOR = "(" + + HANDLER_FIELD_DESCRIPTOR + ")V"; + + private FieldFilter filter; + + public FieldTransformer() { + this(null); + } + + public FieldTransformer(FieldFilter f) { + filter = f; + } + + public void setFieldFilter(FieldFilter f) { + filter = f; + } + + public void transform(File file) throws Exception { + DataInputStream in = new DataInputStream(new FileInputStream(file)); + ClassFile classfile = new ClassFile(in); + transform(classfile); + DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); + try { + classfile.write(out); + } finally { + out.close(); + } + } + + public void transform(ClassFile classfile) throws Exception { + if (classfile.isInterface()) { + return; + } + try { + addFieldHandlerField(classfile); + addGetFieldHandlerMethod(classfile); + addSetFieldHandlerMethod(classfile); + addFieldHandledInterface(classfile); + addReadWriteMethods(classfile); + transformInvokevirtualsIntoPutAndGetfields(classfile); + } catch (CannotCompileException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + private void addFieldHandlerField(ClassFile classfile) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + FieldInfo finfo = new FieldInfo(cp, HANDLER_FIELD_NAME, + HANDLER_FIELD_DESCRIPTOR); + finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.TRANSIENT); + classfile.addField(finfo); + } + + private void addGetFieldHandlerMethod(ClassFile classfile) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + MethodInfo minfo = new MethodInfo(cp, GETFIELDHANDLER_METHOD_NAME, + GETFIELDHANDLER_METHOD_DESCRIPTOR); + /* local variable | this | */ + Bytecode code = new Bytecode(cp, 2, 1); + // aload_0 // load this + code.addAload(0); + // getfield // get field "$JAVASSIST_CALLBACK" defined already + code.addOpcode(Opcode.GETFIELD); + int field_index = cp.addFieldrefInfo(this_class_index, + HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); + code.addIndex(field_index); + // areturn // return the value of the field + code.addOpcode(Opcode.ARETURN); + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void addSetFieldHandlerMethod(ClassFile classfile) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + MethodInfo minfo = new MethodInfo(cp, SETFIELDHANDLER_METHOD_NAME, + SETFIELDHANDLER_METHOD_DESCRIPTOR); + /* local variables | this | callback | */ + Bytecode code = new Bytecode(cp, 3, 3); + // aload_0 // load this + code.addAload(0); + // aload_1 // load callback + code.addAload(1); + // putfield // put field "$JAVASSIST_CALLBACK" defined already + code.addOpcode(Opcode.PUTFIELD); + int field_index = cp.addFieldrefInfo(this_class_index, + HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); + code.addIndex(field_index); + // return + code.addOpcode(Opcode.RETURN); + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void addFieldHandledInterface(ClassFile classfile) { + String[] interfaceNames = classfile.getInterfaces(); + String[] newInterfaceNames = new String[interfaceNames.length + 1]; + System.arraycopy(interfaceNames, 0, newInterfaceNames, 0, + interfaceNames.length); + newInterfaceNames[newInterfaceNames.length - 1] = FIELD_HANDLED_TYPE_NAME; + classfile.setInterfaces(newInterfaceNames); + } + + private void addReadWriteMethods(ClassFile classfile) + throws CannotCompileException { + List fields = classfile.getFields(); + for (Iterator field_iter = fields.iterator(); field_iter.hasNext();) { + FieldInfo finfo = (FieldInfo) field_iter.next(); + if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0 + && (!finfo.getName().equals(HANDLER_FIELD_NAME))) { + // case of non-static field + if (filter.handleRead(finfo.getDescriptor(), finfo + .getName())) { + addReadMethod(classfile, finfo); + } + if (filter.handleWrite(finfo.getDescriptor(), finfo + .getName())) { + addWriteMethod(classfile, finfo); + } + } + } + } + + private void addReadMethod(ClassFile classfile, FieldInfo finfo) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + String desc = "()" + finfo.getDescriptor(); + MethodInfo minfo = new MethodInfo(cp, EACH_READ_METHOD_PREFIX + + finfo.getName(), desc); + /* local variables | target obj | each oldvalue | */ + Bytecode code = new Bytecode(cp, 5, 3); + // aload_0 + code.addAload(0); + // getfield // get each field + code.addOpcode(Opcode.GETFIELD); + int base_field_index = cp.addFieldrefInfo(this_class_index, finfo + .getName(), finfo.getDescriptor()); + code.addIndex(base_field_index); + // aload_0 + code.addAload(0); + // invokeinterface // invoke Enabled.getInterceptFieldCallback() + int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME); + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // ifnonnull + code.addOpcode(Opcode.IFNONNULL); + code.addIndex(4); + // *return // each type + addTypeDependDataReturn(code, finfo.getDescriptor()); + // *store_1 // each type + addTypeDependDataStore(code, finfo.getDescriptor(), 1); + // aload_0 + code.addAload(0); + // invokeinterface // invoke Enabled.getInterceptFieldCallback() + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // aload_0 + code.addAload(0); + // ldc // name of the field + code.addLdc(finfo.getName()); + // *load_1 // each type + addTypeDependDataLoad(code, finfo.getDescriptor(), 1); + // invokeinterface // invoke Callback.read*() // each type + addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(), + true); + // *return // each type + addTypeDependDataReturn(code, finfo.getDescriptor()); + + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void addWriteMethod(ClassFile classfile, FieldInfo finfo) + throws CannotCompileException { + ConstPool cp = classfile.getConstPool(); + int this_class_index = cp.getThisClassInfo(); + String desc = "(" + finfo.getDescriptor() + ")V"; + MethodInfo minfo = new MethodInfo(cp, EACH_WRITE_METHOD_PREFIX + + finfo.getName(), desc); + /* local variables | target obj | each oldvalue | */ + Bytecode code = new Bytecode(cp, 6, 3); + // aload_0 + code.addAload(0); + // invokeinterface // enabled.getInterceptFieldCallback() + int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME); + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // ifnonnull (label1) + code.addOpcode(Opcode.IFNONNULL); + code.addIndex(9); + // aload_0 + code.addAload(0); + // *load_1 + addTypeDependDataLoad(code, finfo.getDescriptor(), 1); + // putfield + code.addOpcode(Opcode.PUTFIELD); + int base_field_index = cp.addFieldrefInfo(this_class_index, finfo + .getName(), finfo.getDescriptor()); + code.addIndex(base_field_index); + code.growStack(-Descriptor.dataSize(finfo.getDescriptor())); + // return ; + code.addOpcode(Opcode.RETURN); + // aload_0 + code.addAload(0); + // dup + code.addOpcode(Opcode.DUP); + // invokeinterface // enabled.getInterceptFieldCallback() + code.addInvokeinterface(enabled_class_index, + GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, + 1); + // aload_0 + code.addAload(0); + // ldc // field name + code.addLdc(finfo.getName()); + // aload_0 + code.addAload(0); + // getfield // old value of the field + code.addOpcode(Opcode.GETFIELD); + code.addIndex(base_field_index); + code.growStack(Descriptor.dataSize(finfo.getDescriptor()) - 1); + // *load_1 + addTypeDependDataLoad(code, finfo.getDescriptor(), 1); + // invokeinterface // callback.write*(..) + addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(), + false); + // putfield // new value of the field + code.addOpcode(Opcode.PUTFIELD); + code.addIndex(base_field_index); + code.growStack(-Descriptor.dataSize(finfo.getDescriptor())); + // return + code.addOpcode(Opcode.RETURN); + + minfo.setCodeAttribute(code.toCodeAttribute()); + minfo.setAccessFlags(AccessFlag.PUBLIC); + classfile.addMethod(minfo); + } + + private void transformInvokevirtualsIntoPutAndGetfields(ClassFile classfile) + throws CannotCompileException { + List methods = classfile.getMethods(); + for (Iterator method_iter = methods.iterator(); method_iter.hasNext();) { + MethodInfo minfo = (MethodInfo) method_iter.next(); + String methodName = minfo.getName(); + if (methodName.startsWith(EACH_READ_METHOD_PREFIX) + || methodName.startsWith(EACH_WRITE_METHOD_PREFIX) + || methodName.equals(GETFIELDHANDLER_METHOD_NAME) + || methodName.equals(SETFIELDHANDLER_METHOD_NAME)) { + continue; + } + CodeAttribute codeAttr = minfo.getCodeAttribute(); + if (codeAttr == null) { + return; + } + CodeIterator iter = codeAttr.iterator(); + while (iter.hasNext()) { + try { + int pos = iter.next(); + pos = transformInvokevirtualsIntoGetfields(classfile, iter, pos); + pos = transformInvokevirtualsIntoPutfields(classfile, iter, pos); + + } catch (BadBytecode e) { + throw new CannotCompileException(e); + } + } + } + } + + private int transformInvokevirtualsIntoGetfields(ClassFile classfile, CodeIterator iter, int pos) { + ConstPool cp = classfile.getConstPool(); + int c = iter.byteAt(pos); + if (c != Opcode.GETFIELD) { + return pos; + } + int index = iter.u16bitAt(pos + 1); + String fieldName = cp.getFieldrefName(index); + String className = cp.getFieldrefClassName(index); + if ( !filter.handleReadAccess( className, fieldName ) ) { + return pos; + } + String desc = "()" + cp.getFieldrefType( index ); + int read_method_index = cp.addMethodrefInfo( + cp.getThisClassInfo(), + EACH_READ_METHOD_PREFIX + fieldName, + desc + ); + iter.writeByte(Opcode.INVOKEVIRTUAL, pos); + iter.write16bit(read_method_index, pos + 1); + return pos; + } + + private int transformInvokevirtualsIntoPutfields( + ClassFile classfile, + CodeIterator iter, int pos) { + ConstPool cp = classfile.getConstPool(); + int c = iter.byteAt(pos); + if (c != Opcode.PUTFIELD) { + return pos; + } + int index = iter.u16bitAt(pos + 1); + String fieldName = cp.getFieldrefName(index); + String className = cp.getFieldrefClassName(index); + if ( !filter.handleWriteAccess( className, fieldName ) ) { + return pos; + } + String desc = "(" + cp.getFieldrefType( index ) + ")V"; + int write_method_index = cp.addMethodrefInfo( + cp.getThisClassInfo(), + EACH_WRITE_METHOD_PREFIX + fieldName, + desc + ); + iter.writeByte(Opcode.INVOKEVIRTUAL, pos); + iter.write16bit(write_method_index, pos + 1); + return pos; + } + + private static void addInvokeFieldHandlerMethod(ClassFile classfile, + Bytecode code, String typeName, boolean isReadMethod) { + ConstPool cp = classfile.getConstPool(); + // invokeinterface + int callback_type_index = cp.addClassInfo(FIELD_HANDLER_TYPE_NAME); + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + int indexOfL = typeName.indexOf('L'); + String type; + if (indexOfL == 0) { + // not array + type = typeName.substring(1, typeName.length() - 1); + type = type.replace('/', '.'); + } else if (indexOfL == -1) { + // array of primitive type + // do nothing + type = typeName; + } else { + // array of reference type + type = typeName.replace('/', '.'); + } + if (isReadMethod) { + code + .addInvokeinterface( + callback_type_index, + "readObject", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", + 4); + // checkcast + code.addCheckcast(type); + } else { + code + .addInvokeinterface( + callback_type_index, + "writeObject", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + 5); + // checkcast + code.addCheckcast(type); + } + } else if (typeName.equals("Z")) { + // boolean + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readBoolean", + "(Ljava/lang/Object;Ljava/lang/String;Z)Z", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeBoolean", + "(Ljava/lang/Object;Ljava/lang/String;ZZ)Z", 5); + } + } else if (typeName.equals("B")) { + // byte + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readByte", + "(Ljava/lang/Object;Ljava/lang/String;B)B", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeByte", + "(Ljava/lang/Object;Ljava/lang/String;BB)B", 5); + } + } else if (typeName.equals("C")) { + // char + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readChar", + "(Ljava/lang/Object;Ljava/lang/String;C)C", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeChar", + "(Ljava/lang/Object;Ljava/lang/String;CC)C", 5); + } + } else if (typeName.equals("I")) { + // int + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readInt", + "(Ljava/lang/Object;Ljava/lang/String;I)I", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeInt", + "(Ljava/lang/Object;Ljava/lang/String;II)I", 5); + } + } else if (typeName.equals("S")) { + // short + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readShort", + "(Ljava/lang/Object;Ljava/lang/String;S)S", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeShort", + "(Ljava/lang/Object;Ljava/lang/String;SS)S", 5); + } + } else if (typeName.equals("D")) { + // double + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readDouble", + "(Ljava/lang/Object;Ljava/lang/String;D)D", 5); + } else { + code.addInvokeinterface(callback_type_index, "writeDouble", + "(Ljava/lang/Object;Ljava/lang/String;DD)D", 7); + } + } else if (typeName.equals("F")) { + // float + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readFloat", + "(Ljava/lang/Object;Ljava/lang/String;F)F", 4); + } else { + code.addInvokeinterface(callback_type_index, "writeFloat", + "(Ljava/lang/Object;Ljava/lang/String;FF)F", 5); + } + } else if (typeName.equals("J")) { + // long + if (isReadMethod) { + code.addInvokeinterface(callback_type_index, "readLong", + "(Ljava/lang/Object;Ljava/lang/String;J)J", 5); + } else { + code.addInvokeinterface(callback_type_index, "writeLong", + "(Ljava/lang/Object;Ljava/lang/String;JJ)J", 7); + } + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + + private static void addTypeDependDataLoad(Bytecode code, String typeName, + int i) { + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + code.addAload(i); + } else if (typeName.equals("Z") || typeName.equals("B") + || typeName.equals("C") || typeName.equals("I") + || typeName.equals("S")) { + // boolean, byte, char, int, short + code.addIload(i); + } else if (typeName.equals("D")) { + // double + code.addDload(i); + } else if (typeName.equals("F")) { + // float + code.addFload(i); + } else if (typeName.equals("J")) { + // long + code.addLload(i); + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + + private static void addTypeDependDataStore(Bytecode code, String typeName, + int i) { + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + code.addAstore(i); + } else if (typeName.equals("Z") || typeName.equals("B") + || typeName.equals("C") || typeName.equals("I") + || typeName.equals("S")) { + // boolean, byte, char, int, short + code.addIstore(i); + } else if (typeName.equals("D")) { + // double + code.addDstore(i); + } else if (typeName.equals("F")) { + // float + code.addFstore(i); + } else if (typeName.equals("J")) { + // long + code.addLstore(i); + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + + private static void addTypeDependDataReturn(Bytecode code, String typeName) { + if ((typeName.charAt(0) == 'L') + && (typeName.charAt(typeName.length() - 1) == ';') + || (typeName.charAt(0) == '[')) { + // reference type + code.addOpcode(Opcode.ARETURN); + } else if (typeName.equals("Z") || typeName.equals("B") + || typeName.equals("C") || typeName.equals("I") + || typeName.equals("S")) { + // boolean, byte, char, int, short + code.addOpcode(Opcode.IRETURN); + } else if (typeName.equals("D")) { + // double + code.addOpcode(Opcode.DRETURN); + } else if (typeName.equals("F")) { + // float + code.addOpcode(Opcode.FRETURN); + } else if (typeName.equals("J")) { + // long + code.addOpcode(Opcode.LRETURN); + } else { + // bad type + throw new RuntimeException("bad type: " + typeName); + } + } + +} Property changes on: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/FieldTransformer.java ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Modified: trunk/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/javassist/JavassistClassTransformer.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -13,22 +13,21 @@ import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.bytecode.AbstractClassTransformerImpl; -import org.hibernate.tool.instrument.javassist.FieldFilter; -import org.hibernate.tool.instrument.javassist.FieldHandled; -import org.hibernate.tool.instrument.javassist.FieldTransformer; +import org.hibernate.bytecode.util.ClassFilter; /** * Enhance the classes allowing them to implements InterceptFieldEnabled * This interface is then used by Hibernate for some optimizations. * * @author Emmanuel Bernard + * @author Steve Ebersole */ public class JavassistClassTransformer extends AbstractClassTransformerImpl { private static Log log = LogFactory.getLog( JavassistClassTransformer.class.getName() ); - public JavassistClassTransformer(String[] packages, String[] classes) { - super(packages, classes); + public JavassistClassTransformer(ClassFilter classFilter, org.hibernate.bytecode.util.FieldFilter fieldFilter) { + super( classFilter, fieldFilter ); } protected byte[] doTransform( @@ -75,23 +74,29 @@ return classfileBuffer; } - protected FieldTransformer getFieldTransformer(ClassFile classfile) { + protected FieldTransformer getFieldTransformer(final ClassFile classfile) { if ( alreadyInstrumented( classfile ) ) { return null; } - else { - return new FieldTransformer( - new FieldFilter() { - public boolean handleRead(String desc, String name) { - return true; - } + return new FieldTransformer( + new FieldFilter() { + public boolean handleRead(String desc, String name) { + return fieldFilter.shouldInstrumentField( classfile.getName(), name ); + } - public boolean handleWrite(String desc, String name) { - return true; - } + public boolean handleWrite(String desc, String name) { + return fieldFilter.shouldInstrumentField( classfile.getName(), name ); } - ); - } + + public boolean handleReadAccess(String fieldOwnerClassName, String fieldName) { + return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName ); + } + + public boolean handleWriteAccess(String fieldOwnerClassName, String fieldName) { + return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName ); + } + } + ); } private boolean alreadyInstrumented(ClassFile classfile) { Added: trunk/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/util/BasicClassFilter.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,59 @@ +package org.hibernate.bytecode.util; + +import java.util.Set; +import java.util.HashSet; + +/** + * BasicClassFilter provides class filtering based on a series of packages to + * be included and/or a series of explicit class names to be included. If + * neither is specified, then no restrictions are applied. + * + * @author Steve Ebersole + */ +public class BasicClassFilter implements ClassFilter { + private final String[] includedPackages; + private final Set includedClassNames = new HashSet(); + private final boolean isAllEmpty; + + public BasicClassFilter() { + this( null, null ); + } + + public BasicClassFilter(String[] includedPackages, String[] includedClassNames) { + this.includedPackages = includedPackages; + if ( includedClassNames != null ) { + for ( int i = 0; i < includedClassNames.length; i++ ) { + this.includedClassNames.add( includedClassNames[i] ); + } + } + + isAllEmpty = ( this.includedPackages == null || this.includedPackages.length == 0 ) + && ( this.includedClassNames.isEmpty() ); + } + + public boolean shouldInstrumentClass(String className) { + if ( isAllEmpty ) { + return true; + } + else if ( includedClassNames.contains( className ) ) { + return true; + } + else if ( isInIncludedPackage( className ) ) { + return true; + } + else { + return false; + } + } + + private boolean isInIncludedPackage(String className) { + if ( includedPackages != null ) { + for ( int i = 0; i < includedPackages.length; i++ ) { + if ( className.startsWith( includedPackages[i] ) ) { + return true; + } + } + } + return false; + } +} Added: trunk/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/util/ByteCodeHelper.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,78 @@ +package org.hibernate.bytecode.util; + +import java.io.InputStream; +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.util.zip.ZipInputStream; + +/** + * A helper for reading byte code from various input sources. + * + * @author Steve Ebersole + */ +public class ByteCodeHelper { + private ByteCodeHelper() { + } + + /** + * Reads class byte array info from the given input stream. + * <p/> + * The stream is closed within this method! + * + * @param inputStream + * @return + * @throws IOException + */ + public static byte[] readByteCode(InputStream inputStream) throws IOException { + if ( inputStream == null ) { + throw new IOException( "null input stream" ); + } + + byte[] buffer = new byte[409600]; + byte[] classBytes = new byte[0]; + int r = 0; + + try { + r = inputStream.read( buffer ); + while ( r >= buffer.length ) { + byte[] temp = new byte[ classBytes.length + buffer.length ]; + System.arraycopy( classBytes, 0, temp, 0, classBytes.length ); + System.arraycopy( buffer, 0, temp, classBytes.length, buffer.length ); + classBytes = temp; + } + if ( r != -1 ) { + byte[] temp = new byte[ classBytes.length + r ]; + System.arraycopy( classBytes, 0, temp, 0, classBytes.length ); + System.arraycopy( buffer, 0, temp, classBytes.length, r ); + classBytes = temp; + } + } + finally { + try { + inputStream.close(); + } + catch (IOException ignore) { + // intentionally empty + } + } + + return classBytes; + } + + public static byte[] readByteCode(File file) throws IOException { + return ByteCodeHelper.readByteCode( new FileInputStream( file ) ); + } + + public static byte[] readByteCode(ZipInputStream zip) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + InputStream in = new BufferedInputStream( zip ); + int b; + while ( ( b = in.read() ) != -1 ) { + bout.write( b ); + } + return bout.toByteArray(); + } +} Added: trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassDescriptor.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,30 @@ +package org.hibernate.bytecode.util; + +/** + * Contract describing the information Hibernate needs in terms of instrumenting + * a class, either via ant task or dynamic classloader. + * + * @author Steve Ebersole + */ +public interface ClassDescriptor { + /** + * The name of the class. + * + * @return The class name. + */ + public String getName(); + + /** + * Determine if the class is already instrumented. + * + * @return True if already instrumented; false otherwise. + */ + public boolean isInstrumented(); + + /** + * The bytes making up the class' bytecode. + * + * @return The bytecode bytes. + */ + public byte[] getBytes(); +} Added: trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/util/ClassFilter.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,10 @@ +package org.hibernate.bytecode.util; + +/** + * Used to determine whether a class should be instrumented. + * + * @author Steve Ebersole + */ +public interface ClassFilter { + public boolean shouldInstrumentClass(String className); +} Added: trunk/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/bytecode/util/FieldFilter.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -0,0 +1,29 @@ +package org.hibernate.bytecode.util; + +/** + * Used to determine whether a field reference should be instrumented. + * + * @author Steve Ebersole + */ +public interface FieldFilter { + /** + * Should this field definition be instrumented? + * + * @param className The name of the class currently being processed + * @param fieldName The name of the field being checked. + * @return True if we should instrument this field. + */ + public boolean shouldInstrumentField(String className, String fieldName); + + /** + * Should we instrument *access to* the given field. This differs from + * {@link #shouldInstrumentField} in that here we are talking about a particular usage of + * a field. + * + * @param transformingClassName The class currently being transformed. + * @param fieldOwnerClassName The name of the class owning this field being checked. + * @param fieldName The name of the field being checked. + * @return True if this access should be transformed. + */ + public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName); +} Modified: trunk/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/intercept/FieldInterceptionHelper.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -27,7 +27,7 @@ Class[] definedInterfaces = entityClass.getInterfaces(); for ( int i = 0; i < definedInterfaces.length; i++ ) { if ( "net.sf.cglib.transform.impl.InterceptFieldEnabled".equals( definedInterfaces[i].getName() ) - || "org.hibernate.tool.instrument.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { + || "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { return true; } } @@ -48,7 +48,7 @@ // we have a CGLIB enhanced entity return CGLIBHelper.extractFieldInterceptor( entity ); } - else if ( "org.hibernate.tool.instrument.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { + else if ( "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { // we have a Javassist enhanced entity return JavassistHelper.extractFieldInterceptor( entity ); } @@ -68,7 +68,7 @@ // we have a CGLIB enhanced entity return CGLIBHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session ); } - else if ( "org.hibernate.tool.instrument.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { + else if ( "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) { // we have a Javassist enhanced entity return JavassistHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session ); } Modified: trunk/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/intercept/javassist/FieldInterceptorImpl.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -4,7 +4,7 @@ import java.io.Serializable; import java.util.Set; -import org.hibernate.tool.instrument.javassist.FieldHandler; +import org.hibernate.bytecode.javassist.FieldHandler; import org.hibernate.intercept.AbstractFieldInterceptor; import org.hibernate.engine.SessionImplementor; import org.hibernate.proxy.HibernateProxy; @@ -145,10 +145,10 @@ public String toString() { return "FieldInterceptorImpl(" + - "entityName=" + getEntityName() + - ",dirty=" + isDirty() + - ",uninitializedFields=" + getUninitializedFields() + - ')'; + "entityName=" + getEntityName() + + ",dirty=" + isDirty() + + ",uninitializedFields=" + getUninitializedFields() + + ')'; } } \ No newline at end of file Modified: trunk/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/intercept/javassist/JavassistHelper.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -2,7 +2,7 @@ import org.hibernate.intercept.FieldInterceptor; import org.hibernate.engine.SessionImplementor; -import org.hibernate.tool.instrument.javassist.FieldHandled; +import org.hibernate.bytecode.javassist.FieldHandled; import java.util.Set; Modified: trunk/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java 2006-08-03 17:16:34 UTC (rev 10205) +++ trunk/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java 2006-08-03 19:59:42 UTC (rev 10206) @@ -1,16 +1,18 @@ //$Id$ package org.hibernate.tool.instrument.cglib; -import java.util.Arrays; +import org.hibernate.bytecode.util.BasicClassFilter; +import org.hibernate.bytecode.util.ClassDescriptor; +import org.hibernate.bytecode.cglib.BytecodeProviderImpl; +import org.hibernate.bytecode.ClassTransformer; +import org.hibernate.tool.instrument.BasicInstrumentationTask; +import org.objectweb.asm.ClassReader; -import net.sf.cglib.transform.AbstractTransformTask; -import net.sf.cglib.transform.ClassTransformer; +import java.io.ByteArrayInputStream; + +import net.sf.cglib.core.ClassNameReader; import net.sf.cglib.transform.impl.InterceptFieldEnabled; -import net.sf.cglib.transform.impl.InterceptFieldFilter; -import net.sf.cglib.transform.impl.InterceptFieldTransformer; -import org.objectweb.asm.Type; - /** * An Ant task for instrumenting persistent classes in order to enable * field-level interception using CGLIB. @@ -34,36 +36,71 @@ * </pre> * where the nested ANT fileset includes the class you would like to have * instrumented. + * <p/> + * Optionally you can chose to enable "Extended Instrumentation" if desired + * by specifying the extended attriubute on the task:<pre> + * <instrument verbose="true" extended="true"> + * ... + * </instrument> + * </pre> + * See the Hibernate manual regarding this option. * * @author Gavin King + * @author Steve Ebersole */ -public class InstrumentTask extends AbstractTransformTask { +public class InstrumentTask extends BasicInstrumentationTask { - /** - * Override the {@link AbstractTransformTask#getClassTransformer} method - * in order to define field access interception transformation should occur. - */ - protected ClassTransformer getClassTransformer(final String[] classInfo) { - if ( Arrays.asList( classInfo ).contains( InterceptFieldEnabled.class.getName() ) ) { - // The class is already instrumented, so skip this step + private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter(); + + private final BytecodeProviderImpl provider = new BytecodeProviderImpl(); + + + protected ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception { + return new CustomClassDescriptor( byecode ); + } + + protected ClassTransformer getClassTransformer(ClassDescriptor descriptor) { + if ( descriptor.isInstrumented() ) { + logger.verbose( "class [" + descriptor.getName() + "] already instrumented" ); return null; } else { + return provider.getTr... [truncated message content] |
From: <hib...@li...> - 2006-08-03 17:16:49
|
Author: AnthonyHib Date: 2006-08-03 13:16:34 -0400 (Thu, 03 Aug 2006) New Revision: 10205 Modified: trunk/Hibernate3/doc/reference/fr/master.xml trunk/Hibernate3/doc/reference/fr/modules/basic_mapping.xml trunk/Hibernate3/doc/reference/fr/modules/batch.xml trunk/Hibernate3/doc/reference/fr/modules/configuration.xml trunk/Hibernate3/doc/reference/fr/modules/events.xml trunk/Hibernate3/doc/reference/fr/modules/query_hql.xml trunk/Hibernate3/doc/reference/fr/modules/query_sql.xml trunk/Hibernate3/doc/reference/fr/modules/session_api.xml trunk/Hibernate3/doc/reference/fr/modules/transactions.xml trunk/Hibernate3/doc/reference/fr/modules/tutorial.xml Log: update for 3.2 doc compliance Modified: trunk/Hibernate3/doc/reference/fr/master.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/master.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/master.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -33,7 +33,7 @@ <bookinfo> <title>HIBERNATE - Persistance relationnelle en Java standard</title> <subtitle>Documentation de rrence d'Hibernate</subtitle> - <releaseinfo>3.1final</releaseinfo> + <releaseinfo>3.2final</releaseinfo> </bookinfo> <toc/> Modified: trunk/Hibernate3/doc/reference/fr/modules/basic_mapping.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/basic_mapping.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/basic_mapping.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -86,7 +86,8 @@ qui agissent sur le sch de base de donn exportar l'outil de gration de sch. (Par exemple l'attribut <literal>not-null</literal>.) </para> - <sect2 id="mapping-declaration-doctype" revision="2"> + + <sect2 id="mapping-declaration-doctype" revision="3"> <title>Doctype</title> <para> Tous les mappings XML devraient utiliser le doctype indiqu @@ -96,6 +97,56 @@ des recherches de la DTD sur Internet, vfiez votre daration de DTD par rapport au contenu de votre classpath. </para> + + <sect3 id="mapping-declaration-entity-resolution"> + <title>EntityResolver</title> + <para> + Comme citrdemment, Hibernate tentera de trouver les DTDs d'abord dans son classpath. Il + rsit aire cela en utilisant une implntation particuli de <literal>org.xml.sax.EntityResolver</literal> + avec le SAXReader qu'il utilise pour lire les fichiers xml. Cet <literal>EntityResolver</literal> particulier + reconnait deux espaces de nommage systemId diffnts. + </para> + <itemizedlist> + <listitem> + <para> + un <literal>espace de nommage hibernate</literal> est reconnu dqu'un systemId commence par + <literal>http://hibernate.sourceforge.net/</literal>; alors ces entitsont rlues via le + classloader qui a charges classes Hibernate. + </para> + </listitem> + <listitem> + <para> + un <literal>espace de nommage utilisateur</literal> est reconnu dqu'un systemId utilise + un protocol URL <literal>classpath://</literal>. Le rlveur tentera de rudre ces entit+ via (1) le classloader du contexte du thread courant et (2) le classloader qui a charg les classes Hibernate. + </para> + </listitem> + </itemizedlist> + <para> + Un exemple d'utilisation de l'espace de nommage utilisateur: + </para> + <programlisting><![CDATA[<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [ + <!ENTITY types SYSTEM "classpath://your/domain/types.xml"> +]> + +<hibernate-mapping package="your.domain"> + <class name="MyEntity"> + <id name="id" type="my-custom-id-type"> + ... + </id> + <class> + &types; +</hibernate-mapping>]]></programlisting> + <para> + Oteral>types.xml</literal> est une ressource dans le package <literal>your.domain</literal> + et qui contient un <xref linkend="mapping-types-custom">typedef</xref> particulier. + </para> + </sect3> + </sect2> <sect2 id="mapping-declaration-mapping" revision="3"> <title>hibernate-mapping</title> @@ -1103,7 +1154,7 @@ utilisent des identifiants assignou des clefs compos !</emphasis> </para> </sect2> - <sect2 id="mapping-declaration-timestamp" revision="3" > + <sect2 id="mapping-declaration-timestamp" revision="4" > <title>timestamp (optionnel)</title> <para> L'ment optionnel <literal><timestamp></literal> indique que la table contient des donn @@ -1179,7 +1230,9 @@ </programlistingco> <para> Notez que <literal><timestamp></literal> est ivalent - <literal><version type="timestamp"></literal>. + <literal><version type="timestamp"></literal> et + <literal><timestamp source="db"></literal> ivaut <literal><version type="dbtimestamp"></literal>. </para> </sect2> <sect2 id="mapping-declaration-property" revision="4"> Modified: trunk/Hibernate3/doc/reference/fr/modules/batch.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/batch.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/batch.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -150,7 +150,7 @@ </sect1> - <sect1 id="batch-direct" revision="2"> + <sect1 id="batch-direct" revision="3"> <title>Options de style DML</title> <para> @@ -218,10 +218,34 @@ session.close();]]></programlisting> <para> - Pour exter un <literal>DELETE</literal> HQL, utilisez la m mode - <literal>Query.executeUpdate()</literal> : + Par dut, les statements HQL <literal>UPDATE</literal>, n'affectent pas la valeur des propris + <xref linkend="mapping-declaration-version">version</xref> ou + <xref linkend="mapping-declaration-timestamp">timestamp</xref> + pour les entitaffect; ceci est compatible avec la spec EJB3. Toutefois, + vous pouvez forcer Hibernate ettre our les valeurs des propris + <literal>version</literal> ou <literal>timestamp</literal> en utilisant le <literal>versioned update</literal>. + Pour se faire, ajoutez le mot clliteral>VERSIONED</literal> aprle mot clliteral>UPDATE</literal>. </para> +<programlisting><![CDATA[Session session = sessionFactory.openSession(); +Transaction tx = session.beginTransaction(); +String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName"; +int updatedEntities = s.createQuery( hqlUpdate ) + .setString( "newName", newName ) + .setString( "oldName", oldName ) + .executeUpdate(); +tx.commit(); +session.close();]]></programlisting> + + <para> + Notez que les types personnalis(<literal>org.hibernate.usertype.UserVersionType</literal>) + ne sont pas supporten conjonction avec le statement <literal>update versioned</literal> statement. + </para> + + <para> + Pour exter un HQL <literal>DELETE</literal>, utilisez la m mode<literal>Query.executeUpdate()</literal>: + </para> + <programlisting><![CDATA[Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Modified: trunk/Hibernate3/doc/reference/fr/modules/configuration.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/configuration.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/configuration.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -938,7 +938,7 @@ </tgroup> </table> - <table frame="topbot" id="configuration-misc-properties" revision="9"> + <table frame="topbot" id="configuration-misc-properties" revision="10"> <title>Propris diverses</title> <tgroup cols="2"> <colspec colname="c1" colwidth="1*"/> @@ -962,7 +962,7 @@ <para> <emphasis role="strong">eg.</emphasis> <literal>jta</literal> | <literal>thread</literal> | - <literal>custom.Class</literal> + <literal>managed</literal> | <literal>custom.Class</literal> </para> </entry> </row> Modified: trunk/Hibernate3/doc/reference/fr/modules/events.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/events.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/events.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -8,7 +8,7 @@ fonctionnalitgriques, et d'extensions de fonctionnalitd'Hibernate. </para> - <sect1 id="objectstate-interceptors" revision="2"> + <sect1 id="objectstate-interceptors" revision="3"> <title>Intercepteurs</title> <para> @@ -115,21 +115,32 @@ }]]></programlisting> <para> - L'intercepteur doit e spfiuand une session est cr. + Il y a deux types d'intercepteurs: li la <literal>Session</literal> et + li la <literal>SessionFactory</literal>. </para> + <para> + Un intercepteur li la <literal>Session</literal> est dni + lorsqu'une session est ouverte via l'invocation des modes surcharg SessionFactory.openSession() + acceptant un <literal>Interceptor</literal> (comme argument). + </para> <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting> <para> - Vous pouvez aussi mettre un intercepteur au niveau global, en utilisant l'objet <literal>Configuration</literal>. - Dans ce cas, l'intercepteur doit e "threadsafe". + Un intercepteur li <literal>SessionFactory</literal> est dni avec l'objet <literal>Configuration</literal> + avant la construction de la <literal>SessionFactory</literal>. Dans ce cas, les intercepteurs fournis seront + appliquoutes les sessions ouvertes pour cette <literal>SessionFactory</literal>; ceci est vrai + oins que la session ne soit ouverte en spfiant l'intercepteur tiliser. + Les intercepteurs lia <literal>SessionFactory</literal> doivent e thread safe, faire attention + e pas stocker des ts spfiques de la session puisque plusieurs sessions peuvent utiliser + l'intercepteur de mani concurrente. </para> <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting> </sect1> - <sect1 id="objectstate-events" revision="3"> + <sect1 id="objectstate-events" revision="4"> <title>Syst d'nements</title> <para> Modified: trunk/Hibernate3/doc/reference/fr/modules/query_hql.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/query_hql.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/query_hql.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -80,7 +80,7 @@ </sect1> - <sect1 id="queryhql-joins" revision="1"> + <sect1 id="queryhql-joins" revision="2"> <title>Associations et jointures</title> <para> @@ -171,8 +171,9 @@ Notez que la construction de <literal>fetch</literal> ne peut pas e utilisdans les requs appel par <literal>scroll()</literal> ou <literal>iterate()</literal>. <literal>fetch</literal> ne devrait pas non plus e utilisvec <literal>setMaxResults()</literal> ou - <literal>setFirstResult()</literal>. <literal>fetch</literal> ne peut pas non plus e utilisvec une - condition <literal>with</literal> ad hoc. Il est + <literal>setFirstResult()</literal>, ces options nt bas sur le nombre de rltats qui contient + gralement des doublons dque des collections sont charg. + <literal>fetch</literal> ne peut pas non plus e utilisvec une condition <literal>with</literal> ad hoc. Il est possible de cr un produit carten par jointure en rpnt plus d'une collection dans une requ, donc faites attention dans ce cas. Rpr par jointure de multiples collections donne aussi parfois des rltats inattendus pour des mappings de bag, donc soyez prudent lorsque vous formulez vos requs dans de tels cas. Modified: trunk/Hibernate3/doc/reference/fr/modules/query_sql.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/query_sql.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/query_sql.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -13,7 +13,7 @@ <para>Hibernate3 vous permet de spfier du SQL it a main (incluant les procres stock) pour toutes les options de crion, mise our, suppression et chargement.</para> - <sect1 id="querysql-creating" revision="3"> + <sect1 id="querysql-creating" revision="4"> <title>Utiliser une <literal>SQLQuery</literal></title> <para>L'extion des requs en SQL natif est contr par l'interface <literal>SQLQuery</literal>, @@ -21,224 +21,369 @@ Dans des cas extrment simples, nous pouvons utiliser la forme suivante : </para> - <programlisting>List cats = sess.createSQLQuery("select * from cats") - .addEntity(Cat.class) - .list();</programlisting> + <sect2> + <title>Requs scalaires</title> - <para>Cette requ a spfi</para> + <para>La requ SQL la plus basique permet de rpr une liste de (valeurs) scalaires.</para> - <itemizedlist> - <listitem> - <para>la requ SQL</para> - </listitem> + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list(); +sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list(); +]]></programlisting> - <listitem> - <para>l'entitetournpar la requ</para> - </listitem> - </itemizedlist> + <para>Ces deux requs retourneront un tableau d'objets (Object[]) avec + les valeurs scalaires de chacune des colonnes de la table CATS. + Hibernate utilisera le ResultSetMetadata pour dire l'ordre et le type + des valeurs scalaires retourn.</para> - <para> - Ici, les noms de colonne des rltats sont suppose les ms que les noms de colonne spfidans le - document de mapping. Cela peut e probltique pour des requs SQL qui joignent de multiple tables, puisque - les ms noms de colonne peuvent apparae dans plus d'une table. La forme suivante n'est pas vulnble a - duplication des noms de colonne : - </para> + <para>Pour ter l'overhead li <literal>ResultSetMetadata</literal> ou simplement pour + e plus explicite dans ce qui est retournvous pouvez utiliser <literal>addScalar()</literal>.</para> - <programlisting>List cats = sess.createSQLQuery("select {cat.*} from cats cat") - .addEntity("cat", Cat.class) - .list();</programlisting> + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS") + .addScalar("ID", Hibernate.LONG) + .addScalar("NAME", Hibernate.STRING) + .addScalar("BIRTHDATE", Hibernate.DATE) +]]></programlisting> - <para>Cette requ a spfi</para> + <para>Cette requ spfie:</para> - <itemizedlist> - <listitem> - <para>la requ SQL, avec un parame fictif pour Hibernate pour injecter les alias de colonne</para> - </listitem> + <itemizedlist> + <listitem> + <para>la cha de caract SQL</para> + </listitem> - <listitem> - <para>l'entitetournpar la requ, et son alias de table SQL</para> - </listitem> - </itemizedlist> + <listitem> + <para>les colonnes et les types retourn/para> + </listitem> + </itemizedlist> - <para> - La mode <literal>addEntity()</literal> associe l'alias de la table SQL - avec la classe de l'entitetourn et drmine la forme de l'ensemble des rltats de la requ. - </para> + <para>Cela retournera toujours un tableau d'objets, mais sans utiliser le + <literal>ResultSetMetdata</literal>, mais rpra explicitement les colonnes + ID, NAME and BIRTHDATE column nt de respectivement de type Long, String et Short, + depuis le resultset sous jacent. Cela signifie aussi que seules ces colonnes seront + retourn m si la requ utilise <literal>*</literal> + et aurait pu retourner plus que les trois colonnes list.</para> - <para> - La mode <literal>addJoin()</literal> peut e utilispour charger des associations vers d'autres - entitet collections. - </para> + <para>Il est possible de ne pas dnir l'information sur le type pour toutes ou partie + des calaires.</para> - <programlisting>List cats = sess.createSQLQuery( - "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" - ) - .addEntity("cat", Cat.class) - .addJoin("kitten", "cat.kittens") - .list();</programlisting> + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS") + .addScalar("ID", Hibernate.LONG) + .addScalar("NAME") + .addScalar("BIRTHDATE") +]]></programlisting> - <para> - Une requ SQL native pourrait retourner une simple valeur scalaire ou une combinaison de scalaires et d'entit - </para> + <para>Il s'agit essentiellement de la m requ que prdemment, mais + le <literal>ResultSetMetaData</literal> est utilisour dder des types de NAME + et BIRTHDATE alors que le type de ID est explicitement spfi/para> - <programlisting>Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat") - .addScalar("maxWeight", Hibernate.DOUBLE); - .uniqueResult();</programlisting> + <para>Les java.sql.Types retournpar le ResultSetMetaData sont mappaux type Hibernate + via le Dialect. Si un type spfique n'est pas mappu est mapp un type non souhaitil + est possible de personnaliser en invoquant <literal>registerHibernateType</literal> dans + le Dialect.</para> + </sect2> - <para>Vous pouvez alternativement dire les informations de mapping des rltats dans vos fichiers hbm - et les utiliser pour vos requs.</para> + <sect2> + <title>Requs d'entit/title> - <programlisting>List cats = sess.createSQLQuery( - "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" - ) - .setResultSetMapping("catAndKitten") - .list();</programlisting> - </sect1> + <para>Les requs prdentes ne retournaient que des valeurs scalaires, + retournant basiquement que les valeurs brutes du resultset. Ce qui suit montre + comment rpr des entitdepuis une requ native SQL, gr <literal>addEntity()</literal>.</para> - <sect1 id="querysql-aliasreferences"> - <title>Alias et rrences de propri</title> + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); +sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class); +]]></programlisting> - <para> - La notation <literal>{cat.*}</literal> utilisau-dessus est un raccourci pour "toutes les propris". - Alternativement, vous pouvez lister explicitement les colonnes, mais m ce cas que nous laissons ibernate - injecte des alias de colonne SQL pour chaque propri. Le remplat pour un alias de colonne - est juste le nom de la propri qualifiar l'alias de la table. - Dans l'exemple suivant, nous rpns des <literal>Cat</literal>s artir d'une table diffnte - (<literal>cat_log</literal>) de celle dardans les m-donn de mapping. - Notez que nous pouvons m utiliser les alias de propri dans la clause "where" si nous le souhaitons. - </para> + <para>Cette requ spfie:</para> - <para> - La syntaxe <literal>{}</literal> <emphasis>n'est pas</emphasis> requise pour le requs nomm. Voir - <xref linkend="querysql-namedqueries" />. - </para> + <itemizedlist> + <listitem> + <para>La cha de caract de requ SQL</para> + </listitem> - <programlisting>String sql = "select cat.originalId as {cat.id}, " + - "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " + - "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " + - "from cat_log cat where {cat.mate} = :catId" + <listitem> + <para>L'entitetournpar la requ</para> + </listitem> + </itemizedlist> + <para>Avec Cat mappomme classe avec les colonnes ID, NAME + et BIRTHDATE, les requs prdentes retournent toutes deux une liste + oque ment est une entitat.</para> + + <para>Si l'entitst mappavec un <literal>many-to-one</literal> vers + une autre entitil est requis de retourner aussi cette entitn extant + la requ native, sinon une erreur "column not found" spfique a base de + donn sera soulev Les colonnes additionnelles seront automatiquement + retourn en utilisant la notation *, mais nous prrons e explicites + comme dans l'exemple suivant avec le <literal>many-to-one</literal> vers + <literal>Dog</literal>:</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class); +]]></programlisting> + + <para>Ceci permet at.getDog() de fonctionner normalement.</para> + </sect2> + + <sect2> + <title>Gr les associations et collections</title> + + <para>Il est possible de charger agressivement <literal>Dog</literal> pour + ter le chargement de proxy qui signifie aller retour supplntaire vers + la base de donn. Ceci est faisable via la mode <literal>addJoin()</literal>, + qui vous permet de joindre une association ou collection.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID") + .addEntity("cat", Cat.class) + .addJoin("cat.dog"); +]]></programlisting> + + <para>Dans cet exemple, les <literal>Cat</literal> retournauront leur + propri <literal>dog</literal> entiment initialis sans aucun aller/retour + supplntaire vers la base de donn. Notez que nous avons ajoutn alias + ("cat") pour e capable de spfier la propri cible de la jointure. + Il est possible de faire la m jointure aggressive pour les collections, e.g. si le + <literal>Cat</literal> a un one-to-many vers <literal>Dog</literal>.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID") + .addEntity("cat", Cat.class) + .addJoin("cat.dogs"); +]]></programlisting> + + <p>Nous arrivons aux limites de ce qui est possible avec les requs natives + sans les modifier pour les rendre utilisables par Hibernate; les probls + surviennent lorsque nous essayons de retourner des entitdu m type ou + lorsque les alias/colonnes par dut ne sont plus suffisants..</p> + </sect2> + + <sect2> + <title>Retour d'entitmultiples</title> + + <para>Jusqu'rnt, les colonnes du resultset sont suppos e les ms + que les colonnes spfi dans les fichiers de mapping. Ceci peut + e probltique pour les requs SQL qui effectuent de multiples + jointures vers diffntes tables, puisque les ms colonnes peuvent + apparae dans plus d'une table.</para> + + <para>L'injection d'alias de colonne est requis pour la requ suivante + (qui risque de ne pas fonctionner):</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class) +]]></programlisting> + + <para>Le but de cette requ est de retourner deux instances de Cat par ligne, + un chat et sa m. Cela ouera puisqu'il y a conflit de nom puisqu'ils sont + mappau m nom de colonne et que sur certaines base de donn, les alias + de colonnes retournseront plute la forme + "c.ID", "c.NAME", etc. qui ne sont pas ux aux colonnes spfi dans les + mappings ("ID" and "NAME").</para> + + <para>La forme suivante n'est pas vulnble a duplication des noms de colonnes:</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class) +]]></programlisting> + + <para>Cette requ spfie:</para> + + <itemizedlist> + <listitem> + <para>la requ SQL, avec des rptacles pour qu'Hibernate injecte les alias de colonnes</para> + </listitem> + + <listitem> + <para>les entitretournpar la requ</para> + </listitem> + </itemizedlist> + + <para>Les notations {cat.*} et {mother.*} utilis sont un ivalent toutes les propris'. + Alternativement, vous pouvez lister les colonnes explicitement, mais m pour ce cas, nous + laissons Hibernate injecter les alias de colonne pour chaque propri. + Le rptable pour un alias de colonne est simplement le nom de la propri + qualifiar l'alias de la table. Dans l'exemple suivant, nous rpns + les chats et leur m depuis une table diffntes (cat_log) de celle dar+ dans les mappings. Notez que nous pouvons aussi utiliser les alias de propri + dans la clause where si nous le voulons.</para> + + <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + + "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " + + "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID"; + List loggedCats = sess.createSQLQuery(sql) - .addEntity("cat", Cat.class) - .setLong("catId", catId) - .list();</programlisting> + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class).list() +]]></programlisting> + <sect3 id="querysql-aliasreferences" revision="2"> + <title>Rrences d'alias et de propri</title> - <para> - <emphasis>noter :</emphasis> si vous listez chaque propri explicitement, vous devez inclure - toutes les propris de la classe <emphasis>et ses sous-classes</emphasis> ! - </para> + <para>Pour la plupart des cas prdents, l'injection d'alias est requis, + mais pour les requs relatives es mappings plus complexes, comme + les propris composite, les discriminants d'htage, les collections etc., il + y a des alias spfiques tiliser pour permettre ibernate l'injection + des bons alias.</para> - <para> - La table suivante montre les diffntes possibilitd'utilisation de l'injection d'alias. noter : les noms - des alias dans le rltat sont des exemples, chaque alias aura un nom unique et probablement diffnt lors de l'utilisation. - </para> + <para>Le tableau suivant montre les diverses possiblitd'utilisation + d'injection d'alias. Note: les noms d'alias dans le rltat sont des + exemples, chaque alias aura un nom unique et probablement diffnt lorsqu'ils + seront utilis</para> - <table frame="topbot" id="aliasinjection-summary"> - <title>Noms d'injection d'alias</title> + <table frame="topbot" id="aliasinjection-summary"> + <title>Nom d'injection d'alias</title> - <tgroup cols="4"> - <colspec colwidth="1*" /> + <tgroup cols="3"> + <colspec colwidth="1*" /> - <colspec colwidth="1*" /> + <colspec colwidth="1*" /> - <colspec colwidth="2.5*" /> + <colspec colwidth="2.5*" /> - <thead> - <row> - <entry>Description</entry> + <thead> + <row> + <entry>Description</entry> - <entry>Syntaxe</entry> + <entry>Syntaxe</entry> - <entry>Exemple</entry> - </row> - </thead> + <entry>Exemple</entry> + </row> + </thead> - <tbody> - <row> - <entry>Une simple propri</entry> + <tbody> + <row> + <entry>Une propri simple</entry> - <entry><literal>{[aliasname].[propertyname]}</literal></entry> + <entry><literal>{[aliasname].[propertyname]</literal></entry> - <entry><literal>A_NAME as {item.name}</literal></entry> - </row> + <entry><literal>A_NAME as {item.name}</literal></entry> + </row> - <row> - <entry>Une propri compos/entry> + <row> + <entry>Une propri composite</entry> - <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry> + <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry> - <entry><literal>CURRENCY as {item.amount.currency}, VALUE as - {item.amount.value}</literal></entry> - </row> + <entry><literal>CURRENCY as {item.amount.currency}, VALUE as + {item.amount.value}</literal></entry> + </row> - <row> - <entry>Discriminant d'une entitentry> + <row> + <entry>Discriminateur d'une entitentry> - <entry><literal>{[aliasname].class}</literal></entry> + <entry><literal>{[aliasname].class}</literal></entry> - <entry><literal>DISC as {item.class}</literal></entry> - </row> + <entry><literal>DISC as {item.class}</literal></entry> + </row> - <row> - <entry>Toutes les propris d'une entitentry> + <row> + <entry>Toutes les propris d'une entitentry> - <entry><literal>{[aliasname].*}</literal></entry> + <entry><literal>{[aliasname].*}</literal></entry> - <entry><literal>{item.*}</literal></entry> - </row> + <entry><literal>{item.*}</literal></entry> + </row> - <row> - <entry>Une clef de collection</entry> + <row> + <entry>La cl'une collection</entry> - <entry><literal>{[aliasname].key}</literal></entry> + <entry><literal>{[aliasname].key}</literal></entry> - <entry><literal>ORGID as {coll.key}</literal></entry> - </row> + <entry><literal>ORGID as {coll.key}</literal></entry> + </row> - <row> - <entry>L'identifiant d'une collection</entry> + <row> + <entry>L'id d'une collection</entry> - <entry><literal>{[aliasname].id}</literal></entry> + <entry><literal>{[aliasname].id}</literal></entry> - <entry><literal>EMPID as {coll.id}</literal></entry> - </row> + <entry><literal>EMPID as {coll.id}</literal></entry> + </row> - <row> - <entry>L'ment d'une collection</entry> + <row> + <entry>L'ment d'une collection</entry> - <entry><literal>{[aliasname].element}</literal></entry> + <entry><literal>{[aliasname].element}</literal></entry> - <entry><literal>XID as {coll.element}</literal></entry> + <entry><literal>XID as {coll.element}</literal></entry> + </row> - <entry></entry> - </row> + <row> + <entry>Propri d'un ment de collection</entry> - <row> - <entry>Propri de l'ment dans la collection</entry> + <entry><literal>{[aliasname].element.[propertyname]}</literal></entry> - <entry><literal>{[aliasname].element.[propertyname]}</literal></entry> + <entry><literal>NAME as {coll.element.name}</literal></entry> + </row> - <entry><literal>NAME as {coll.element.name}</literal></entry> - </row> + <row> + <entry>Toutes les propris d'un ment de collection</entry> - <row> - <entry>Toutes les propris de l'ment dans la collection</entry> + <entry><literal>{[aliasname].element.*}</literal></entry> - <entry><literal>{[aliasname].element.*}</literal></entry> + <entry><literal>{coll.element.*}</literal></entry> + </row> - <entry><literal>{coll.element.*}</literal></entry> - </row> + <row> + <entry>Toutes les propris d'une collection</entry> - <row> - <entry>Toutes les propris de la collection</entry> + <entry><literal>{[aliasname].*}</literal></entry> - <entry><literal>{[aliasname].*}</literal></entry> + <entry><literal>{coll.*}</literal></entry> + </row> + </tbody> + </tgroup> + </table> + </sect3> + </sect2> + + <sect2> + <title>Retour d'objet n'nt pas des entit/title> - <entry><literal>{coll.*}</literal></entry> - </row> - </tbody> - </tgroup> - </table> + <para>Il est possible d'appliquer un ResultTransformer ne requ native SQL. Ce qui permet, par exemple, de + retourner des entitnon ges.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") + .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting> + + <para>Cette requ spfie:</para> + + <itemizedlist> + <listitem> + <para>une requ SQL</para> + </listitem> + + <listitem> + <para>un transformateur de rltat</para> + </listitem> + </itemizedlist> + + <para> + La requ prdente retournera une liste de <literal>CatDTO</literal> qui auront instanci+ et dans lesquelles les valeurs de NAME et BIRTHNAME auront inject dans les propris ou champs + correspondants. + </para> + </sect2> + + <sect2> + <title>Gr l'htage</title> + + <para>Les requs natives SQL pour les entitprenant part n htage + doivent inclure toutes les propris de la classe de base et de toutes + ses sous classes.</para> + </sect2> + + <sect2> + <title>Parames</title> + + <para>Les requs natives SQL supportent aussi les parames nomm</para> + + <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class); +List pusList = query.setString(0, "Pus%").list(); + +query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class); +List pusList = query.setString("name", "Pus%").list(); ]]></programlisting> + </sect2> + </sect1> <sect1 id="querysql-namedqueries" revision="3"> Modified: trunk/Hibernate3/doc/reference/fr/modules/session_api.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/session_api.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/session_api.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -223,7 +223,7 @@ objets. </para> - <sect2 id="objectstate-querying-executing"> + <sect2 id="objectstate-querying-executing" revision="1"> <title>Extion de requs</title> <para> @@ -251,8 +251,11 @@ Cat mother = (Cat) session.createQuery( "select cat.mother from Cat as cat where cat = ?") .setEntity(0, izi) - .uniqueResult();]]></programlisting> + .uniqueResult(); +Query mothersWithKittens = (Cat) session.createQuery( + "select mother from Cat as mother left join fetch mother.kittens"); +Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting> <para> Une requ est gralement exten invoquant <literal>list()</literal>, le rltat de la requ sera chargcomplment dans une collection en mire. @@ -447,7 +450,7 @@ </sect3> - <sect3 id="objectstate-querying-executing-named"> + <sect3 id="objectstate-querying-executing-named" revision="1"> <title>Externaliser des requs nomm</title> <para> @@ -476,6 +479,15 @@ utilisvous pouvez aussi dnir des requs SQL nativez dans les m-donn, ou migrer des requs existantes vers Hibernate en les plat dans les fichiers de mapping. </para> + + <para> + Notez aussi que la daration d'une requ dans un ment <literal><hibernate-mapping></literal> + nssite un nom globalement unique pour la requ, alors que la daration d'une requ + dans une ment <literal><class></literal> est rendue unique de mani automatique par + la mise en prxe du nom entiment de la classe, par exemple + <literal>eg.Cat.ByNameAndMaximumWeight</literal>. + </para> + </sect3> Modified: trunk/Hibernate3/doc/reference/fr/modules/transactions.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/transactions.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/transactions.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -482,7 +482,7 @@ </sect2> - <sect2 id="transactions-demarcation-jta" revision="2"> + <sect2 id="transactions-demarcation-jta" revision="3"> <title>Utilisation de JTA</title> <para>Si votre couche de persistance s'exte dans un serveur d'application (par exemple, derri un EJB @@ -514,19 +514,26 @@ sess.close(); }]]></programlisting> - <para>Ou encore, avec la gestion automatique de contexte:</para> - + <para> + Si vous souhaitez utiliser une <literal>Session</literal> coupla transaction, c'est ire, utiliser + la fonctionnalitliteral>getCurrentSession()</literal> pour la propagation facile du contexte, + vous devrez utiliser l'API JTA <literal>UserTransaction</literal> directement: + </para> <programlisting><![CDATA[// BMT idiom with getCurrentSession() try { - factory.getCurrentSession().beginTransaction(); + UserTransaction tx = (UserTransaction)new InitialContext() + .lookup("java:comp/UserTransaction"); - // do some work - ... + tx.begin(); - factory.getCurrentSession().getTransaction().commit(); + // Do some work on Session bound to transaction + factory.getCurrentSession().load(...); + factory.getCurrentSession().persist(...); + + tx.commit(); } catch (RuntimeException e) { - factory.getCurrentSession().getTransaction().rollback(); + tx.rollback(); throw e; // or display error message }]]></programlisting> Modified: trunk/Hibernate3/doc/reference/fr/modules/tutorial.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/tutorial.xml 2006-08-03 17:07:28 UTC (rev 10204) +++ trunk/Hibernate3/doc/reference/fr/modules/tutorial.xml 2006-08-03 17:16:34 UTC (rev 10205) @@ -26,7 +26,7 @@ </sect1> - <sect1 id="tutorial-firstapp" revision="1"> + <sect1 id="tutorial-firstapp" revision="2"> <title>Partie 1 - Premi application Hibernate</title> <para> @@ -339,7 +339,7 @@ </sect2> - <sect2 id="tutorial-firstapp-configuration" revision="1"> + <sect2 id="tutorial-firstapp-configuration" revision="2"> <title>Configuration d'Hibernate</title> <para> @@ -353,7 +353,7 @@ <para> Cr un rrtoire appelliteral>data</literal> a racine du rrtoire de dloppement - c'est lue HSQL DB stockera ses fichiers de donn. Drrez maintenant votre base de donn - en extant <literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal> dans votre rrtoire de travail. + en extant <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal> dans votre rrtoire de donn. Vous observez qu'elle drre et ouvre une socket TCP/IP, c'est lue notre application se connectera plus tard. Si vous souhaitez drrez artir d'une nouvelle base de donn pour ce tutoriel (faites <literal>CTRL + C</literal> dans la fene the window), effacez @@ -868,7 +868,7 @@ </sect2> - <sect2 id="tutorial-associations-unidirset" revision="2"> + <sect2 id="tutorial-associations-unidirset" revision="3"> <title>Une association unidirectionnelle bassur Set</title> <para> @@ -920,7 +920,7 @@ <set name="events" table="PERSON_EVENT"> <key column="PERSON_ID"/> - <many-to-many column="EVENT_ID" class="Event"/> + <many-to-many column="EVENT_ID" class="events.Event"/> </set> </class>]]></programlisting> @@ -957,7 +957,7 @@ </sect2> - <sect2 id="tutorial-associations-working" revision="1"> + <sect2 id="tutorial-associations-working" revision="2"> <title>Travailler avec l'association</title> <para> @@ -1037,6 +1037,14 @@ (il se peut que vous ayez besoin de modifier quelques unes des modes prdentes pour retourner cet identifiant). </para> + + <para> + Cela n'a pas grand intt dans notre situation, mais c'est un concept important qu'il vous faut concevoir + dans votre application. Pour le moment, complz cet excercice en ajoutant une nouvelle + action a mode principale de l'<literal>EventManager</literal> et invoquez la depuis la ligne de commande. + Si vous avez besoin des identifiants d'un client et d'un nement - la mode <literal>save()</literal> + vous les retourne (vous devrez peut e modifier certaines modes prdentes pour retourner ces identifiants): + </para> <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) { Long eventId = mgr.createAndStoreEvent("My Event", new Date()); @@ -1045,15 +1053,6 @@ System.out.println("Added person " + personId + " to event " + eventId);]]></programlisting> <para> - Ce n'est pas trutile dans notre situation actuelle, mais c'est un concept important - que vous pouvez mettre dans votre propre application. - Pour le moment, complz cet exercice en ajoutant une nouvelle action a mode - principale des <literal>EventManager</literal>s et appelez la artir de la ligne de - commande. Si vous avez besoin des identifiants d'une personne et d'un nement - la - mode <literal>save()</literal> les retourne. - </para> - - <para> C'it un exemple d'une association entre deux classes de m importance, deux entit Comme mentionnlus til y a d'autres classes et d'autres types dans un mod typique, gralement "moins importants". Vous en avez d vu certains, comme un <literal>int</literal> @@ -1296,7 +1295,7 @@ la base de donn, et fournir une formulaire HTML pour saisir d'autres nements. </para> - <sect2 id="tutorial-webapp-servlet"> + <sect2 id="tutorial-webapp-servlet" revision="1"> <title>Ecrire la servlet de base</title> <para> @@ -1316,12 +1315,6 @@ }]]></programlisting> <para> - Le <literal>dateFormatter</literal> est un outil que nous utiliserons plus tard pour convertir les objets - <literal>Date</literal> depuis et vers des chaines de caracts. Il est propice de n'avoir qu'un - formatter comme membre de la servlet. - </para> - - <para> La servlet n'accepte que les requs HTTP <literal>GET</literal>, la mode mplnter est donc <literal>doGet()</literal>: </para> @@ -1376,7 +1369,7 @@ </sect2> - <sect2 id="tutorial-webapp-processing"> + <sect2 id="tutorial-webapp-processing" revision="1"> <title>Procr et rendre</title> <para> @@ -1434,7 +1427,8 @@ requ: </para> - <programlisting><![CDATA[private void listEvents(PrintWriter out) { + <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) { + List result = HibernateUtil.getSessionFactory() .getCurrentSession().createCriteria(Event.class).list(); if (result.size() > 0) { |
From: <hib...@li...> - 2006-08-03 17:07:32
|
Author: AnthonyHib Date: 2006-08-03 13:07:28 -0400 (Thu, 03 Aug 2006) New Revision: 10204 Added: trunk/Hibernate3/doc/reference/fr/modules/architecture.xml Log: update for 3.2 doc compliance Added: trunk/Hibernate3/doc/reference/fr/modules/architecture.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/architecture.xml 2006-08-03 17:06:21 UTC (rev 10203) +++ trunk/Hibernate3/doc/reference/fr/modules/architecture.xml 2006-08-03 17:07:28 UTC (rev 10204) @@ -0,0 +1,359 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<chapter id="architecture"> + + <title>Architecture</title> + + <sect1 id="architecture-overview" revision="1"> + <title>Gralit/title> + + <para> + Voici une vue (tr haut niveau de l'architecture d'Hibernate : + </para> + + <mediaobject> + <imageobject role="fo"> + <imagedata fileref="images/overview.svg" format="SVG" align="center"/> + </imageobject> + <imageobject role="html"> + <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/> + </imageobject> + </mediaobject> + + <para> + Ce diagramme montre Hibernate utilisant une base de donn et des donn + de configuration pour fournir un service de persistance (et des objets + persistants) 'application. + </para> + + <para> + Nous aimerions dire une vue plus dillde l'architecture. Malheureusement, + Hibernate est flexible et supporte diffntes approches. Nous allons en + montrer les deux extrs. L'architecture lre laisse l'application fournir + ses propres connexions JDBC et gr ses propres transactions. Cette approche + utilise le minimum des APIs Hibernate : + </para> + + <mediaobject> + <imageobject role="fo"> + <imagedata fileref="images/lite.svg" format="SVG" align="center"/> + </imageobject> + <imageobject role="html"> + <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/> + </imageobject> + </mediaobject> + + <para> + L'architecture la plus compl abstrait l'application des APIs JDBC/JTA + sous-jacentes et laisse Hibernate s'occuper des dils. + </para> + + <mediaobject> + <imageobject role="fo"> + <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/> + </imageobject> + <imageobject role="html"> + <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/> + </imageobject> + </mediaobject> + + <para> + Voici quelques dnitions des objets des diagrammes : + + <variablelist spacing="compact"> + <varlistentry> + <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term> + <listitem> + <para> + Un cache threadsafe (immuable) des mappings vers une (et une seule) base + de donn. Une factory (fabrique) de <literal>Session</literal> et un client + de <literal>ConnectionProvider</literal>. Peut contenir un cache optionnel de + donn (de second niveau) qui est rilisable entre les diffntes transactions + que cela soit au sein du m processus (JVLM) ou par plusieurs nuds d'un cluster. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Session (<literal>org.hibernate.Session</literal>)</term> + <listitem> + <para> + Un objet mono-threadurde vie courte, qui reprnte une conversation + entre l'application et l'entrepe persistance. Encapsule une connexion JDBC. + Factory (fabrique) des objets <literal>Transaction</literal>. Contient un cache + (de premier niveau) des objets persistants, ce cache est obligatoire. Il est + utilisors de la navigation dans le graphe d'objets ou lors de la rption + d'objets par leur identifiant. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Objets et Collections persistants</term> + <listitem> + <para> + Objets mono-threadie courte contenant l't de persistance + et la fonction mer. Ceux-ci sont en gral les objets de type JavaBean + (ou POJOs) ; la seule particularitst qu'ils sont associavec une (et + une seule) <literal>Session</literal>. Dque la <literal>Session</literal> + est ferm ils seront dchet libres d'e utilispar n'importe laquelle + des couches de l'application (ie. de et vers la prntation en tant que Data + Transfer Objects - DTO : objet de transfert de donn). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Objets et collections transients</term> + <listitem> + <para> + Instances de classes persistantes qui ne sont actuellement pas associ une <literal>Session</literal>. Elles ont pu e instanci par l'application + et ne pas avoir (encore) persist ou elle ont pu e instanci par + une <literal>Session</literal> ferm + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term> + <listitem> + <para> + (Optionnel) Un objet mono-thread vie courte utilisar l'application + pour dnir une unite travail atomique. Abstrait l'application des + transactions sous-jacentes qu'elles soient JDBC, JTA ou CORBA. Une + <literal>Session</literal> peut fournir plusieurs <literal>Transaction</literal>s + dans certains cas. Toutefois, la dmitation des transactions, via l'API d'Hibernate + ou par la <literal>Transaction</literal> sous-jacente, n'est jamais optionnelle! + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term> + <listitem> + <para> + (Optionnel) Une fabrique de (pool de) connexions JDBC. Abstrait l'application + de la <literal>Datasource</literal> ou du <literal>DriverManager</literal> sous-jacent. + Non expos l'application, mais peut e ndu/implntar le dloppeur. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term> + <listitem> + <para> + (Optionnel) Une fabrique d'instances de <literal>Transaction</literal>. Non + expos l'application, mais peut e ndu/implntar le dloppeur. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><emphasis>Interfaces d'extension</emphasis></term> + <listitem> + <para> + Hibernate fournit de nombreuses interfaces d'extensions optionnelles que + vous pouvez implnter pour personnaliser le comportement de votre couche de persistance. + Reportez vous a documentation de l'API pour plus de dils. + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + + <para> + Dans une architecture lre, l'application n'aura pas tiliser les APIs + <literal>Transaction</literal>/<literal>TransactionFactory</literal> + et/ou n'utilisera pas les APIs <literal>ConnectionProvider</literal> + pour utiliser JTA ou JDBC. + </para> + </sect1> + + <sect1 id="architecture-states" revision="1"> + <title>Etats des instances</title> + <para> + Une instance d'une classe persistante peut e dans l'un des trois ts suivants, + dnis par rapport n <emphasis>contexte de persistance</emphasis>. + L'objet <literal>Session</literal> d'hibernate correspond e concept de + contexte de persistance : + </para> + + <variablelist spacing="compact"> + <varlistentry> + <term>passager (transient)</term> + <listitem> + <para> + L'instance n'est pas et n'a jamais associn contexte + de persistance. Elle ne poss pas d'identitersistante (valeur de clrimaire) + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>persistant</term> + <listitem> + <para> + L'instance est associau contexte de persistance. + Elle poss une identitersistante (valeur de clrimaire) + et, peut-e, un enregistrement correspondant dans la base. + Pour un contexte de persistance particulier, Hibernate + <emphasis>garantit</emphasis> que l'identitersistante + est ivalente 'identitava (emplacement mire de l'objet) + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>dchterm> + <listitem> + <para> + L'instance a associau contexte de persistance mais ce + contexte a fermou l'instance a salisvers un + autre processus. Elle poss une identitersistante et + peut-e un enregistrement correspondant dans la base. + Pour des instances dch, Hibernate ne donne aucune + garantie sur la relation entre l'identitersistante et + l'identitava. + </para> + </listitem> + </varlistentry> + </variablelist> + </sect1> + + <sect1 id="architecture-jmx" revision="1"> + <title>Intation JMX</title> + <para> + JMX est le standard J2EE de gestion des composants Java. + Hibernate peut e g via un service JMX standard. Nous fournissons une implntation + d'un MBean dans la distribution : <literal>org.hibernate.jmx.HibernateService</literal>. + </para> + + <para> + Pour avoir un exemple sur la mani de doyer Hibernate en tant que service JMX dans le + serveur d'application JBoss Application Server, rrez vous au guide utilisateur JBoss (JBoss User Guide). + Si vous doyez Hibernate via JMX sur JBoss AS, vous aurez lement les bfices suivants : + </para> + <itemizedlist> + <listitem> + <para> + <emphasis>Gestion de la session :</emphasis> Le cycle de vie de la <literal>Session</literal> + Hibernate peut e automatiquement limita portd'une transaction JTA. + Cela signifie que vous n'avez plus besoin d'ouvrir et de fermer la <literal>Session</literal> + manuellement, cela devient le travail de l'intercepteur EJB de JBoss. Vous n'avez + pas non plus ous occuper des drcations des transactions dans votre code (sauf + si vous voulez ire une couche de persistance qui soit portable, dans ce cas vous + pouvez utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate). + Vous appelez l'<literal>HibernateContext</literal> pour accr a <literal>Session</literal>. + </para> + </listitem> + <listitem> + <para> + <emphasis>Doiement HAR :</emphasis> Habituellement vous doyez le service JMX + Hibernate en utilisant le descripteur de doiement de JBoss (dans un fichier EAR et/ou un SAR), + il supporte toutes les options de configuration usuelles d'une <literal>SessionFactory</literal> + Hibernate. Cependant, vous devez toujours nommer tous vos fichiers de mapping dans le + descripteur de doiement. Si vous ddez d'utiliser le doiement optionnel sous forme + de HAR, JBoss dctera automatiquement tous vos fichiers de mapping dans votre fichier HAR. + </para> + </listitem> + </itemizedlist> + + <para> + Consultez le guide d'utilisation de JBoss AS pour plus d'informations sur ces options. + </para> + + <para> + Les statistiques pendant l'extion d'Hibernate (au runtime) sont une + autre fonctionnalitisponible en tant que service JMX. Voyez pour cela + <xref linkend="configuration-optional-statistics"/>. + </para> + </sect1> + + <sect1 id="architecture-jca" revision="1"> + <title>Support JCA</title> + <para> + Hibernate peut aussi e configurn tant que connecteur JCA. Rrez-vous au site + web pour de plus amples dils. Il est important de noter que le support JCA d'Hibernate + est encore consid comme expmental. + </para> + </sect1> + + <sect1 id="architecture-current-session" revision="2"> + <title>Sessions Contextuelles</title> + <para> + Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", o une session est lia portd'un contexte particulier. Cependant, les applications ne dnissent + pas toutes la notion de contexte de la m mani, et diffnts contextes dnissent diffntes + port a notion de "courant". Les applications ase d'Hibernate, versions prdentes a 3.0 + utilisaient gralement un principe maison de sessions contextuelles bas sur le <literal>ThreadLocal</literal>, + ainsi que sur des classes utilitaires comme <literal>HibernateUtil</literal>, ou utilisaient des + framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles bas sur + l'utilisation de proxy/interception. + </para> + <para> + A partir de la version 3.0.1, Hibernate a ajouta mode <literal>SessionFactory.getCurrentSession()</literal>. + Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, o+ transaction <literal>JTA</literal> dnissait la portet le contexte de la session courante. + L'ipe Hibernate pense que, nt donnla maturites implntations de <literal>JTA TransactionManager</literal> , + la plupart (sinon toutes) des applications devraient utiliser la gestion des transactions par <literal>JTA</literal> + qu'elles soient ou non doy dans un conteneur <literal>J2EE</literal>. Par consent, + vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la mode bassur JTA. + </para> + <para> + Cependant, depuis la version 3.1, la logique derri + <literal>SessionFactory.getCurrentSession()</literal> est drmais branchable. + A cette fin, une nouvelle interface d'extension (<literal>org.hibernate.context.CurrentSessionContext</literal>) + et un nouveau parame de configuration (<literal>hibernate.current_session_context_class</literal>) + ont ajoutpour permettre de configurer d'autres moyens de dnir la portet le contexte des + sessions courantes. + </para> + <para> + Allez voir les Javadocs de l'interface <literal>org.hibernate.context.CurrentSessionContext</literal> + pour une description dillde son contrat. Elle dnit une seule mode, + <literal>currentSession()</literal>, depuis laquelle l'implntation est responsable + de traquer la session courante du contexte. Hibernate fournit deux implntation + de cette interface. + </para> + + <itemizedlist> + <listitem> + <para> + <literal>org.hibernate.context.JTASessionContext</literal> - les sessions courantes sont + associ ne transaction <literal>JTA</literal>. La logique est la m que + l'ancienne approche bassur JTA. Voir les javadocs pour les dils. + </para> + </listitem> + <listitem> + <para> + <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - les sessions + courantes sont associ au thread d'extion. Voir les javadocs pour les dils. + </para> + </listitem> + <listitem> + <para> + <literal>org.hibernate.context.ManagedSessionContext</literal> - les sessions + courantes sont traqu par l'extion du thread. Toutefois, vous s responsable + de lier et der une instance de <literal>Session</literal> avec les modes + statiques de cette classes, qui n'ouvre, ne flush ou ne ferme jamais de <literal>Session</literal>. + </para> + </listitem> + </itemizedlist> + + <para> + Les deux implntations fournissent un mod de programmation de type "une session - une transaction + a base de donn", aussi connu sous le nom de <emphasis>session-per-request</emphasis>. + Le dt et la fin d'une session Hibernate sont dnis par la durd'une transaction de base de donn. + Si vous utilisez une drcation programmatique de la transaction (par exemple sous J2SE ou JTA/UserTransaction/BMT), + nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le syst + de transaction utilisSi vous extez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune + options de drcations de session ou transaction dans votre code puisque tout + est g de mani darative. Rrez vous xref linkend="transactions"/> pour plus d'informations + et des exemples de code. + </para> + + <para> + Le parame de configuration <literal>hibernate.current_session_context_class</literal> + dnit quelle implntation de <literal>org.hibernate.context.CurrentSessionContext</literal> + doit e utilis Notez que pour assurer la compatibilitvec les versions prdentes, si + ce parame n'est pas dni mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal> + est configurHibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>. + La valeur de ce parame devrait juste nommer la classe d'implntation tiliser, + pour les deux implntations fournies, il y a cependant deux alias correspondant: "jta" et "thread". + </para> + + </sect1> + +</chapter> + |
From: <hib...@li...> - 2006-08-03 17:06:27
|
Author: AnthonyHib Date: 2006-08-03 13:06:21 -0400 (Thu, 03 Aug 2006) New Revision: 10203 Removed: trunk/Hibernate3/doc/reference/fr/modules/architecture.xml Log: update for 3.2 doc compliance Deleted: trunk/Hibernate3/doc/reference/fr/modules/architecture.xml =================================================================== --- trunk/Hibernate3/doc/reference/fr/modules/architecture.xml 2006-08-03 16:34:08 UTC (rev 10202) +++ trunk/Hibernate3/doc/reference/fr/modules/architecture.xml 2006-08-03 17:06:21 UTC (rev 10203) @@ -1,351 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<chapter id="architecture"> - - <title>Architecture</title> - - <sect1 id="architecture-overview" revision="1"> - <title>Gralit/title> - - <para> - Voici une vue (tr haut niveau de l'architecture d'Hibernate : - </para> - - <mediaobject> - <imageobject role="fo"> - <imagedata fileref="images/overview.svg" format="SVG" align="center"/> - </imageobject> - <imageobject role="html"> - <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/> - </imageobject> - </mediaobject> - - <para> - Ce diagramme montre Hibernate utilisant une base de donn et des donn - de configuration pour fournir un service de persistance (et des objets - persistants) 'application. - </para> - - <para> - Nous aimerions dire une vue plus dillde l'architecture. Malheureusement, - Hibernate est flexible et supporte diffntes approches. Nous allons en - montrer les deux extrs. L'architecture lre laisse l'application fournir - ses propres connexions JDBC et gr ses propres transactions. Cette approche - utilise le minimum des APIs Hibernate : - </para> - - <mediaobject> - <imageobject role="fo"> - <imagedata fileref="images/lite.svg" format="SVG" align="center"/> - </imageobject> - <imageobject role="html"> - <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/> - </imageobject> - </mediaobject> - - <para> - L'architecture la plus compl abstrait l'application des APIs JDBC/JTA - sous-jacentes et laisse Hibernate s'occuper des dils. - </para> - - <mediaobject> - <imageobject role="fo"> - <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/> - </imageobject> - <imageobject role="html"> - <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/> - </imageobject> - </mediaobject> - - <para> - Voici quelques dnitions des objets des diagrammes : - - <variablelist spacing="compact"> - <varlistentry> - <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term> - <listitem> - <para> - Un cache threadsafe (immuable) des mappings vers une (et une seule) base - de donn. Une factory (fabrique) de <literal>Session</literal> et un client - de <literal>ConnectionProvider</literal>. Peut contenir un cache optionnel de - donn (de second niveau) qui est rilisable entre les diffntes transactions - que cela soit au sein du m processus (JVLM) ou par plusieurs nuds d'un cluster. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Session (<literal>org.hibernate.Session</literal>)</term> - <listitem> - <para> - Un objet mono-threadurde vie courte, qui reprnte une conversation - entre l'application et l'entrepe persistance. Encapsule une connexion JDBC. - Factory (fabrique) des objets <literal>Transaction</literal>. Contient un cache - (de premier niveau) des objets persistants, ce cache est obligatoire. Il est - utilisors de la navigation dans le graphe d'objets ou lors de la rption - d'objets par leur identifiant. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Objets et Collections persistants</term> - <listitem> - <para> - Objets mono-threadie courte contenant l't de persistance - et la fonction mer. Ceux-ci sont en gral les objets de type JavaBean - (ou POJOs) ; la seule particularitst qu'ils sont associavec une (et - une seule) <literal>Session</literal>. Dque la <literal>Session</literal> - est ferm ils seront dchet libres d'e utilispar n'importe laquelle - des couches de l'application (ie. de et vers la prntation en tant que Data - Transfer Objects - DTO : objet de transfert de donn). - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Objets et collections transients</term> - <listitem> - <para> - Instances de classes persistantes qui ne sont actuellement pas associ une <literal>Session</literal>. Elles ont pu e instanci par l'application - et ne pas avoir (encore) persist ou elle ont pu e instanci par - une <literal>Session</literal> ferm - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term> - <listitem> - <para> - (Optionnel) Un objet mono-thread vie courte utilisar l'application - pour dnir une unite travail atomique. Abstrait l'application des - transactions sous-jacentes qu'elles soient JDBC, JTA ou CORBA. Une - <literal>Session</literal> peut fournir plusieurs <literal>Transaction</literal>s - dans certains cas. Toutefois, la dmitation des transactions, via l'API d'Hibernate - ou par la <literal>Transaction</literal> sous-jacente, n'est jamais optionnelle! - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term> - <listitem> - <para> - (Optionnel) Une fabrique de (pool de) connexions JDBC. Abstrait l'application - de la <literal>Datasource</literal> ou du <literal>DriverManager</literal> sous-jacent. - Non expos l'application, mais peut e ndu/implntar le dloppeur. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term> - <listitem> - <para> - (Optionnel) Une fabrique d'instances de <literal>Transaction</literal>. Non - expos l'application, mais peut e ndu/implntar le dloppeur. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis>Interfaces d'extension</emphasis></term> - <listitem> - <para> - Hibernate fournit de nombreuses interfaces d'extensions optionnelles que - vous pouvez implnter pour personnaliser le comportement de votre couche de persistance. - Reportez vous a documentation de l'API pour plus de dils. - </para> - </listitem> - </varlistentry> - </variablelist> - </para> - - <para> - Dans une architecture lre, l'application n'aura pas tiliser les APIs - <literal>Transaction</literal>/<literal>TransactionFactory</literal> - et/ou n'utilisera pas les APIs <literal>ConnectionProvider</literal> - pour utiliser JTA ou JDBC. - </para> - </sect1> - - <sect1 id="architecture-states" revision="1"> - <title>Etats des instances</title> - <para> - Une instance d'une classe persistante peut e dans l'un des trois ts suivants, - dnis par rapport n <emphasis>contexte de persistance</emphasis>. - L'objet <literal>Session</literal> d'hibernate correspond e concept de - contexte de persistance : - </para> - - <variablelist spacing="compact"> - <varlistentry> - <term>passager (transient)</term> - <listitem> - <para> - L'instance n'est pas et n'a jamais associn contexte - de persistance. Elle ne poss pas d'identitersistante (valeur de clrimaire) - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>persistant</term> - <listitem> - <para> - L'instance est associau contexte de persistance. - Elle poss une identitersistante (valeur de clrimaire) - et, peut-e, un enregistrement correspondant dans la base. - Pour un contexte de persistance particulier, Hibernate - <emphasis>garantit</emphasis> que l'identitersistante - est ivalente 'identitava (emplacement mire de l'objet) - </para> - </listitem> - </varlistentry> - <varlistentry> - <term>dchterm> - <listitem> - <para> - L'instance a associau contexte de persistance mais ce - contexte a fermou l'instance a salisvers un - autre processus. Elle poss une identitersistante et - peut-e un enregistrement correspondant dans la base. - Pour des instances dch, Hibernate ne donne aucune - garantie sur la relation entre l'identitersistante et - l'identitava. - </para> - </listitem> - </varlistentry> - </variablelist> - </sect1> - - <sect1 id="architecture-jmx" revision="1"> - <title>Intation JMX</title> - <para> - JMX est le standard J2EE de gestion des composants Java. - Hibernate peut e g via un service JMX standard. Nous fournissons une implntation - d'un MBean dans la distribution : <literal>org.hibernate.jmx.HibernateService</literal>. - </para> - - <para> - Pour avoir un exemple sur la mani de doyer Hibernate en tant que service JMX dans le - serveur d'application JBoss Application Server, rrez vous au guide utilisateur JBoss (JBoss User Guide). - Si vous doyez Hibernate via JMX sur JBoss AS, vous aurez lement les bfices suivants : - </para> - <itemizedlist> - <listitem> - <para> - <emphasis>Gestion de la session :</emphasis> Le cycle de vie de la <literal>Session</literal> - Hibernate peut e automatiquement limita portd'une transaction JTA. - Cela signifie que vous n'avez plus besoin d'ouvrir et de fermer la <literal>Session</literal> - manuellement, cela devient le travail de l'intercepteur EJB de JBoss. Vous n'avez - pas non plus ous occuper des drcations des transactions dans votre code (sauf - si vous voulez ire une couche de persistance qui soit portable, dans ce cas vous - pouvez utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate). - Vous appelez l'<literal>HibernateContext</literal> pour accr a <literal>Session</literal>. - </para> - </listitem> - <listitem> - <para> - <emphasis>Doiement HAR :</emphasis> Habituellement vous doyez le service JMX - Hibernate en utilisant le descripteur de doiement de JBoss (dans un fichier EAR et/ou un SAR), - il supporte toutes les options de configuration usuelles d'une <literal>SessionFactory</literal> - Hibernate. Cependant, vous devez toujours nommer tous vos fichiers de mapping dans le - descripteur de doiement. Si vous ddez d'utiliser le doiement optionnel sous forme - de HAR, JBoss dctera automatiquement tous vos fichiers de mapping dans votre fichier HAR. - </para> - </listitem> - </itemizedlist> - - <para> - Consultez le guide d'utilisation de JBoss AS pour plus d'informations sur ces options. - </para> - - <para> - Les statistiques pendant l'extion d'Hibernate (au runtime) sont une - autre fonctionnalitisponible en tant que service JMX. Voyez pour cela - <xref linkend="configuration-optional-statistics"/>. - </para> - </sect1> - - <sect1 id="architecture-jca" revision="1"> - <title>Support JCA</title> - <para> - Hibernate peut aussi e configurn tant que connecteur JCA. Rrez-vous au site - web pour de plus amples dils. Il est important de noter que le support JCA d'Hibernate - est encore consid comme expmental. - </para> - </sect1> - - <sect1 id="architecture-current-session" revision="1"> - <title>Sessions Contextuelles</title> - <para> - Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", o une session est lia portd'un contexte particulier. Cependant, les applications ne dnissent - pas toutes la notion de contexte de la m mani, et diffnts contextes dnissent diffntes - port a notion de "courant". Les applications ase d'Hibernate, versions prdentes a 3.0 - utilisaient gralement un principe maison de sessions contextuelles bas sur le <literal>ThreadLocal</literal>, - ainsi que sur des classes utilitaires comme <literal>HibernateUtil</literal>, ou utilisaient des - framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles bas sur - l'utilisation de proxy/interception. - </para> - <para> - A partir de la version 3.0.1, Hibernate a ajouta mode <literal>SessionFactory.getCurrentSession()</literal>. - Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, o- transaction <literal>JTA</literal> dnissait la portet le contexte de la session courante. - L'ipe Hibernate pense que, nt donnla maturites implntations de <literal>JTA TransactionManager</literal> , - la plupart (sinon toutes) des applications devraient utiliser la gestion des transactions par <literal>JTA</literal> - qu'elles soient ou non doy dans un conteneur <literal>J2EE</literal>. Par consent, - vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la mode bassur JTA. - </para> - <para> - Cependant, depuis la version 3.1, la logique derri - <literal>SessionFactory.getCurrentSession()</literal> est drmais branchable. - A cette fin, une nouvelle interface d'extension (<literal>org.hibernate.context.CurrentSessionContext</literal>) - et un nouveau parame de configuration (<literal>hibernate.current_session_context_class</literal>) - ont ajoutpour permettre de configurer d'autres moyens de dnir la portet le contexte des - sessions courantes. - </para> - <para> - Allez voir les Javadocs de l'interface <literal>org.hibernate.context.CurrentSessionContext</literal> - pour une description dillde son contrat. Elle dnit une seule mode, - <literal>currentSession()</literal>, depuis laquelle l'implntation est responsable - de traquer la session courante du contexte. Hibernate fournit deux implntation - de cette interface. - </para> - - <itemizedlist> - <listitem> - <para> - <literal>org.hibernate.context.JTASessionContext</literal> - les sessions courantes sont - associ ne transaction <literal>JTA</literal>. La logique est la m que - l'ancienne approche bassur JTA. Voir les javadocs pour les dils. - </para> - </listitem> - <listitem> - <para> - <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - les sessions - courantes sont associ au thread d'extion. Voir les javadocs pour les dils. - </para> - </listitem> - </itemizedlist> - - <para> - Les deux implntations fournissent un mod de programmation de type "une session - une transaction - a base de donn", aussi connu sous le nom de <emphasis>session-per-request</emphasis>. - Le dt et la fin d'une session Hibernate sont dnis par la durd'une transaction de base de donn. - Si vous utilisez une drcation programmatique de la transaction (par exemple sous J2SE ou JTA/UserTransaction/BMT), - nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le syst - de transaction utilisSi vous extez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune - options de drcations de session ou transaction dans votre code puisque tout - est g de mani darative. Rrez vous xref linkend="transactions"/> pour plus d'informations - et des exemples de code. - </para> - - <para> - Le parame de configuration <literal>hibernate.current_session_context_class</literal> - dnit quelle implntation de <literal>org.hibernate.context.CurrentSessionContext</literal> - doit e utilis Notez que pour assurer la compatibilitvec les versions prdentes, si - ce parame n'est pas dni mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal> - est configurHibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>. - La valeur de ce parame devrait juste nommer la classe d'implntation tiliser, - pour les deux implntations fournies, il y a cependant deux alias correspondant: "jta" et "thread". - </para> - - </sect1> - -</chapter> - |
From: <hib...@li...> - 2006-08-03 16:34:13
|
Author: jdkim528 Date: 2006-08-03 12:34:08 -0400 (Thu, 03 Aug 2006) New Revision: 10202 Modified: trunk/Hibernate3/doc/reference/ko/README-KO.txt Log: 3.2 cr3 korean Modified: trunk/Hibernate3/doc/reference/ko/README-KO.txt =================================================================== --- trunk/Hibernate3/doc/reference/ko/README-KO.txt 2006-08-03 15:50:06 UTC (rev 10201) +++ trunk/Hibernate3/doc/reference/ko/README-KO.txt 2006-08-03 16:34:08 UTC (rev 10202) @@ -12,10 +12,32 @@ * CVS SVNٲ ű 䰡 . - TortoiseSVN ǷTortoiseSVN + TortoiseSVNclipse Subclpse մϴ(ȣsvn Ŭ ٸش ŵ Դϴ) - + + [Subclipse ġ] + + Subclipse ġ http://subclipse.tigris.org/install.html + eclipse ãġ ġ ϴ + + [Subclipse Checkout] + 0) Subclipse ġ Ͻʽÿ + 1) Ŭ Perspective SVN Repository exploring ų + Ŭ Ű Ž 콺 "Ʈ" ϴ + ⼭"Ʈ" ϴ + 2) Ŭ Ű Ž 콺 "Ʈ" Ŭ+ 3) "SVN" "Checkout Projects from SVN" + 4) "" Ŭ+ 5) "Create a new respository location" + 6) " Ŭ+ 7) Location url "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" Ǵ + "https://hibernate.labs.jboss.com/repos/hibernate/trunk" մϴ + 8) "Hibernate3" ų Ư Ϸ Ŭ + 9) Ʈ hibernate3 + 10) checkout ϴ + + [TortoiseSVN ġ] TortoiseSVN Ŭ ġ̴ٸý ʽÿ 1) ϴ(D:\repo) 2) D:\repo 콺 Ŭ TortoiseSVN @@ -24,8 +46,8 @@ 3)hibernate ޱ :\repo\Hibernate3) 4)D:\repo\hibernate 콺 Ŭ , TortoiseSVN CheckOut Ŭʽÿ - 5)URL repository - "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" ϰ + 5)URL repository "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" Ǵ + "https://hibernate.labs.jboss.com/repos/hibernate/trunk" ϰ OK Ŭʽÿ 6) D:\repo\Hibernate3\doc\referenceϴ 7) Ͻø˴ϴ |
From: <hib...@li...> - 2006-08-03 15:50:10
|
Author: jdkim528 Date: 2006-08-03 11:50:06 -0400 (Thu, 03 Aug 2006) New Revision: 10201 Modified: trunk/Hibernate3/doc/reference/build.xml Log: 3.2 cr3 korean Modified: trunk/Hibernate3/doc/reference/build.xml =================================================================== --- trunk/Hibernate3/doc/reference/build.xml 2006-08-03 15:19:26 UTC (rev 10200) +++ trunk/Hibernate3/doc/reference/build.xml 2006-08-03 15:50:06 UTC (rev 10201) @@ -40,11 +40,11 @@ <!-- TRANSLATOR: Duplicate this line for your language --> <antcall target="lang.all"><param name="lang" value="en"/></antcall> + <antcall target="lang.all"><param name="lang" value="ko"/></antcall> <!-- TODO: These translations need updating... <antcall target="lang.all"><param name="lang" value="zh-cn"/></antcall> <antcall target="lang.all"><param name="lang" value="es"/></antcall> <antcall target="lang.all"><param name="lang" value="ja"/></antcall> - <antcall target="lang.all"><param name="lang" value="ko"/></antcall> <antcall target="lang.all"><param name="lang" value="fr"/></antcall> --> |
From: <hib...@li...> - 2006-08-03 15:19:33
|
Author: jdkim528 Date: 2006-08-03 11:19:26 -0400 (Thu, 03 Aug 2006) New Revision: 10200 Modified: trunk/Hibernate3/doc/reference/ko/modules/configuration.xml trunk/Hibernate3/doc/reference/ko/modules/events.xml trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml trunk/Hibernate3/doc/reference/ko/modules/tutorial.xml Log: 3.2 cr3 Modified: trunk/Hibernate3/doc/reference/ko/modules/configuration.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/configuration.xml 2006-08-03 14:42:53 UTC (rev 10199) +++ trunk/Hibernate3/doc/reference/ko/modules/configuration.xml 2006-08-03 15:19:26 UTC (rev 10200) @@ -871,7 +871,7 @@ </tgroup> </table> - <table frame="topbot" id="configuration-misc-properties" revision="9"> + <table frame="topbot" id="configuration-misc-properties" revision="10"> <title>여러가지 프로퍼티들</title> <tgroup cols="2"> <colspec colname="c1" colwidth="1*"/> @@ -889,12 +889,12 @@ </entry> <entry> "현재" <literal>Session</literal>의 영역화를 위한 하나의 (맞춤) 방도를 - 공급한다. 빌드되어 있는 방도들에 대한 추가 정보는 + 제공한다. 빌드되어 있는 방도들에 대한 추가 정보는 <xref linkend="architecture-current-session"/>를 보라. <para> <emphasis role="strong">예.</emphasis> - <literal>jta</literal> | <literal>thread</literal> | - <literal>custom.Class</literal> + <literal>jta</literal> | <literal>thread</literal> | + <literal>managed</literal> | <literal>custom.Class</literal> </para> </entry> </row> @@ -906,7 +906,7 @@ Chooses the HQL 파서 구현을 선택한다. <para> <emphasis role="strong">예.</emphasis> - <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> 또는 + <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal> </para> </entry> @@ -916,7 +916,8 @@ <literal>hibernate.query.substitutions</literal> </entry> <entry> - Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑(예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다). + Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑 + (예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다). <para> <emphasis role="strong">예.</emphasis> <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal> @@ -928,8 +929,10 @@ <literal>hibernate.hbm2ddl.auto</literal> </entry> <entry> - <literal>SessionFactory</literal>가 생성될 때 스키마 DDL을 데이터베이스로 자동적으로 유효성 검사하거나 내보내기 한다. <literal>create-drop</literal>의 경우, - <literal>SessionFactory</literal>가 명시적으로 닫혀질 때,, 데이터베이스 스키마가 드롭될 것이다. + <literal>SessionFactory</literal>가 생성될 때, 자동적으로 유효성을 검사하거나 + schema DDL을 데이터베이스로 내보내기 한다. <literal>create-drop</literal>의 경우, + <literal>SessionFactory</literal>가 명시적으로 닫혀질 때 데이터베이스 스키마가 + 드롭될 것이다. <para> <emphasis role="strong">예.</emphasis> <literal>validate</literal> | <literal>update</literal> | @@ -942,8 +945,10 @@ <literal>hibernate.cglib.use_reflection_optimizer</literal> </entry> <entry> - 런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티). Reflection은 문제가 발생할 시에 때때로 유용할 수 있고, - 당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라. 당신은 <literal>hibernate.cfg.xml</literal> + 런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티). + Reflection은 문제가 발생할 시에 때때로 유용할 수 있고, + 당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라. + 당신은 <literal>hibernate.cfg.xml</literal> 속에 이 프로퍼티를 설정할수 없다. <para> <emphasis role="strong">예.</emphasis> Modified: trunk/Hibernate3/doc/reference/ko/modules/events.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/events.xml 2006-08-03 14:42:53 UTC (rev 10199) +++ trunk/Hibernate3/doc/reference/ko/modules/events.xml 2006-08-03 15:19:26 UTC (rev 10200) @@ -6,7 +6,7 @@ 그리고 Hibernate의 확장 기능의 구현을 허용해준다. </para> - <sect1 id="objectstate-interceptors" revision="2"> + <sect1 id="objectstate-interceptors" revision="3"> <title>인터셉터들</title> <para> @@ -106,12 +106,13 @@ }]]></programlisting> <para> - 세션이 생성될 때 인터셉터가 지정될 것이다. + 인터셉터들은 다음 두 개의 특징들로 나타난다: <literal>Session</literal>-영역화 그리고 + <literal>SessionFactory</literal>-영역화. </para> <para> - <literal>Session</literal>-영역의 인터셉터는 <literal>Interceptor</literal>를 수용하는 - 하나의 세션이 오버로드된 SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때 + <literal>Session</literal>-영역의 인터셉터는 세션이 하나의 <literal>Interceptor</literal>를 수용하는 + 오버로드된 SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때 지정된다. </para> @@ -122,23 +123,34 @@ 이 경우에, 인터셉터는 threadsafe이어야 한다. </para> + <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting> + + <para> + <literal>SessionFactory</literal>-영역의 인터셉터는 <literal>SessionFactory</literal>을 빌드하기에 앞서 + <literal>Configuration</literal> 객체에 등록된다. 이 경우에, 공급되는 인터셉터는 그 <literal>SessionFactory</literal>로부터 + 열려진 모든 세션들에 적용될 것이다; 하나의 세션이 사용할 인터셉터를 명시적으로 지정하여 열리지 않는 한 이것은 참이다. + <literal>SessionFactory</literal>-영역의 인터셉터들은 세션-지정적인 상태를 저장하지 않도록 주의하여 쓰레드-안전해야 한다. + 왜냐하면 다중 세션들은 (잠정적으로) 이 인터셉터를 동시적으로 사용할 것이기 때문이다. + </para> + <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting> </sect1> - <sect1 id="objectstate-events" revision="3"> + <sect1 id="objectstate-events" revision="4"> <title>이벤트 시스템</title> <para> - 만일 당신이 당신의 영속 계층에서 특별한 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>이벤트</emphasis> + 만일 당신이 당신의 영속 계층에서 특정 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>event</emphasis> 아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다. </para> <para> - 본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 당신은 <literal>LoadEvent</literal>, + 본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. + 당신은 <literal>LoadEvent</literal>, <literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는 <literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때, - Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입에 대한 구성된 이벤트 리스너에게 전달한다. + Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입의 구성된 이벤트 리스너에게 전달한다. 박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을 구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal>는 <literal>LoadEventListener</literal> 인터페이스의 등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal> @@ -152,10 +164,10 @@ <para> 맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate - out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고자 그리고/또는 확장하고자 원하는 이벤트들에 대해 + out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고/하거나 확장하고자 원하는 이벤트들에 대해 적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로 등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다). - 다음은 맞춤형 load 이벤트 리스너에 대한 예제이다: + 다음은 맞춤형 load 이벤트 리스너에 대한 예제이다: </para> <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener { @@ -191,13 +203,13 @@ cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting> <para> - 선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 <literal><listener/></literal> + 선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 개의 <literal><listener/></literal> 요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을 공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다. </para> <para> - 컨피그레이션 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을 + 구성 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을 구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을 더 쉽게 해준다. </para> Modified: trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml 2006-08-03 14:42:53 UTC (rev 10199) +++ trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml 2006-08-03 15:19:26 UTC (rev 10200) @@ -116,7 +116,7 @@ ]]></programlisting> <para>이것은 cat.getDog()이 고유하게 기능하는 것을 허용한다.</para> - <sect2> + </sect2> <sect2> <title>연관들과 콜렉션들을 처리하기</title> Modified: trunk/Hibernate3/doc/reference/ko/modules/tutorial.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/tutorial.xml 2006-08-03 14:42:53 UTC (rev 10199) +++ trunk/Hibernate3/doc/reference/ko/modules/tutorial.xml 2006-08-03 15:19:26 UTC (rev 10200) @@ -1,7 +1,7 @@ <chapter id="tutorial"> <title>Hibernate 개요</title> - <sect1 id="tutorial-intro"> + <sect1 id="tutorial-intro" revision="1"> <title>머리말</title> <para> @@ -67,15 +67,17 @@ 다음으로 우리는 우리가 데이터베이스 속에 저장시키고자 원하는 이벤트를 표현하는 한 개의 클래스를 생성시킨다. </para> - <sect2 id="tutorial-firstapp-firstclass"> + <sect2 id="tutorial-firstapp-firstclass" revision="1"> <title>첫 번째 클래스</title> <para> 우리의 첫 번째 영속 클래스는 몇몇 프로퍼티들을 가진 간단한 자바빈즈 클래스이다: </para> - <programlisting><![CDATA[import java.util.Date; + <programlisting><![CDATA[package events; +import java.util.Date; + public class Event { private Long id; @@ -117,14 +119,14 @@ </para> <para> - <literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 만일 우리가 Hibernate의 - 전체 특징을 사용하고자 원할 경우 모든 영속 엔티티 클래스들(보다 덜 중요한 종속 클래스들 또한 존재한다)은 그런 - 식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해 - 객체들을 구분지을 필요가 있어서, 당신은 이것을 어떤 제한이라기 보다는 하나의 특징으로 간주할 것이다. 하지만 - 우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때, - Hibernate는 단지 식별자를 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들 - 뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려 - 있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다. + <literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 모든 영속 엔티티 클래스들 + (보다 덜 중요한 종속 클래스들도 존재한다)은 우리가 Hibernate의 전체 특징 집합을 사용하고자 원할 경우에 + 그런 식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해 + 객체들을 구분지을 필요가 있어서, 당신은 이것을 어떤 제약점이라기 보다는 하나의 특징으로 간주할 것이다. 하지만 + 우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때, + Hibernate는 단지 식별자들을 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들 + 뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려 + 있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다. </para> <para> @@ -134,7 +136,7 @@ </para> <para> - 이 Java 노스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제 + 이 Java 소스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제 그 디렉토리는 다음과 같을 것이다: </para> @@ -723,9 +725,9 @@ </listitem> <listitem> <para> - 이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 프로퍼티를 주석처리함으로써 hbm2ddl을 - 사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서 그것을 사용 가능하게 내버려두어도 되지만, 또 다른 - hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>드롭</emphasis>시킬 것이다 - <literal>create</literal> + 이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 그 프로퍼티를 주석처리함으로써 hbm2ddl을 + 사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서는 그것을 사용 가능하게 내버려두어도 되지만, 또 다른 + hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>drop</emphasis>시킬 것이다 - <literal>create</literal> 구성 설정은 실제로 "스키마로부터 모든 테이블들을 드롭시키고 나서, SessionFactory가 빌드될 때 모든 테이블들을 다시 생성시키는 것"으로 변환된다. </para> @@ -756,7 +758,7 @@ 우리는 우리의 어플리케이션에 사람들을 추가하고 그들이 참여하는 이벤트들의 목록을 저장할 것이다. </para> - <sect2 id="tutorial-associations-mappinguser"> + <sect2 id="tutorial-associations-mappinguser" revision="1"> <title>Person 클래스 매핑하기</title> <para> |
From: <hib...@li...> - 2006-08-03 14:42:58
|
Author: chr...@jb... Date: 2006-08-03 10:42:53 -0400 (Thu, 03 Aug 2006) New Revision: 10199 Modified: trunk/Hibernate3/doc/reference/README Log: Updated process description Modified: trunk/Hibernate3/doc/reference/README =================================================================== --- trunk/Hibernate3/doc/reference/README 2006-08-03 14:01:28 UTC (rev 10198) +++ trunk/Hibernate3/doc/reference/README 2006-08-03 14:42:53 UTC (rev 10199) @@ -1,9 +1,176 @@ -We're using the DocBook XSL distribution for HTML and PDF -generation. The best results can be achieved with the -Saxon XSLT processor (don't use Xalan!) and the Apache -FOP library. +THE HIBERNATE DOCUMENTATION +ch...@hi... -The documentation is generated with the distribution -build.xml target 'doc<pdf|html|htmlsingle>'. +COPYRIGHT NOTICE: This documentation system and all its source files are +licensed under the GNU Lesser Public License (LGPL). Authors and translators +retain the copyright of their work. All font and other build files (the DocBook +system) are property of their respective copyright holders. Some of the files +(especially font files) might require a license from the respective vendor; you +are responsible to check and obtain these licenses as necessary before you use +and/or distribute these files. -ch...@hi... + +Preface + +The Hibernate documentation is a modular documentation, it uses +various XML files (written with the DocBook DTD) and a Java-based +build process to generate HTML and PDF output. Use a simple text +editor with XML support, such as JEdit, to edit the source files. You +will need Java and Ant installed for the output generation. The toolset +is Java only and should work on any operating system. + +Note: Always use 4 spaces to indent, no tabstops (code examples will +be broken otherwise). + + +1. How to get it + +Check out a copy of Hibernate from the repository. A regular +Hibernate download will not contain the build process for the +documentation, only the PDF/HTML output, use the repository! +See http://www.hibernate.org/Download/DownloadOverview + + +2. Working on the original language + +The original and master language is English, hence the "en" subdirectory +in /doc/reference/ is authorative. We use "id" and "revision" attributes on +XML elements to track changes. Here are the rules, they are mandatory: + +2a. Changing existing content involves an update of the "revision" of the XML +element you are working on (e.g. a <sect1>, <sect2> or even a <para>). + +If a <sect1> has a revision="1", you update it to "2" after updating the +content in that section. + +You can also add a revision attribute to an element if there is none, +start with revision="1". You should not add a revision attribute to each +paragraph, try to only add/use revision attributes to sections. You can' +t add a revision attribute to elements without an "id" attribute! + +2b. Adding new content involves adding new elements (even new files), such +as <sect1>, <para> and so on. Any new element (or its new parent element) +needs an "id" attribute if the new content is to be included in the change +tracking. If you add a section, give it a unique short text +identifer, look at the parent element's identifier for the common prefix. + +2c. Deleting content involves removing old elements. Just remove them and +make sure that the parent elements revision is updated, if the removed +element did not itself have an identifer and a revision. If you remove an +element with its own identifier, everything is fine and no other changes are +necessary. + + +3. Starting a new language + +If you start a translation for a new language, you have to copy +the default language (English) and start an initial translation. + +3a. First, duplicate the default language "en" by duplicating the directory +/doc/reference/en. For example, a new German translation +will be a copy of that directory in /doc/reference/de. We use the ISO +codes to name the language subdirectories. + +3b. You also have to add your new language to the language build file, +/doc/reference/build.xml. Look for the lines that have a "TRANSLATOR" +comment and duplicate them. Change the default "en" to your language +code, every language listed here will be included in both the PDF/HTML +generation and the revision diff change tracking reports (discussed later). + + +4. The initial translation + +If you just copied the default language, start translating the DocBook +XML modules and illustrations in the new language subdirectory. For +example, all modules for German would be in /doc/reference/de/modules +and all illustrations in /doc/reference/de/images, note that you also have +to translate the master.xml in your language subdirectory. + +The initial translation is straightforward: Translate all modules and +all illustrations, but don't add any files, don't add any new XML elements +(like a section or a chapter, not even a paragraph). Simply translate +sentence by sentence. This is very important. + +Note that every DocBook XML file needs an encoding, specific to a +language. Add a line like this at the top of every file, if it doesn't exist: +<?xml version='1.0' encoding="iso-8859-1"?> + +You can use UTF-8 or any other character set, please experiment with +the builds to see what works for you. + +If you need a new section or paragraph, because your translation requires +more explanation, you can add it if you also add an "id" and a "revision" +to that new section or paragraph. + +For example, if you add a new <para> element to the existing document, +give it an identifier, a short unique string that extends the identifier +string of the parent element: <para id="queryhql-projection-specialnote"> +would be a special paragraph in the <sect1 id="queryhql-projection"> +section in the chapter <chapter id="queryhql">. + +Never add a new element in a translated version without also adding a new +unique identifier value! Also, you have to mark this new element as "only +relevant in the translated version". Simply set the "revision" attribute of +your new element to "-1". For example, set the previously created +paragraph to "only relevant in the translation" by declaring +<para id="queryhql-projection-specialnote" revision="-1">. +Changes to that paragraph will not be tracked, it is your responsibility to +watch out for neccessary updates. Any element with revision="-1" will not be +tracked. + + +5. Updating translated documentation + +Translators get updates by updating their working directory from the +repository. As a translator you will get an e-mail from us when translation +is required, you can then update your copy. Or, subscribe to the commit +mailing list to get all updates automatically. + +The documentation tools can generate a report after you updated +from the repository and show you what needs to be translated and/or removed +in your local translation copy. To generate that report, run "ant all.revdiff" +in the doc/reference/ subdirectory. Click on the generated HTML report +file for your language and you will see what has to be updated and/or +removed. + +If the report indicates that content in the original has been removed, +simply remove the identified XML element from your language modules. + +If the report detects a new revision, open the file that has been updated +in your translation, find the identified XML element and update/translate +its contents. Important: Make sure you also update the "revision" +attribute of that XML element by setting it to the same version as in +the original file, hence both the original XML file and your translated +file should have the same revision number for all elements. If an +XML element in your translation doesn't have a revision, but the original +file has, add a new "revision" attribute to your XML element. +The HTML report shows the identifiers and revisions for both the original +and the translated files, use it to compare. + +Rerun the "ant all.revdiff" report generation as often as you like until +no more differences are detected. You should always try to get your +copy clean, with all updated revisions and all identified elements +synchronzied. + + +6. Committing a translation + +All translators will be asked to submit their translated versions from +time to time. This will be a manual process, you will get an e-mail from +the Hibernate team and simply send your language subdirectory as +a ZIP file to us. It will then be integrated in the main Hibernate +distribution and on the website. Or, you can contact us for commit access +to the repository, where you can maintain a translation directly. + + +7. Generating PDF and HTML output + +The documentation is generated with the target 'ant all.doc'. + +To build the reference docs for a particular language only, use +"ant -Dlang=en", for example, and call either lang.all, lang.docpdf, +lang.dochtml, or lang.dochtmlsingle for the target of your choice. + +You can also call lang.section-check to track down missing identifiers in +a particular language, or you can call lang.revdiff to get a difference +report for a particular language, compared with the English reference. |
From: <hib...@li...> - 2006-08-03 14:01:48
|
Author: jdkim528 Date: 2006-08-03 10:01:28 -0400 (Thu, 03 Aug 2006) New Revision: 10198 Modified: trunk/Hibernate3/doc/reference/ko/README-KO.txt trunk/Hibernate3/doc/reference/ko/master.xml trunk/Hibernate3/doc/reference/ko/modules/architecture.xml trunk/Hibernate3/doc/reference/ko/modules/association_mapping.xml trunk/Hibernate3/doc/reference/ko/modules/basic_mapping.xml trunk/Hibernate3/doc/reference/ko/modules/batch.xml trunk/Hibernate3/doc/reference/ko/modules/collection_mapping.xml trunk/Hibernate3/doc/reference/ko/modules/component_mapping.xml trunk/Hibernate3/doc/reference/ko/modules/configuration.xml trunk/Hibernate3/doc/reference/ko/modules/events.xml trunk/Hibernate3/doc/reference/ko/modules/example_mappings.xml trunk/Hibernate3/doc/reference/ko/modules/inheritance_mapping.xml trunk/Hibernate3/doc/reference/ko/modules/performance.xml trunk/Hibernate3/doc/reference/ko/modules/persistent_classes.xml trunk/Hibernate3/doc/reference/ko/modules/query_criteria.xml trunk/Hibernate3/doc/reference/ko/modules/query_hql.xml trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml trunk/Hibernate3/doc/reference/ko/modules/session_api.xml trunk/Hibernate3/doc/reference/ko/modules/transactions.xml trunk/Hibernate3/doc/reference/ko/modules/tutorial.xml Log: 3.2 cr3 Modified: trunk/Hibernate3/doc/reference/ko/README-KO.txt =================================================================== --- trunk/Hibernate3/doc/reference/ko/README-KO.txt 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/README-KO.txt 2006-08-03 14:01:28 UTC (rev 10198) @@ -9,28 +9,34 @@ Blog : http://blog.naver.com/jdkim528/ [Down/Config/Build] - cvs Ŭ ִٸ - 1) : pserve/extssh ϴ- 2) : anonymous - 3)ȣƮ : cvs.sourceforge.net - 4)Ʈ : ⺻ - 5)Ұ : /cvsroot/hibernate - 6) : Hibernate3/doc/reference - REFERENCE ü ŵ - ôٸŵ ˴ϴ - []. ޱ 6) Hibernate3/doc/reference/supportð- ǻ 丮 []/reference/ ϴ- []. ۺ ޱ 6) Hibernate3/doc/reference/ko- ǻ 丮 []/reference/ ϴ - [. ޱ /doc/reference/build.xml + * CVS SVNٲ ű 䰡 + . + + TortoiseSVN ǷTortoiseSVN + մϴ(ȣsvn Ŭ ٸش + ŵ Դϴ) + + TortoiseSVN Ŭ ġ̴ٸý ʽÿ + 1) ϴ(D:\repo) + 2) D:\repo 콺 Ŭ TortoiseSVN + "Create repository Here..." Ŭ˾ߴµ, + ý/DB K + 3)hibernate ޱ :\repo\Hibernate3) + 4)D:\repo\hibernate 콺 Ŭ , + TortoiseSVN CheckOut Ŭʽÿ + 5)URL repository + "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" ϰ + OK Ŭʽÿ+ 6) D:\repo\Hibernate3\doc\referenceϴ + 7) Ͻø˴ϴ + + *) ôٸŵ ˴ϴ + /doc/reference/build.xml Ʒ κе óϴ - [ϱ []. ϱ []/reference/ ant all.docϽø˴ϴ ð 2 ҿϴ - []. []. 丮 []/reference/build/ko/ 丮 ñٶ. ſð Modified: trunk/Hibernate3/doc/reference/ko/master.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/master.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/master.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -33,7 +33,7 @@ <bookinfo lang="ko"> <title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title> <subtitle>하이버네이트 참조 문서</subtitle> - <releaseinfo lang="ko">3.1</releaseinfo> + <releaseinfo lang="ko">3.2 cr3</releaseinfo> </bookinfo> <toc lang="ko" /> Modified: trunk/Hibernate3/doc/reference/ko/modules/architecture.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/architecture.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/architecture.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -236,7 +236,7 @@ </para> </sect1> - <sect1 id="architecture-current-session" revision="1"> + <sect1 id="architecture-current-session" revision="2"> <title>컨텍스트 상의 세션들</title> <para> Hibernate를 사용하는 대부분의 어플리케이션들은 어떤 양식의 "컨텍스트상의(contextual)" 세션들을 필요로 한다. 여기서 @@ -264,7 +264,7 @@ <para> 그것의 계약에 대한 상세한 논의는 <literal>org.hibernate.context.CurrentSessionContext</literal> 인터페이스에 관한 javadocs를 보라. 그것은 하나의 메소드, <literal>currentSession()</literal>를 정의하며, 그 구현은 - 현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 구 개의 구현들을 부수적으로 + 현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 세 개의 구현들을 부수적으로 포함하고 있다. </para> @@ -284,7 +284,7 @@ </listitem> </itemizedlist> <para> - 두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는 + 처음의 두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는 "하나의 세션 - 하나의 데이터베이스 트랜잭션" 프로그래밍 모형을 제공한다. 하나의 Hibernate 세션의 시작과 끝은 데이터베이스 트랜잭션의 존속 기간에 의해 정의된다. 만일 (예를 들면 순수 J2SE에서 또는 JTA/UserTransaction/BMT의 경우에) 당신이 프로그램 상의 트랜잭션 경계구분을 사용할 경우, 당신은 당신의 코드로부터 기본 트랜잭션 시스템을 은폐시키는데 Modified: trunk/Hibernate3/doc/reference/ko/modules/association_mapping.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/association_mapping.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/association_mapping.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -48,8 +48,7 @@ </id> </class>]]></programlisting> <programlisting><![CDATA[ -create table Person ( personId bigint not null primary key, - addressId bigint not null ) +create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -79,8 +78,7 @@ </id> </class>]]></programlisting> <programlisting><![CDATA[ -create table Person ( personId bigint not null primary key, - addressId bigint not null unique ) +create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -135,8 +133,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table Address ( addressId bigint not null primary key, - personId bigint not null ) +create table Address ( addressId bigint not null primary key, personId bigint not null ) ]]></programlisting> <para> @@ -177,8 +174,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId not null, - addressId bigint not null primary key ) +create table PersonAddress ( personId not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -211,8 +207,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId bigint not null primary key, - addressId bigint not null ) +create table PersonAddress ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -247,8 +242,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId bigint not null primary key, - addressId bigint not null unique ) +create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -279,9 +273,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId bigint not null, - addressId bigint not null, - primary key (personId, addressId) ) +create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -319,8 +311,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ -create table Person ( personId bigint not null primary key, - addressId bigint not null ) +create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -386,8 +377,7 @@ property-ref="address"/> </class>]]></programlisting> <programlisting><![CDATA[ -create table Person ( personId bigint not null primary key, - addressId bigint not null unique ) +create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -459,8 +449,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId bigint not null, - addressId bigint not null primary key ) +create table PersonAddress ( personId bigint not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -505,8 +494,7 @@ </class>]]></programlisting> <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId bigint not null primary key, - addressId bigint not null unique ) +create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> @@ -543,9 +531,7 @@ <programlisting><![CDATA[ create table Person ( personId bigint not null primary key ) -create table PersonAddress ( personId bigint not null, - addressId bigint not null, - primary key (personId, addressId) ) +create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) ) create table Address ( addressId bigint not null primary key ) ]]></programlisting> Modified: trunk/Hibernate3/doc/reference/ko/modules/basic_mapping.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/basic_mapping.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/basic_mapping.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -92,7 +92,7 @@ - <sect2 id="mapping-declaration-doctype" revision="2"> + <sect2 id="mapping-declaration-doctype" revision="3"> <title>Doctype</title> <para> @@ -102,6 +102,56 @@ 당신이 인터넷 연결을 사용하는 DTD에 대한 룩업들을 겪게 될 경우, 당신의 classpath의 컨텐츠에 대해 당신의 DTD 선언을 체크하라. </para> + + <sect3 id="mapping-declaration-entity-resolution"> + <title>EntityResolver</title> + <para> + 앞서 언급했듯이, Hibernate는 먼저 그것의 classpath에서 DTD들을 해석하려고 시도할 것이다. + Hibernate가 이것을 행하는 방법은 그것이 xml 파일들을 읽어들이는데 사용하는 SAXReader에 맞춤형 + <literal>org.xml.sax.EntityResolver</literal> 구현을 등록하는 것이다. 이 맞춤형 + <literal>EntityResolver</literal>는 두 개의 다른 systemId namespace들을 인지해낸다. + </para> + <itemizedlist> + <listitem> + <para> + <literal>hibernate namespace</literal>는 resolver가 + <literal>http://hibernate.sourceforge.net/</literal>로 시작하는 하나의 + systemId와 만날때마다 인지된다; resolver는 Hibernate 클래스들을 로드시켰던 클래스로더를 통해 + 이들 엔티티들을 해석하려고 시도한다. + </para> + </listitem> + <listitem> + <para> + <literal>user namespace</literal>는 resolver가 <literal>classpath://</literal> + URL 프로토콜을 사용하는 systemId를 만날때마다 인지된다; resolver는 (1)현재 쓰레드 컨텍스트 + 클래스로더와 (2)Hibernate 클래스들을 로드시켰던 클래스로더를 통해 이들 엔티티들을 해석하려고 + 시도할 것이다. + </para> + </listitem> + </itemizedlist> + <para> + user namespacing을 활용하는 예제: + </para> + <programlisting><![CDATA[<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [ + <!ENTITY types SYSTEM "classpath://your/domain/types.xml"> +]> + +<hibernate-mapping package="your.domain"> + <class name="MyEntity"> + <id name="id" type="my-custom-id-type"> + ... + </id> + <class> + &types; +</hibernate-mapping>]]></programlisting> + <para> + 여기서 <literal>types.xml</literal>은 <literal>your.domain</literal> 패키지 내에 있는 리소스이고 + 맞춤형 <xref linkend="mapping-types-custom">typedef</xref>를 포함한다. + </para> + </sect3> </sect2> <sect2 id="mapping-declaration-mapping" revision="3"> @@ -692,6 +742,17 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term><literal>sequence-identity</literal></term> + <listitem> + <para> + 실제 값 생성을 위해 데이터베이스 시퀀스를 활용하지만, 생성된 식별자 값을 insert 문장 실행의 부분으로서 + 실제로 반환시키기 위해 이것을 JDBC3 getGeneratedKeys와 결합시킨 특화된 시퀀스 생성 방도. 이 방도는 + JDK 1.4에 대상화된 Oracle 10g 드라이버들 상에서만 지원되는 거승로 알려져 있다. 이들 insert 문장들에 + 대한 주석들은 Oracle 드라이버들 내에 있는 버그 때문에 사용불가능하게 되어 있음을 노트하라. + </para> + </listitem> + </varlistentry> </variablelist> </para> @@ -1082,7 +1143,7 @@ </para> </sect2> - <sect2 id="mapping-declaration-timestamp" revision="3" > + <sect2 id="mapping-declaration-timestamp" revision="4" > <title>timestamp (옵션)</title> <para> @@ -1090,7 +1151,7 @@ 버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로 어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다. </para> - + <programlistingco> <areaspec> <area id="timestamp1" coords="2 70"/> @@ -1123,7 +1184,7 @@ 가진 자바빈즈 스타일의 프로퍼티 이름. </para> </callout> - <callout arearefs="timestamp3"> + <callout arearefs="timestamp3"> <para> <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): Hibernate가 프로퍼티 값에 접근하는데 사용할 방도. @@ -1140,18 +1201,18 @@ <callout arearefs="timestamp5"> <para> <literal>source</literal> (옵션 - 디폴트는 <literal>vm</literal>): - Hibernate는 어느 장소로부터 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가? - Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야 하기 때문에 데이터베이스 기반의 - timestamp들은 오버헤드를 초래하지만, 클러스터링된 환경들의 용도로 더 안전할 것이다. 또한 모든 + Hibernate는 어디서 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가? + 데이터베이스 기반의 timestamp들은 Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야 + 하기 때문에 오버헤드를 초래하지만, 클러스터링된 환경들에서의 용도로 보다 더 안전할 것이다. 또한 모든 <literal>Dialect</literal>들이 데이터베이스의 현재의 timestamp에 대한 검색을 지원하는 것으로 알려져 - 있는 반면에, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용에 대해 안전하지 않을 + 있지 않지만, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용이 안전하지 않을 수 있음을 노트하라(예를 들면 오라클 8). </para> </callout> <callout arearefs="timestamp6"> <para> <literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>): - 이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다. + 이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 생성됨을 지정한다. <xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의들 보라. </para> </callout> Modified: trunk/Hibernate3/doc/reference/ko/modules/batch.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/batch.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/batch.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -28,8 +28,6 @@ <para> 당신은 또한 second-level 캐시를 가진 상호작용이 완전하게 불가능한 프로세스 내에서 이런 종류의 작업을 행하고 싶어할 수도 있다: - You also might like to do this kind of work in a process where interaction with - the second-level cache is completely disabled: </para> <programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting> @@ -94,7 +92,6 @@ session.close();]]></programlisting> </sect1> - <sect1 id="batch-statelesssession"> <title>StatelessSession 인터페이스</title> @@ -140,7 +137,7 @@ </sect1> - <sect1 id="batch-direct" revision="2"> + <sect1 id="batch-direct" revision="3"> <title>DML-스타일 연산들</title> <para> @@ -151,9 +148,9 @@ (<xref linkend="queryhql">HQL</xref>)를 통해 실행되는 대량 SQL-스타일의 DML 문장 실행을 위한 메소드들을 제공한다. </para> - <para> - <literal>UPDATE</literal>와 <literal>DELETE</literal> 문장들의 유사-구문은 다음과 같다: - <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지 : + <para> + <literal>UPDATE</literal>와 <literal>DELETE</literal> 문장들에 대한 유사 구문은 다음과 같다: + <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지: </para> <itemizedlist spacing="compact"> @@ -201,10 +198,34 @@ session.close();]]></programlisting> <para> - 한 개의 HQL <literal>DELETE</literal>를 실행하기 위해, 동일한 <literal>Query.executeUpdate()</literal> 메소드를 + HQL <literal>UPDATE</literal> 문장들은 디폴트로 영향받는 엔티티들에 대한 + <xref linkend="mapping-declaration-version">version</xref> 또는 + <xref linkend="mapping-declaration-timestamp">timestamp</xref> 프로퍼티 값들에 영향을 주지 않는다; + 이것은 EJB3 명세서에서 유지되고 있다. 하지만 당신은 하이버네이트로 하여금 <literal>versioned update</literal>의 + 사용을 통해 <literal>version</literal> 또는 <literal>timestamp</literal> 프로퍼티 값들을 적절하게 + 재설정하도록 강제할 수 있다. 이것은 <literal>UPDATE</literal> 키워드 뒤에 <literal>VERSIONED</literal> 키워드를 + 추가시켜서 성취된다. + </para> +<programlisting><![CDATA[Session session = sessionFactory.openSession(); +Transaction tx = session.beginTransaction(); +String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName"; +int updatedEntities = s.createQuery( hqlUpdate ) + .setString( "newName", newName ) + .setString( "oldName", oldName ) + .executeUpdate(); +tx.commit(); +session.close();]]></programlisting> + + <para> + 맞춤형 version 타입들(<literal>org.hibernate.usertype.UserVersionType</literal>)은 + <literal>update versioned</literal> 문장과 함께 사용하는 것이 허용되지 않음을 노트하라. + </para> + + <para> + HQL <literal>DELETE</literal>를 실행하려면, 같은 메소드 <literal>Query.executeUpdate()</literal>를 사용하라: </para> - + <programlisting><![CDATA[Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Modified: trunk/Hibernate3/doc/reference/ko/modules/collection_mapping.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/collection_mapping.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/collection_mapping.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -107,7 +107,7 @@ schema="schema_name" lazy="true|extra|false" inverse="true|false" - cascade="all|none|save-update|delete|all-delete-orphan" + cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan" sort="unsorted|natural|comparatorClass" order-by="column_name asc|desc" where="arbitrary sql where condition" Modified: trunk/Hibernate3/doc/reference/ko/modules/component_mapping.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/component_mapping.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/component_mapping.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -184,8 +184,7 @@ <property name="purchaseDate"/> <property name="price"/> <property name="quantity"/> - <many-to-one name="item" class="eg.Item"/> - <!-- class attribute is optional --> + <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional --> </composite-element> </set> </class>]]></programlisting> Modified: trunk/Hibernate3/doc/reference/ko/modules/configuration.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/configuration.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/configuration.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -653,9 +653,16 @@ 선택할 것이다. <para> <emphasis role="strong">eg.</emphasis> - <literal>on_close</literal> (디폴트) | <literal>after_transaction</literal> | - <literal>after_statement</literal> | <literal>auto</literal> + <literal>auto</literal> (디폴트) | <literal>on_close</literal> | + <literal>after_transaction</literal> | <literal>after_statement</literal> </para> + <para> + 이 설정이 <literal>SessionFactory.openSession</literal>로부터 반환된 <literal>Session</literal>들에만 + 영향을 준다는 점을 노트하라. <literal>SessionFactory.getCurrentSession</literal>을 통해 얻어진 + <literal>Session</literal>들의 경우, 사용하기 위해 구성된 <literal>CurrentSessionContext</literal> 구현이 + 그들 <literal>Session</literal>들에 대한 연결 해제를 제어한다. <xref linkend="architecture-current-session"/>를 + 보라. + </para> </entry> </row> <row> Modified: trunk/Hibernate3/doc/reference/ko/modules/events.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/events.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/events.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -109,6 +109,12 @@ 세션이 생성될 때 인터셉터가 지정될 것이다. </para> + <para> + <literal>Session</literal>-영역의 인터셉터는 <literal>Interceptor</literal>를 수용하는 + 하나의 세션이 오버로드된 SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때 + 지정된다. + </para> + <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting> <para> Modified: trunk/Hibernate3/doc/reference/ko/modules/example_mappings.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/example_mappings.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/example_mappings.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -538,7 +538,7 @@ </class> ]]></programlisting> </sect2> - + <sect2 id="example-mappings-content-discrimination"> <title>내용 기반 판별</title> <programlisting><![CDATA[<class name="Person" Modified: trunk/Hibernate3/doc/reference/ko/modules/inheritance_mapping.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/inheritance_mapping.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/inheritance_mapping.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -63,6 +63,7 @@ </subclass> </hibernate-mapping>]]></programlisting> + <sect2 id="inheritance-tableperclass" > <title>Table per class hierarchy</title> Modified: trunk/Hibernate3/doc/reference/ko/modules/performance.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/performance.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/performance.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -576,11 +576,24 @@ 만료되도록 구성되어 있을지라도) 또 다른 어플리케이션에 의해 영속 저장소에 대해 행해진 변경들을 결코 알지 못한다. </para> - <para> + <para revision="1"> 디폴트로, Hibernate는 JVM-레벨의 캐싱에 EHCache를 사용한다. (JCS 지원은 이제 진부하게 되었고 Hibernate의 장래 버전에서 제거될 것이다.) 당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여 <literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 다른 구현을 선택할 수도 있다. + You have the option to tell Hibernate which caching implementation to use by + specifying the name of a class that implements <literal>org.hibernate.cache.CacheProvider</literal> + using the property <literal>hibernate.cache.provider_class</literal>. Hibernate + comes bundled with a number of built-in integrations with open-source cache providers + (listed below); additionally, you could implement your own and plug it in as + outlined above. Note that versions prior to 3.2 defaulted to use EhCache as the + default cache provider; that is no longer the case as of 3.2. + 당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여 + <literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 어느 캐싱 구현을 + 사용할 것인지를 Hibernate에게 알려주는 옵션을 갖는다. Hibernate는 (아래에 열거된) 오픈-소스 프로바이더들을 가진 + 많은 빌드되어 있는 통합들을 번들로 갖고 있다; 추가적으로 당신은 위에서 언급했듯이 그것에 당신 자신의 것을 구현할 수 있고 그것에 + 플러그 시킬 수 있다. 3.2 이번 버전들은 디플트 캐시 프로바이더로서 EhCache를 사용하도록 디포릍로 내장되어 있음을 노트하라; + 버전 3.2의 경우에 그것은 더이상 디폴트 내장이 아니다. </para> <table frame="topbot" id="cacheproviders" revision="1"> Modified: trunk/Hibernate3/doc/reference/ko/modules/persistent_classes.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/persistent_classes.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/persistent_classes.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -104,6 +104,7 @@ 준수할 네 개의 주요 규칙들이 다음에 있다: </para> + <sect2 id="persistent-classes-pojo-constructor" revision="1"> <title>아규먼트 없는 생성자를 구현하라 </title> @@ -228,7 +229,8 @@ <title><literal>equals()</literal>와 <literal>hashCode()</literal> 구현하기</title> <para> - 만일 당신이 + 만일 당신이 다음의 경우라면, 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal> + 메소드들을 오버라이드 시켜야 한다. </para> <itemizedlist spacing="compact"> <listitem> @@ -244,11 +246,8 @@ </para> </listitem> </itemizedlist> + <para> - 경우에 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal> 메소드들을 오버라이드 시켜야 한다. - </para> - - <para> Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다. 따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게 만들고자 원할 경우, 우리는 <literal>equals()</literal>와 <literal>hashCode()</literal>를 구현해야 한다. @@ -432,7 +431,7 @@ </sect1> - <sect1 id="persistent-classes-tuplizers" revision="0"> + <sect1 id="persistent-classes-tuplizers" revision="1"> <title>Tuplizer들</title> <para> @@ -442,8 +441,8 @@ 그런 데이터 구조로부터 값들을 추출시키는 방법 그리고 그런 데이터구조 속으로 값들을 삽입시키는 방법을 알고 있는 것이다. 예를 들어, POJO 엔티티 모드의 경우, 대응하는 tuplizer는 그것의 생성자를 통해 POJO를 생성시키는 방법, 그리고 정의된 프로퍼티 접근자들을 사용하여 POJO 프로퍼티들에 접근하는 방법을 안다. - <literal>org.hibernate.tuple.EntityTuplizer</literal> 인터페이스와 - <literal>org.hibernate.tuple.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의 + <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> 인터페이스와 + <literal>org.hibernate.tuple.component.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의 Tuplizer들이 존재한다. <literal>EntityTuplizer</literal>들은 엔티티들에 관해서는 위에 언급된 계약들을 매핑할 책임이 있는 반면에, <literal>ComponentTuplizer</literal>들은 컴포넌트들에 대해서도 동일한 것을 행한다. </para> @@ -476,7 +475,7 @@ public class CustomMapTuplizerImpl - extends org.hibernate.tuple.DynamicMapEntityTuplizer { + extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer { // override the buildInstantiator() method to plug in our custom map... protected final Instantiator buildInstantiator( org.hibernate.mapping.PersistentClass mappingInfo) { Modified: trunk/Hibernate3/doc/reference/ko/modules/query_criteria.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/query_criteria.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/query_criteria.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -364,7 +364,6 @@ </sect1> - <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer는 -JDO2에서 setResultClass와 유사한- 임의적인 사용자 객체들을 반환하는 것을 허용한다. ResultTransformer에 대한 일반적인 사용이 또한 설명될 수 있다. --> Modified: trunk/Hibernate3/doc/reference/ko/modules/query_hql.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/query_hql.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/query_hql.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -1,5 +1,5 @@ <chapter id="queryhql"> - <title>HQL: Hibernate Query Language</title> + <title>HQL: 하이버네이트 질의 언어(Hibernate Query Language)</title> <para> Hibernate는 (아주 의도적으로) SQL과 매우 흡사하게 보이는 극히 강력한 질의 언어를 구비하고 있다. 그러나 그 구문에 의해 우롱당하지 말라; @@ -126,7 +126,7 @@ <programlisting><![CDATA[from Cat as cat left join cat.kittens as kitten with kitten.bodyWeight > 10.0]]></programlisting> - + <para> 게다가, "fetch" join은 값들을 가진 콜렉션들이나 연관관계들이 한 개의 select를 사용하여, 그것들의 부모 객체들에 따라 초기화 되는 것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관관계들과 콜렉션들에 대한 매핑 파일의 outer join과 lazy 선언들을 @@ -147,7 +147,7 @@ inner join fetch cat.mate left join fetch cat.kittens child left join fetch child.kittens]]></programlisting> - + <para> (비록 <literal>scroll()</literal>이 사용될 수 있을지라도) <literal>fetch</literal> 구조체는 <literal>iterate()</literal>를 사용하여 호출되는 질의들 내에 사용될 수 없음을 노트하라. 이들 오퍼레이션들이 결과 행들에 @@ -167,9 +167,9 @@ <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting> <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting> - + </sect1> - + <sect1 id="queryhql-joins-forms"> <title>join 구문의 형식들</title> @@ -566,39 +566,27 @@ </listitem> <listitem> <para> - 조인된 인덱싱된 콜렉션의 alias들에 적용되는, HQL <literal>index()</literal> 함수 - </para> - </listitem> - <listitem> - <para> - 콜렉션 값을 가진 경로 표현식들을 취하는 HQL 함수들 : <literal>some, all, exists, any, in</literal>을 - 사용하여 정량화 될 수 있는 특별한 <literal>elements()</literal>와 <literal>indices</literal> - 함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>. - </para> - </listitem> - <listitem> - <para> <literal>cast(... as ...)</literal>, 여기서 두번 째 아규먼트는 Hibernate 타입의 이름이고, - ANSI <literal>cast()</literal>와 <literal>extract()</literal>가 기본 데이터베이스에 의해 지원될 경우에는 - <literal>extract(... from ...)</literal> + ANSI <literal>cast()</literal>와 <literal>extract()</literal>가 기반 데이터베이스에 의해 + 지원될 경우에는 <literal>extract(... from ...)</literal>. </para> </listitem> <listitem> <para> - 조인된 인덱싱된 콜렉션의 alias들을 적용하는 HQL <literal>index()</literal> 함수 + 조인된 인덱싱된 콜렉션의 alias들에 적용되는, HQL <literal>index()</literal> 함수 </para> </listitem> <listitem> <para> - 콜렉션 값 경로 표현식들을 취하는 HQL 함수들: <literal>some, all, exists, any, in</literal>을 사용하여 - 양이 한정될 수 있는 특별한 <literal>elements()</literal> 및 <literal>indices</literal> 함수들과 함께 - <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal> 함수들. + 콜렉션 값을 가진 경로 표현식들을 취하는 HQL 함수들 : <literal>some, all, exists, any, in</literal>을 + 사용하여 정량화 될 수 있는 특별한 <literal>elements()</literal>와 <literal>indices</literal> + 함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>. </para> </listitem> <listitem> <para> <literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>, - <literal>sin()</literal>과 같이 임의의 데이터베이스-지원 SQL 스칼라 함수 + <literal>sin()</literal>과 같이 임의의 데이터베이스 지원 SQL 스칼라 함수 </para> </listitem> <listitem> @@ -867,6 +855,10 @@ <para> select 리스트 내에 있는 하나 이상의 표현식을 가진 서브질의들의 경우에 당신은 tuple 생성자를 사용할 수 있다: </para> + + <para> + select 목록 내에 하나 이상의 표현식을 가진 서브질의들의 경우, 당신은 튜플(tuple) 구조를 사용할 수 있다: + </para> <programlisting><![CDATA[from Cat as cat where not ( cat.name, cat.color ) in ( Modified: trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml =================================================================== --- trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml 2006-08-03 09:00:25 UTC (rev 10197) +++ trunk/Hibernate3/doc/reference/ko/modules/query_sql.xml 2006-08-03 14:01:28 UTC (rev 10198) @@ -1,216 +1,366 @@ <?xml version="1.0" encoding="UTF-8"?> <chapter id="querysql" revision="2"> - <title>Native SQL</title> + <title>Native SQL</title> - <para> - 당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. 당신이 오라클의 질의 힌트들 또는 - <literal>CONNECT</literal> 키워드와 같은 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다. - 그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 이전 경로를 제공한다. - </para> + <para>당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. + 당신이 오라클의 질의 힌트들 또는 <literal>CONNECT</literal> 키워드와 같은 + 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다. + 그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 + 이전 경로를 제공한다.</para> - <para> - Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 (내장 프로시저들을 포함하여) 손으로 작성된 SQL을 - 지정하는 것을 당신에게 허용해준다. - </para> + <para>Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 + (내장 프로시저들을 포함하여) 손으로 작성된 SQL을 지정하는 것을 당신에게 허용해준다.</para> - <sect1 id="querysql-creating" revision="3"> - <title><literal>SQLQuery</literal> 사용하기</title> + <sect1 id="querysql-creating" revision="4"> + <title><literal>SQLQuery</literal> 사용하기</title> - <para> - native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해 제어되며, 그것은 - <literal>Session.createSQLQuery()</literal>을 호출하여 획득된다. 극히 간단한 경우들에서 , - 우리는 다음 형식을 사용할 수 있다: - </para> + <para>native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해 + 제어되며, 그것은 <literal>Session.createSQLQuery()</literal>을 호출하여 + 획득된다. 다음은 이 API를 질의에 사용하는 방법을 설명한다.</para> - <programlisting><![CDATA[List cats = sess.createSQLQuery("select * from cats") - .addEntity(Cat.class) - .list();]]></programlisting> - - <para>이 질의는 다음을 지정했다:</para> + <sect2> + <title>스칼라 질의들</title> - <itemizedlist> + <para>가장 기본적인 SQL 질의는 스칼라들(값들)의 목록을 얻는 + 것이다.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list(); +sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list(); +]]></programlisting> + + <para>이것들은 둘다 CATS 테이블 내에 있는 각각의 컬럼에 대한 스칼라 값들을 가진 Object + 배열들의 List를 반환할 것이다. Hibernate는 반환되는 스칼라 값들의 실제 순서와 타입들을 + 도출하는데 ResultSetMetadata를 사용할 것이다.</para> + + <para><literal>ResultSetMetadata</literal> 사용의 오버헤드를 피하거나 + 간단하게는 반환되는 것을 보다 명시적이게끔 하기 위해 우리는 + <literal>addScalar()</literal>를 사용할 수 있다.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS") + .addScalar("ID", Hibernate.LONG) + .addScalar("NAME", Hibernate.STRING) + .addScalar("BIRTHDATE", Hibernate.DATE) +]]></programlisting> + + <para>이 질의는 다음을 지정했다:</para> + + <itemizedlist> <listitem> - <para> - SQL 질의 문자열 - </para> + <para>SQL 질의 문자열</para> </listitem> + <listitem> - <para> - 그 질의에 의해 반환되는 엔티티 - </para> + <para>반환할 컬럼들과 타입들</para> </listitem> - </itemizedlist> + </itemizedlist> - <para> - 여기서, 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일한 것으로 가정된다. 이것은 조인 다중 테이블들을 가진 - SQL 질의들에 대해 문제가 될 수 있다. 왜냐하면 동일한 컬럼 이름들이 하나 이상의 테이블 들 내에 나타날 수도 있기 때문이다. - 다음 형식은 컬럼 이름 중복에 대해 취약하지 않다: - </para> + <para>이것은 여전히 Object 배열들을 반환할 것이지만, 이제 그것은 + <literal>ResultSetMetdata</literal>를 사용하지 않을 것이고 대신에 + 기반 결과셋으로부터 ID, NAME 그리고 BIRTHDATE 컬럼을 각각 Long, String + 그리고 Short 타입으로 반환할 것이다. 심지어 그 질의가 <literal>*</literal>를 + 사용하고 세 개의 열거된 컬럼들 보다 더 많은 것을 반환할 수 있을지라도, 이것은 + 또한 오직 이들 세 개의 컬럼들 만이 반환될 것임을 의미한다.</para> - <programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat") - .addEntity("cat", Cat.class) - .list();]]></programlisting> + <para>스칼라들 중 몇몇 또는 전부에 대한 타입 정보를 남겨두는 것이 가능하다.</para> + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS") + .addScalar("ID", Hibernate.LONG) + .addScalar("NAME") + .addScalar("BIRTHDATE") +]]></programlisting> + + <para>이것은 본질적으로 앞의 것과 동일한 질의이지만, 이제 + <literal>ResultSetMetaData</literal>는 ID의 타입이 명시적으로 지정되어 있으므로 + NAME과 BIRTHDATE의 타입을 결정하는데 사용된다.</para> + + <para>java.sql.Types returned from ResultSetMetaData이 Hibernate + 타입들로 매핑되는 방법은 Dialect에 의해 제어된다. 만일 특정 타입이 매핑되지 않거나 + 예상되는 타입으로 귀결되지 않을 경우에 Dialect 내에 있는 + <literal>registerHibernateType</literal>에 대한 호출들을 통해 그것을 + 맞춤화 시키는 것이 가능하다.</para> + </sect2> + + <sect2> + <title>Entity 질의들</title> + + <para>위의 질의들은 스칼라 값들을 반환하는 것, 결과셋들로부터 "원래의" 값들을 + 기본적으로 반환하는 것에 대한 전부였다. 다음은 <literal>addEntity()</literal>를 + 통해 native sql 질의로부터 엔티티 객체들을 얻는 방법을 보여준다.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); +sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class); +]]></programlisting> + <para>이 질의는 다음을 지정했다:</para> - + <itemizedlist> <listitem> - <para> - Hibernate가 컬럼 alias들을 도입하기 위한, placeholder를 가진, SQL 질의 문자열 - </para> + <para>SQL 질의 문자열</para> </listitem> + <listitem> - <para> - 그 질의에 의해 반환된 엔티티와 그것의 SQL 테이블 alias - </para> + <para>그 질의에 의해 반환되는 엔티티</para> </listitem> - </itemizedlist> - - <para> - <literal>addEntity()</literal> 메소드는 SQL 테이블 alias를 반환된 엔티티 클래스와 연관지우고, - 질의 결과 셋의 형태를 결정한다. - </para> - - <para> - <literal>addJoin()</literal> 메소드는 다른 엔티티들과 콜렉션들에 대한 연관들을 로드시키는데 사용될 수 있다. - </para> - - <programlisting><![CDATA[List cats = sess.createSQLQuery( - "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" - ) - .addEntity("cat", Cat.class) - .addJoin("kitten", "cat.kittens") - .list();]]></programlisting> - - <para> - native SQL 질의는 간단한 스칼라 값을 반환하거나 스칼라들과 엔티티들의 조합을 반환할 수도 있다. - </para> + </itemizedlist> - <programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat") - .addScalar("maxWeight", Hibernate.DOUBLE); - .uniqueResult();]]></programlisting> - - <para>당신은 당신의 hbm 파일들 내에 결과셋 매핑 정보를 대안저긍로 설명활 수 있고 당신의 질의들을 위해 그것들을 - 사용할 수 있다.</para> + <para>Cat이 컬럼 ID, NAME 그리고 BIRTHDATE로서 매핑된다고 가정하면, + 위의 질의들은 둘다 각각의 요소가 하나의 Cat 엔티티인 하나의 List를 반환할 것이다.</para> - <programlisting><![CDATA[List cats = sess.createSQLQuery( - "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" - ) - .setResultSetMapping("catAndKitten") - .list();]]></programlisting> + <para>만일 그 엔티티가 또 다른 엔티티에 대해 <literal>many-to-one</literal>로 + 매핑되어 있다면 또한 native 질의를 실행할 때 이것을 반환하는 것이 필수적고, 그 밖의 경우 + 데이터베이스 지정적인 "컬럼이 발견되지 않았습니다" 오류가 일어날 것이다. 추가적인 + 컬럼은 * 표기를 사용할 자동적으로 반환될 것이지만, 우리는 다음 <literal>Dog</literal>에 + 대한 <literal>many-to-one</literal> 예제에서처럼 명시적인 것을 더 선호한다:</para> - </sect1> + <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class); +]]></programlisting> - <sect1 id="querysql-aliasreferences"> - <title>Alias 참조와 프로퍼티 참조</title> + <para>이것은 cat.getDog()이 고유하게 기능하는 것을 허용한다.</para> + <sect2> - <para> - 위에서 사용된 <literal>{cat.*}</literal> 표기는 "모든 프로퍼티"에 대한 약어이다. 다른 방법으로, 당신은 명시적으로 컬럼들을 - 리스트할 수 있지만, 심지어 이 경우 조차도 우리는 Hibernate로 하여금 각각의 프로퍼티에 대해 SQL 컬럼 alias들을 끼워넣도록 해야 한다. - 컬럼 alias에 대한 placeholder는 테이블 alias 수식어가 붙은 프로퍼티 이름이다. 다음 예제에서, 우리는 매핑 메타데이터에 선언된 - 것에 대해 다른 테이블 (<literal>cat_log</literal>)로부터 <literal>Cat</literal>들을 검색한다. 우리는 심지어 우리가 - 좋아할 경우 where 절 속에 프로퍼티 alias들을 사용할 수도 있음을 주목하라. - </para> - <para> - The <literal>{}</literal>-syntax is <emphasis>not</emphasis> required for named queries. - See <xref linkend="querysql-namedqueries"/> - </para> - - <programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " + - "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " + - "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " + - "from cat_log cat where {cat.mate} = :catId" + <sect2> + <title>연관들과 콜렉션들을 처리하기</title> + <para>프락시를 초기화 시킴에 있어 가능한 특별한 라운드트립을 피하기 위해서 + <literal>Dog</literal>에서 eagerly join시키는 것이 간으하다. 이것은 + <literal>addJoin()</literal> 메소드를 통해 행해지는데, 그것은 + 연관이나 콜렉션 내에서 조인시키는 것을 당신에게 허용해준다.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID") + .addEntity("cat", Cat.class) + .addJoin("cat.dog"); +]]></programlisting> + + <para>이 예제에서 반환되는 <literal>Cat</literal>들은 데이터베이스에 + 대한 임의의 특별한 라운드크립 없이 전체적으로 초기화된 그것들의 <literal>dog</literal> + 프로퍼티를 갖는다. 우리가 join의 대상 프로퍼티 경로를 지정하는 것을 가능하도록 하기 위해 + 하나의 alias 이름("cat")을 추가했음을 주지하라. 대신에 예를 들어 <literal>Cat</literal>이 + <literal>Dog</literal>에 대해 one-to-many를 가질 경우, 콜렉션들에 대해 동일한 eager joining을 + 행하는 것이 가능하다.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID") + .addEntity("cat", Cat.class) + .addJoin("cat.dogs"); +]]></programlisting> + + <p>이 단계에서 우리는 Hibernate에서 native 질의들을 사용가능하도록 만들기 위해 + sql 질의들을 강화시키지는 것을 시작하지 않고서도 native 질의들로서 가능한 것의 한계에 + 도달하고 있다; 문제점들은 동일한 타입의 여러 엔티티들을 반환할 때 또는 디폴트 alias/column + 이름들이 충분하지 않을 때 발생하기 시작한다.</p> + </sect2> + + <sect2> + <title>여러 개의 엔티티들을 반환하기</title> + + <para>지금까지 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일하다고 가정되어 있다. + 동일한 컬럼이 하나 이상의 테이블 내에서 나타날 수 있기 때문에, 이것은 여러 개의 테이블들을 조인시키는 + SQL 질의들에 대해 문제가 될 수 있다.</para> + + <para>컬럼 alias 주입은 다음 질의(아마 실패할 것이다)에서 필요하다:</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class) +]]></programlisting> + + <para>이 질의의 목적은 단위 행 당 두 개의 Cat 인스턴스들, 하나의 cat 그리고 그것의 mother를 + 반환하는 것이다. 왜냐하면 그것들이 동일한 컬럼 이름들로 매핑되어 있기 때문에 이것은 실패할 것이고 + 데이베이스 상에서 반환된 컬럼 alias들은 아마 매핑들 내에 지정된 컬럼들("ID" 와 "NAME")과 같지 않은 + "c.ID", "c.NAME" 등의 형식일 것이다.</para> + + <para>다음 형식은 컬럼 이름 중복 취약점을 갖지 않는다:</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class) +]]></programlisting> + + <para>이 질의는 다음을 지정했다:</para> + + <itemizedlist> + <listitem> + <para>컬럼 alias들을 주입하기 위한 Hibernate용 placeholder들을 가진 SQL 질의 문자열</para> + </listitem> + + <listitem> + <para>그 질의에 의해 반환되는 엔티티들</para> + </listitem> + </itemizedlist> + + <para>위에 사용된 {cat.*} 과 {mother.*} 표기는 "모든 프로퍼티들"에 대한 생략이다. + 다른 방법으로 당신은 컬럼들을 명시적으로 열거할 수도 있지만, 이 경우에 우리는 Hibernate로 하여금 + SQL 컬럼 alias들을 각각의 컬럼에 주입시키도록 강제한다. 컬럼 alias를 위한 placeholder는 단지 + 그 테이블 alias에 의해 수식된 프로퍼티 이름이다. 다음 예제에서, 우리는 다른 테이블(cat_log)로부터 + 매핑 메타데이터 내에 선언된 것으로의 Cat들과 그것들의 mother들을 검색한다. 우리는 우리가 좋다면 + 심지어 where 절 내에 프로퍼티 alias를 사용할 수도 있음을 주지하라.</para> + + <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + + "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " + + "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID"; + List loggedCats = sess.createSQLQuery(sql) - .addEntity("cat", Cat.class) - .setLong("catId", catId) - .list();]]></programlisting> + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class).list() +]]></programlisting> + <sect3 id="querysql-aliasreferences" revision="2"> + <title>alias 참조와 프로퍼티 참조</title> + + <para>대부분의 경우에 위의 alias 주입이 필요하지만, composite 프로퍼티들, 상속 판별자들 + (inheritance discriminators), 콜렉션 등과 같은 보다 복잡한 매핑들과 관련된 질의들의 경우에는 + 고유한 alias들을 주입시키는 것을 Hibernate에게 허용하는데 사용될 몇몇 특별한 alias들이 존재한다.</para> + + <para>다음 테이블은 alias 주입을 사용하는 다른 가능성들을 보여준다. 노트: 결과 내에 있는 alias 이름들이 + 예제이며, 각각의 alias는 사용될 때 하나의 유일한 이름과 아마 다른 이름을 가질 것이다.</para> + + <table frame="topbot" id="aliasinjection-summary"> + <title>alias 주입 이름들</title> + + <tgroup cols="3"> + <colspec colwidth="1*" /> + + <colspec colwidth="1*" /> + + <colspec colwidth="2.5*" /> + + <thead> + <row> + <entry>설명</entry> + + <entry>구문</entry> + + <entry>예제</entry> + </row> + </thead> + + <tbody> + <row> + <entry>간단한 프로퍼티</entry> + <entry><literal>{[aliasname].[propertyname]</literal></entry> + + <entry><literal>A_NAME as {item.name}</literal></entry> + </row> + + <row> + <entry>composite 프로퍼티</entry> + + <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry> + + <entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry> + </row> + + <row> + <entry>엔티티의 판별자(Discriminator)</entry> + <entry><literal>{[aliasname].class}</literal></entry> + + <entry><literal>DISC as {item.class}</literal></entry> + </row> + + <row> + <entry>엔티티의 모든 프로퍼티들</entry> + <entry><literal>{[aliasname].*}</literal></entry> + + <entry><literal>{item.*}</literal></entry> + </row> + + <row> + <entry>콜렉션 키</entry> + <entry><literal>{[aliasname].key}</literal></entry> + + <entry><literal>ORGID as {coll.key}</literal></entry> + </row> + + <row> + <entry>콜렉션의 id</entry> + <entry><literal>{[aliasname].id}</literal></entry> + + <entry><literal>EMPID as {coll.id}</literal></entry> + </row> + + <row> + <entry>콜렉션의 요소</entry> + <entry><literal>{[aliasname].element}</literal></entry> + + <entry><literal>XID as {coll.element}</literal></entry> + <entry></entry> + </row> + + <row> + <entry>콜렉션 내에 있는 요소의 프로퍼티</entry> + <entry><literal>{[aliasname].element.[propertyname]}</literal></entry> + + <entry><literal>NAME as {coll.element.name}</literal></entry> + </row> + + <row> + <entry>콜렉션 내에 있는 요소의 모든 프로퍼티들</entry> + <entry><literal>{[aliasname].element.*}</literal></entry> + + <entry><literal>{coll.element.*}</literal></entry> + </row> + + <row> + <entry>콜렉션의 모든 프로퍼티들</entry> + <entry><literal>{[aliasname].*}</literal></entry> + + <entry><literal>{coll.*}</literal></entry> + </row> + </tbody> + </tgroup> + </table> + </sect3> + </sect2> + + <sect2> + <title>non-managed 엔티티들을 반환하기</title> + + <para>native sql 질의에 ResultTransformer를 적용하는 것이 가능하다. 예를 들어 + non-managed 엔티티들을 반환하기 위해 ResultTransformer를 허용하는 것.</para> + + <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") + .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting> + + <para>이 질의는 다음을 지정했다:</para> + + <itemizedlist> + <listitem> + <para>SQL 질의 문자열</para> + </listitem> + + <listitem> + <para>결과 변환자(transformer)</para> + </listitem> + </itemizedlist> + <para> - <emphasis>노트:</emphasis> 만일 당신이 각각의 프로퍼티를 명시적으로 리스트할 경우, 당신은 그 클래스와 - <emphasis>그것의 서브클래스들</emphasis>의 모든 프로퍼티들을 포함해야 한다! + 위의 질의는 초기화되어 있고 NAME과 BIRTHNAME의 값들을 <literal>CatDTO</literal>의 + 대응하는 프로퍼티들과 필드들 속으로 주입시킨 <literal>CatDTO</literal>의 리스트를 반환할 것이다. </para> - <para> - 다음 테이블은 alias injection을 사용하는 다른 가능성들을 보여준다. 노트 : 결과 내에서 alias 이름들이 예제들이며, 각각의 alias는 - 사용될 시에 하나의 유일한 그리고 가능한 다른 이름을 가질 것이다. - </para> + </sect2> - <table frame="topbot" id="aliasinjection-summary"> - <title>Alias injection 이름들</title> - - <tgroup cols="4"> - <colspec colwidth="1*"/> - - <colspec colwidth="1*"/> - - <colspec colwidth="2.5*"/> - - <thead> - <row> - <entry>설명</entry> - <entry>구문</entry> - <entry>예제</entry> - </row> - </thead> - <tbody> - <row> - <entry>간단한 프로퍼티</entry> - <entry><literal>{[aliasname].[propertyname]</literal></entry> - <entry><literal>A_NAME as {item.name}</literal></entry> - </row> - <row> - <entry>composite 프로퍼티</entry> - <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry> - <entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry> - </row> - <row> - <entry>엔티티의 판별자(Discriminator)</entry> - <entry><literal>{[aliasname].class}</literal></entry> - <entry><literal>DISC as {item.class}</literal></entry> - </row> - <row> - <entry>엔티티의 모든 프로퍼티들</entry> - <entry><literal>{[aliasname].*}</literal></entry> - <entry><literal>{item.*}</literal></entry> - </row> - <row> - <entry>콜렉션 키</entry> - <entry><literal>{[aliasname].key}</literal></entry> - <entry><literal>ORGID as {coll.key}</literal></entry> - </row> - <row> - <entry>콜렉션의 id</entry> - <entry><literal>{[aliasname].id}</literal></entry> - <entry><literal>EMPID as {coll.id}</literal></entry> - </row> - <row> - <entry>콜렉션의 요소</entry> - <entry><literal>{[aliasname].element}</literal></entry> - <entry><literal>XID as {coll.element}</literal></entry> - <entry></entry> - </row> - <row> - <entry>콜렉션 내에 있는 요소의 프로퍼티</entry> - <entry><literal>{[aliasname].element.[propertyname]}</literal></entry> - <entry><literal>NAME as {coll.element.name}</literal></entry> - </row> - - <row> - <entry>콜렉션 내에 있는 요소의 모든 프로퍼티들</entry> - <entry><literal>{[aliasname].element.*}</literal></entry> - <entry><literal>{coll.element.*}</literal></entry> - </row> - <row> - <entry>콜렉션의 모든 프로퍼티들</entry> - <entry><literal>{[aliasname].*}</literal></entry> - <entry><literal>{coll.*}</literal></entry> - </row> - </tbody> - </tgroup> - </table> + <sect2> + <title>상속 처리하기</title> + <para>상속의 부분으로서 매핑되는 엔티티들을 질의하는 native sql 질의들은 baseclass의 + 모든 프로퍼티들을 포함해야 하고 그 모든 것이 서브클래스화 되어야 한다.</para> + </sect2> + + <sect2> + <title>파라미터들</title> + + <para>Native sql 질의들은 위치 파라미터들 뿐만 아니라 명명된 파라미터들을 지원한다:</para> + + <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class); +List pusList = query.setString(0, "Pus%").list(); + +query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class); +List pusList = query.setString("name", "Pus%").list(); ]]></programlisting> + </sect2> + + + </sect1> - + <sect1 id="querysql-namedqueries" revision="3"> <title>명명된 SQL 질의들</title> @@ -219,7 +369,7 @@ <literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>. </para> - <programlisting><![CDATA[<sql-query name="persons"> + <programlisting><![CDATA[<sql-query name="persons"> <return alias="person" class="eg.Person"/> SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, @@ -228,16 +378,17 @@ WHERE person.NAME LIKE :namePattern </sql-query>]]></programlisting> - <programlisting><![CDATA[List people = sess.getNamedQuery("persons") + <programlisting><![CDATA[List people = sess.getNamedQuery("persons") .setString("namePattern", namePattern) .setMaxResults(50) .list();]]></programlisting> - <para> - The <literal><return-join></literal> 요소와 <literal><load-collection></literal> - 요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을 정의하는데 사용된다. - </para> + + <para><literal><return-join></literal> 요소와 + <literal><load-collect... [truncated message content] |
From: <hib...@li...> - 2006-08-03 09:00:28
|
Author: max...@jb... Date: 2006-08-03 05:00:25 -0400 (Thu, 03 Aug 2006) New Revision: 10197 Modified: trunk/HibernateExt/tools/src/templates/seam/selector.java.ftl Log: HBX-721 and JBIDE-345 for incorrect resourcebundle issue with seam templates Modified: trunk/HibernateExt/tools/src/templates/seam/selector.java.ftl =================================================================== --- trunk/HibernateExt/tools/src/templates/seam/selector.java.ftl 2006-08-03 07:53:27 UTC (rev 10196) +++ trunk/HibernateExt/tools/src/templates/seam/selector.java.ftl 2006-08-03 09:00:25 UTC (rev 10197) @@ -23,7 +23,7 @@ @${pojo.importType("javax.interceptor.Interceptors")}(${pojo.importType("org.jboss.seam.ejb.SeamInterceptor")}.class) public static class Default${pojo.shortName}Selector implements ${pojo.shortName}Selector { - @${pojo.importType("org.jboss.seam.annotations.In")} + @${pojo.importType("org.jboss.seam.annotations.In")}(create=true) private transient ${pojo.importType("java.util.ResourceBundle")} resourceBundle; @${pojo.importType("org.jboss.seam.annotations.In")}(create=true) |
From: <hib...@li...> - 2006-08-03 07:53:34
|
Author: max...@jb... Date: 2006-08-03 03:53:27 -0400 (Thu, 03 Aug 2006) New Revision: 10196 Modified: trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java trunk/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java trunk/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java trunk/Hibernate3/src/org/hibernate/cfg/SecondPass.java Log: removal of nonused parameter due to HHH-1963 Modified: trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) +++ trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-03 07:53:27 UTC (rev 10196) @@ -35,7 +35,7 @@ this(mappings, collection, Collections.EMPTY_MAP); } - public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) + public void doSecondPass(java.util.Map persistentClasses) throws MappingException { if ( log.isDebugEnabled() ) log.debug( "Second pass for collection: " + collection.getRole() ); Modified: trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-03 07:53:15 UTC (rev 10195) +++ trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-03 07:53:27 UTC (rev 10196) @@ -1051,7 +1051,7 @@ while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); if ( ! (sp instanceof QuerySecondPass) ) { - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); + sp.doSecondPass( classes ); iter.remove(); } } @@ -1060,7 +1060,7 @@ iter = secondPasses.iterator(); while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); + sp.doSecondPass( classes ); iter.remove(); } Modified: trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-03 07:53:15 UTC (rev 10195) +++ trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-03 07:53:27 UTC (rev 10196) @@ -2703,7 +2703,7 @@ this.manyToOne = manyToOne; } - public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException { + public void doSecondPass(java.util.Map persistentClasses) throws MappingException { manyToOne.createPropertyRefConstraints(persistentClasses); } Modified: trunk/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) +++ trunk/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java 2006-08-03 07:53:27 UTC (rev 10196) @@ -29,7 +29,7 @@ this.mappings = mappings; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { String queryName = queryElem.attribute( "name" ).getValue(); if (path!=null) queryName = path + '.' + queryName; Modified: trunk/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) +++ trunk/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java 2006-08-03 07:53:27 UTC (rev 10196) @@ -21,7 +21,7 @@ this.mappings = mappings; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { ResultSetMappingDefinition definition = buildResultSetMappingDefinition( element, path, mappings); mappings.addResultSetMapping( definition ); } Modified: trunk/Hibernate3/src/org/hibernate/cfg/SecondPass.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/SecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) +++ trunk/Hibernate3/src/org/hibernate/cfg/SecondPass.java 2006-08-03 07:53:27 UTC (rev 10196) @@ -12,7 +12,7 @@ */ public interface SecondPass extends Serializable { - void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) + void doSecondPass(java.util.Map persistentClasses) throws MappingException; } |
From: <hib...@li...> - 2006-08-03 07:53:24
|
Author: max...@jb... Date: 2006-08-03 03:53:15 -0400 (Thu, 03 Aug 2006) New Revision: 10195 Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationConfiguration.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/CreateKeySecondPass.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/FkSecondPass.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/IndexSecondPass.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/OneToOneSecondPass.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java Log: removal of nonused parameter due to HHH-1963 Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationConfiguration.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationConfiguration.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationConfiguration.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -6,7 +6,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -285,7 +284,7 @@ SecondPass sp = (SecondPass) iter.next(); //do the second pass of fk before the others and remove them if ( sp instanceof FkSecondPass ) { - sp.doSecondPass( classes, Collections.EMPTY_MAP ); // TODO: align meta-attributes with normal bind... + sp.doSecondPass( classes ); iter.remove(); } } @@ -294,7 +293,7 @@ SecondPass sp = (SecondPass) iter.next(); //do the second pass of fk before the others and remove them if ( sp instanceof CreateKeySecondPass ) { - sp.doSecondPass( classes, Collections.EMPTY_MAP ); // TODO: align meta-attributes with normal bind... + sp.doSecondPass( classes ); iter.remove(); } } Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/CreateKeySecondPass.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/CreateKeySecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/CreateKeySecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -22,7 +22,7 @@ this.joinedSubClass = joinedSubClass; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { if ( rootClass != null ) { rootClass.createPrimaryKey(); } Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/FkSecondPass.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/FkSecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/FkSecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -32,7 +32,7 @@ this.path = path; } - public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException { + public void doSecondPass(java.util.Map persistentClasses) throws MappingException { if ( value instanceof ManyToOne ) { ManyToOne manyToOne = (ManyToOne) value; PersistentClass ref = (PersistentClass) persistentClasses.get( manyToOne.getReferencedEntityName() ); Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/IndexSecondPass.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/IndexSecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/IndexSecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -33,7 +33,7 @@ this.mappings = mappings; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { if ( columns != null ) { for ( String columnName : columns ) { addIndexToColumn( columnName ); Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/OneToOneSecondPass.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/OneToOneSecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/OneToOneSecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -59,7 +59,7 @@ } //TODO refactor this code, there is a lot of duplication in this method - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { org.hibernate.mapping.OneToOne value = new org.hibernate.mapping.OneToOne( propertyHolder.getTable(), propertyHolder.getPersistentClass() ); @@ -105,7 +105,7 @@ value, joinColumns, !optional, //cannot have nullabe and unique on certain DBs path, mappings - ) ).doSecondPass( persistentClasses, inheritedMetas ); + ) ).doSecondPass( persistentClasses ); //no column associated since its a one to one propertyHolder.addProperty( prop ); } Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -359,7 +359,7 @@ || property.isAnnotationPresent( CollectionOfElements.class ) ) { // do it right away, otherwise @ManyToon on composite element call addSecondPass // and raise a ConcurrentModificationException - sp.doSecondPass( CollectionHelper.EMPTY_MAP, CollectionHelper.EMPTY_MAP ); + sp.doSecondPass( CollectionHelper.EMPTY_MAP ); } else { mappings.addSecondPass( sp, ! isMappedBy ); Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java 2006-08-03 07:53:15 UTC (rev 10195) @@ -46,7 +46,7 @@ this.isDefault = isDefault; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { //TODO add parameters checkings if ( ann == null ) return; ResultSetMappingDefinition definition = new ResultSetMappingDefinition( ann.name() ); |
From: <hib...@li...> - 2006-08-03 07:53:14
|
Author: max...@jb... Date: 2006-08-03 03:53:09 -0400 (Thu, 03 Aug 2006) New Revision: 10194 Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/SecondPass.java Log: removal of nonused parameter due to HHH-1963 Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-03 07:34:29 UTC (rev 10193) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) @@ -35,7 +35,7 @@ this(mappings, collection, Collections.EMPTY_MAP); } - public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) + public void doSecondPass(java.util.Map persistentClasses) throws MappingException { if ( log.isDebugEnabled() ) log.debug( "Second pass for collection: " + collection.getRole() ); Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-03 07:34:29 UTC (rev 10193) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-03 07:53:09 UTC (rev 10194) @@ -1051,7 +1051,7 @@ while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); if ( ! (sp instanceof QuerySecondPass) ) { - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); + sp.doSecondPass( classes ); iter.remove(); } } @@ -1060,7 +1060,7 @@ iter = secondPasses.iterator(); while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); + sp.doSecondPass( classes ); iter.remove(); } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-03 07:34:29 UTC (rev 10193) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-03 07:53:09 UTC (rev 10194) @@ -2703,7 +2703,7 @@ this.manyToOne = manyToOne; } - public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException { + public void doSecondPass(java.util.Map persistentClasses) throws MappingException { manyToOne.createPropertyRefConstraints(persistentClasses); } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java 2006-08-03 07:34:29 UTC (rev 10193) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/NamedSQLQuerySecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) @@ -29,7 +29,7 @@ this.mappings = mappings; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { String queryName = queryElem.attribute( "name" ).getValue(); if (path!=null) queryName = path + '.' + queryName; Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java 2006-08-03 07:34:29 UTC (rev 10193) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/ResultSetMappingSecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) @@ -21,7 +21,7 @@ this.mappings = mappings; } - public void doSecondPass(Map persistentClasses, Map inheritedMetas) throws MappingException { + public void doSecondPass(Map persistentClasses) throws MappingException { ResultSetMappingDefinition definition = buildResultSetMappingDefinition( element, path, mappings); mappings.addResultSetMapping( definition ); } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/SecondPass.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/SecondPass.java 2006-08-03 07:34:29 UTC (rev 10193) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/SecondPass.java 2006-08-03 07:53:09 UTC (rev 10194) @@ -12,7 +12,7 @@ */ public interface SecondPass extends Serializable { - void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) + void doSecondPass(java.util.Map persistentClasses) throws MappingException; } |
From: <hib...@li...> - 2006-08-03 07:34:34
|
Author: max...@jb... Date: 2006-08-03 03:34:29 -0400 (Thu, 03 Aug 2006) New Revision: 10193 Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java Log: make code legal ;) Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java 2006-08-02 15:05:52 UTC (rev 10192) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java 2006-08-03 07:34:29 UTC (rev 10193) @@ -40,7 +40,7 @@ public DirectoryProvider<?> createDirectoryProvider(Class<?> entity, Configuration cfg) { //get properties Properties indexProps = getDirectoryProperties( cfg, entity ); - + //set up the directory String className = indexProps.getProperty( "directory_provider" ); if ( StringHelper.isEmpty( className ) ) { @@ -73,8 +73,8 @@ String indexName = LUCENE_PREFIX + getTypeName( entity ); Properties indexProps = new Properties(); Properties indexSpecificProps = new Properties(); - for ( Map.Entry<String, ?> entry : ( (Map<String, ?>) props ).entrySet() ) { - String key = entry.getKey(); + for ( Map.Entry entry : props.entrySet() ) { + String key = (String) entry.getKey(); if ( key.startsWith( LUCENE_DEFAULT ) ) { indexProps.setProperty( key.substring( LUCENE_DEFAULT.length() ), (String) entry.getValue() ); } |
From: <hib...@li...> - 2006-08-02 15:06:01
|
Author: max...@jb... Date: 2006-08-02 11:05:52 -0400 (Wed, 02 Aug 2006) New Revision: 10192 Modified: trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java trunk/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java trunk/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml Log: HHH-1963 meta inheritance is broken HBX-719 Modified: trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-02 15:05:40 UTC (rev 10191) +++ trunk/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-02 15:05:52 UTC (rev 10192) @@ -1,7 +1,9 @@ //$Id$ package org.hibernate.cfg; +import java.util.Collections; import java.util.Iterator; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,18 +23,24 @@ private static Log log = LogFactory.getLog( CollectionSecondPass.class ); Mappings mappings; Collection collection; + private Map localInheritedMetas; - public CollectionSecondPass(Mappings mappings, Collection collection) { + public CollectionSecondPass(Mappings mappings, Collection collection, java.util.Map inheritedMetas) { this.collection = collection; this.mappings = mappings; + this.localInheritedMetas = inheritedMetas; } + public CollectionSecondPass(Mappings mappings, Collection collection) { + this(mappings, collection, Collections.EMPTY_MAP); + } + public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException { if ( log.isDebugEnabled() ) log.debug( "Second pass for collection: " + collection.getRole() ); - secondPass( persistentClasses, inheritedMetas ); + secondPass( persistentClasses, localInheritedMetas ); // using local since the inheritedMetas at this point is not the correct map since it is always the empty map collection.createAllKeys(); if ( log.isDebugEnabled() ) { Modified: trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-02 15:05:40 UTC (rev 10191) +++ trunk/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-02 15:05:52 UTC (rev 10192) @@ -1051,7 +1051,7 @@ while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); if ( ! (sp instanceof QuerySecondPass) ) { - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); // TODO: align meta-attributes with normal bind... + sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); iter.remove(); } } @@ -1060,7 +1060,7 @@ iter = secondPasses.iterator(); while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); // TODO: align meta-attributes with normal bind... + sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); iter.remove(); } Modified: trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-02 15:05:40 UTC (rev 10191) +++ trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-02 15:05:52 UTC (rev 10192) @@ -2,6 +2,7 @@ package org.hibernate.cfg; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -1287,7 +1288,7 @@ * Called for all collections */ public static void bindCollection(Element node, Collection collection, String className, - String path, Mappings mappings) throws MappingException { + String path, Mappings mappings, java.util.Map inheritedMetas) throws MappingException { // ROLENAME collection.setRole(path); @@ -1438,20 +1439,21 @@ handleCustomSQL( node, collection ); // set up second pass if ( collection instanceof List ) { - mappings.addSecondPass( new ListSecondPass( node, mappings, (List) collection ) ); + mappings.addSecondPass( new ListSecondPass( node, mappings, (List) collection, inheritedMetas ) ); } else if ( collection instanceof Map ) { - mappings.addSecondPass( new MapSecondPass( node, mappings, (Map) collection ) ); + mappings.addSecondPass( new MapSecondPass( node, mappings, (Map) collection, inheritedMetas ) ); } else if ( collection instanceof IdentifierCollection ) { mappings.addSecondPass( new IdentifierCollectionSecondPass( node, mappings, - collection + collection, + inheritedMetas ) ); } else { - mappings.addSecondPass( new CollectionSecondPass( node, mappings, collection ) ); + mappings.addSecondPass( new CollectionSecondPass( node, mappings, collection, inheritedMetas ) ); } Iterator iter = node.elementIterator( "filter" ); @@ -1669,9 +1671,9 @@ * Called for arrays and primitive arrays */ public static void bindArray(Element node, Array array, String prefix, String path, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { - bindCollection( node, array, prefix, path, mappings ); + bindCollection( node, array, prefix, path, mappings, inheritedMetas ); Attribute att = node.attribute( "element-class" ); if ( att != null ) array.setElementClassName( getClassName( att, mappings ) ); @@ -1770,7 +1772,8 @@ component.setEmbedded( isEmbedded ); component.setRoleName( path ); - component.setMetaAttributes( getMetas( node, inheritedMetas ) ); + inheritedMetas = getMetas( node, inheritedMetas ); + component.setMetaAttributes( inheritedMetas ); Attribute classNode = isIdentifierMapper ? null : node.attribute( "class" ); if ( classNode != null ) { @@ -1823,7 +1826,7 @@ subnode, subpath, component.getOwner(), - mappings + mappings, inheritedMetas ); mappings.addCollection( collection ); value = collection; @@ -2048,7 +2051,7 @@ subnode, StringHelper.qualify( entityName, propertyName ), persistentClass, - mappings + mappings, inheritedMetas ); mappings.addCollection( collection ); value = collection; @@ -2639,8 +2642,8 @@ static class CollectionSecondPass extends org.hibernate.cfg.CollectionSecondPass { Element node; - CollectionSecondPass(Element node, Mappings mappings, Collection collection) { - super(mappings, collection); + CollectionSecondPass(Element node, Mappings mappings, Collection collection, java.util.Map inheritedMetas) { + super(mappings, collection, inheritedMetas); this.node = node; } @@ -2657,8 +2660,8 @@ } static class IdentifierCollectionSecondPass extends CollectionSecondPass { - IdentifierCollectionSecondPass(Element node, Mappings mappings, Collection collection) { - super( node, mappings, collection ); + IdentifierCollectionSecondPass(Element node, Mappings mappings, Collection collection, java.util.Map inheritedMetas) { + super( node, mappings, collection, inheritedMetas ); } public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) @@ -2675,8 +2678,8 @@ } static class MapSecondPass extends CollectionSecondPass { - MapSecondPass(Element node, Mappings mappings, Map collection) { - super( node, mappings, collection ); + MapSecondPass(Element node, Mappings mappings, Map collection, java.util.Map inheritedMetas) { + super( node, mappings, collection, inheritedMetas ); } public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) @@ -2707,8 +2710,8 @@ } static class ListSecondPass extends CollectionSecondPass { - ListSecondPass(Element node, Mappings mappings, List collection) { - super( node, mappings, collection ); + ListSecondPass(Element node, Mappings mappings, List collection, java.util.Map inheritedMetas) { + super( node, mappings, collection, inheritedMetas ); } public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) @@ -2729,7 +2732,7 @@ private String xmlTag; public abstract Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException; + Mappings mappings, java.util.Map inheritedMetas) throws MappingException; CollectionType(String xmlTag) { this.xmlTag = xmlTag; @@ -2741,57 +2744,57 @@ private static final CollectionType MAP = new CollectionType( "map" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Map map = new Map( owner ); - bindCollection( node, map, owner.getEntityName(), path, mappings ); + bindCollection( node, map, owner.getEntityName(), path, mappings, inheritedMetas ); return map; } }; private static final CollectionType SET = new CollectionType( "set" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Set set = new Set( owner ); - bindCollection( node, set, owner.getEntityName(), path, mappings ); + bindCollection( node, set, owner.getEntityName(), path, mappings, inheritedMetas ); return set; } }; private static final CollectionType LIST = new CollectionType( "list" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { List list = new List( owner ); - bindCollection( node, list, owner.getEntityName(), path, mappings ); + bindCollection( node, list, owner.getEntityName(), path, mappings, inheritedMetas ); return list; } }; private static final CollectionType BAG = new CollectionType( "bag" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Bag bag = new Bag( owner ); - bindCollection( node, bag, owner.getEntityName(), path, mappings ); + bindCollection( node, bag, owner.getEntityName(), path, mappings, inheritedMetas ); return bag; } }; private static final CollectionType IDBAG = new CollectionType( "idbag" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { IdentifierBag bag = new IdentifierBag( owner ); - bindCollection( node, bag, owner.getEntityName(), path, mappings ); + bindCollection( node, bag, owner.getEntityName(), path, mappings, inheritedMetas ); return bag; } }; private static final CollectionType ARRAY = new CollectionType( "array" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Array array = new Array( owner ); - bindArray( node, array, owner.getEntityName(), path, mappings ); + bindArray( node, array, owner.getEntityName(), path, mappings, inheritedMetas ); return array; } }; private static final CollectionType PRIMITIVE_ARRAY = new CollectionType( "primitive-array" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { PrimitiveArray array = new PrimitiveArray( owner ); - bindArray( node, array, owner.getEntityName(), path, mappings ); + bindArray( node, array, owner.getEntityName(), path, mappings, inheritedMetas ); return array; } }; @@ -2854,10 +2857,18 @@ String name = metaNode.attributeValue( "attribute" ); MetaAttribute meta = (MetaAttribute) map.get( name ); - if ( meta == null ) { + MetaAttribute inheritedAttribute = (MetaAttribute) inheritedMeta.get( name ); + if ( meta == null ) { meta = new MetaAttribute( name ); map.put( name, meta ); - } + } else if (meta == inheritedAttribute) { // to prevent mutation of the inherited meta attribute. + meta = new MetaAttribute( name ); + map.put( name, meta ); + java.util.List values = inheritedAttribute.getValues(); + for (Iterator iterator = values.iterator(); iterator.hasNext();) { + meta.addValue( (String) iterator.next() ); + } + } meta.addValue( metaNode.getText() ); } return map; Modified: trunk/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java 2006-08-02 15:05:40 UTC (rev 10191) +++ trunk/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java 2006-08-02 15:05:52 UTC (rev 10192) @@ -10,7 +10,9 @@ import org.hibernate.MappingException; import org.hibernate.cfg.Configuration; +import org.hibernate.mapping.Bag; import org.hibernate.mapping.Collection; +import org.hibernate.mapping.Component; import org.hibernate.mapping.MetaAttribute; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; @@ -30,7 +32,7 @@ } public String[] getMappings() { - return new String[] { "legacy/Wicked.hbm.xml" }; + return new String[] { "legacy/Wicked.hbm.xml"}; } void buildConfiguration(String[] files) throws MappingException { @@ -46,7 +48,6 @@ throw e; } - } protected void setUp() throws Exception { @@ -108,6 +109,91 @@ } + // HBX-718 + public void testNonMutatedInheritance() { + Configuration cfg = getCfg(); + cfg.buildMappings(); + + PersistentClass cm = cfg.getClassMapping("org.hibernate.test.legacy.Wicked"); + MetaAttribute metaAttribute = cm.getMetaAttribute( "globalmutated" ); + + assertNotNull(metaAttribute); + assertEquals( metaAttribute.getValues().size(), 2 ); + assertEquals( "top level", metaAttribute.getValues().get(0) ); + assertEquals( "wicked level", metaAttribute.getValues().get(1) ); + + Property property = cm.getProperty( "component" ); + MetaAttribute propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 3 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount level", propertyAttribute.getValues().get(2) ); + + org.hibernate.mapping.Component component = (Component)property.getValue(); + property = component.getProperty( "x" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 4 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount level", propertyAttribute.getValues().get(2) ); + assertEquals( "monetaryamount x level", propertyAttribute.getValues().get(3) ); + + property = cm.getProperty( "sortedEmployee" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 3 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "sortedemployee level", propertyAttribute.getValues().get(2) ); + + property = cm.getProperty( "anotherSet" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 2 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + + Bag bag = (Bag) property.getValue(); + component = (Component)bag.getElement(); + + assertEquals(4,component.getMetaAttributes().size()); + + metaAttribute = component.getMetaAttribute( "globalmutated" ); + assertEquals( metaAttribute.getValues().size(), 3 ); + assertEquals( "top level", metaAttribute.getValues().get(0) ); + assertEquals( "wicked level", metaAttribute.getValues().get(1) ); + assertEquals( "monetaryamount anotherSet composite level", metaAttribute.getValues().get(2) ); + + property = component.getProperty( "emp" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 4 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount anotherSet composite level", propertyAttribute.getValues().get(2) ); + assertEquals( "monetaryamount anotherSet composite property emp level", propertyAttribute.getValues().get(3) ); + + + property = component.getProperty( "empinone" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 4 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount anotherSet composite level", propertyAttribute.getValues().get(2) ); + assertEquals( "monetaryamount anotherSet composite property empinone level", propertyAttribute.getValues().get(3) ); + + + } + public void testComparator() { Configuration cfg = getCfg(); cfg.buildMappings(); Modified: trunk/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml 2006-08-02 15:05:40 UTC (rev 10191) +++ trunk/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml 2006-08-02 15:05:52 UTC (rev 10192) @@ -7,6 +7,8 @@ <hibernate-mapping default-lazy="false"> <meta attribute="global">global value</meta> <meta attribute="globalnoinherit" inherit="false">only visible at top level</meta> + <meta attribute="globalmutated">top level</meta> + <class name="org.hibernate.test.legacy.Wicked" table="WICKED" schema="HR"> @@ -14,7 +16,7 @@ <meta attribute="implements">java.lang.Observer</meta> <meta attribute="implements" inherit="false">org.foo.BogusVisitor</meta> <meta attribute="extends">AuditInfo</meta> - + <meta attribute="globalmutated">wicked level</meta> <id name="id" type="long" column="EMPLOYEE_ID"> @@ -31,14 +33,30 @@ <component name="component" class="net.sf.hibern8ide.test.MonetaryAmount"> <meta attribute="componentonly" inherit="true"/> <meta attribute="allcomponent"/> - <property name="x" type="string"/> + <meta attribute="globalmutated">monetaryamount level</meta> + <property name="x" type="string"> + <meta attribute="globalmutated">monetaryamount x level</meta> + </property> </component> <set name="sortedEmployee" sort="org.hibernate.test.legacy.NonExistingComparator"> + <meta attribute="globalmutated">sortedemployee level</meta> <key column="attrb_id"/> <many-to-many class="org.hibernate.test.legacy.Employee" column="id"/> </set> + <bag name="anotherSet"> + <key column="attrb2_id"/> + <composite-element class="org.hibernate.test.legacy.Employee"> + <meta attribute="globalmutated">monetaryamount anotherSet composite level</meta> + <property name="emp" type="string"> + <meta attribute="globalmutated">monetaryamount anotherSet composite property emp level</meta> + </property> + <many-to-one name="empinone" class="org.hibernate.test.legacy.Employee"> + <meta attribute="globalmutated">monetaryamount anotherSet composite property empinone level</meta> + </many-to-one> + </composite-element> + </bag> </class> |
From: <hib...@li...> - 2006-08-02 15:05:52
|
Author: max...@jb... Date: 2006-08-02 11:05:40 -0400 (Wed, 02 Aug 2006) New Revision: 10191 Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml Log: HHH-1963 meta inheritance is broken HBX-719 Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-02 13:41:02 UTC (rev 10190) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/CollectionSecondPass.java 2006-08-02 15:05:40 UTC (rev 10191) @@ -1,7 +1,9 @@ //$Id$ package org.hibernate.cfg; +import java.util.Collections; import java.util.Iterator; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,18 +23,24 @@ private static Log log = LogFactory.getLog( CollectionSecondPass.class ); Mappings mappings; Collection collection; + private Map localInheritedMetas; - public CollectionSecondPass(Mappings mappings, Collection collection) { + public CollectionSecondPass(Mappings mappings, Collection collection, java.util.Map inheritedMetas) { this.collection = collection; this.mappings = mappings; + this.localInheritedMetas = inheritedMetas; } + public CollectionSecondPass(Mappings mappings, Collection collection) { + this(mappings, collection, Collections.EMPTY_MAP); + } + public void doSecondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) throws MappingException { if ( log.isDebugEnabled() ) log.debug( "Second pass for collection: " + collection.getRole() ); - secondPass( persistentClasses, inheritedMetas ); + secondPass( persistentClasses, localInheritedMetas ); // using local since the inheritedMetas at this point is not the correct map since it is always the empty map collection.createAllKeys(); if ( log.isDebugEnabled() ) { Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-02 13:41:02 UTC (rev 10190) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/Configuration.java 2006-08-02 15:05:40 UTC (rev 10191) @@ -1051,7 +1051,7 @@ while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); if ( ! (sp instanceof QuerySecondPass) ) { - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); // TODO: align meta-attributes with normal bind... + sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); iter.remove(); } } @@ -1060,7 +1060,7 @@ iter = secondPasses.iterator(); while ( iter.hasNext() ) { SecondPass sp = (SecondPass) iter.next(); - sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); // TODO: align meta-attributes with normal bind... + sp.doSecondPass( classes, CollectionHelper.EMPTY_MAP ); iter.remove(); } Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-02 13:41:02 UTC (rev 10190) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-08-02 15:05:40 UTC (rev 10191) @@ -2,6 +2,7 @@ package org.hibernate.cfg; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -1287,7 +1288,7 @@ * Called for all collections */ public static void bindCollection(Element node, Collection collection, String className, - String path, Mappings mappings) throws MappingException { + String path, Mappings mappings, java.util.Map inheritedMetas) throws MappingException { // ROLENAME collection.setRole(path); @@ -1438,20 +1439,21 @@ handleCustomSQL( node, collection ); // set up second pass if ( collection instanceof List ) { - mappings.addSecondPass( new ListSecondPass( node, mappings, (List) collection ) ); + mappings.addSecondPass( new ListSecondPass( node, mappings, (List) collection, inheritedMetas ) ); } else if ( collection instanceof Map ) { - mappings.addSecondPass( new MapSecondPass( node, mappings, (Map) collection ) ); + mappings.addSecondPass( new MapSecondPass( node, mappings, (Map) collection, inheritedMetas ) ); } else if ( collection instanceof IdentifierCollection ) { mappings.addSecondPass( new IdentifierCollectionSecondPass( node, mappings, - collection + collection, + inheritedMetas ) ); } else { - mappings.addSecondPass( new CollectionSecondPass( node, mappings, collection ) ); + mappings.addSecondPass( new CollectionSecondPass( node, mappings, collection, inheritedMetas ) ); } Iterator iter = node.elementIterator( "filter" ); @@ -1669,9 +1671,9 @@ * Called for arrays and primitive arrays */ public static void bindArray(Element node, Array array, String prefix, String path, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { - bindCollection( node, array, prefix, path, mappings ); + bindCollection( node, array, prefix, path, mappings, inheritedMetas ); Attribute att = node.attribute( "element-class" ); if ( att != null ) array.setElementClassName( getClassName( att, mappings ) ); @@ -1770,7 +1772,8 @@ component.setEmbedded( isEmbedded ); component.setRoleName( path ); - component.setMetaAttributes( getMetas( node, inheritedMetas ) ); + inheritedMetas = getMetas( node, inheritedMetas ); + component.setMetaAttributes( inheritedMetas ); Attribute classNode = isIdentifierMapper ? null : node.attribute( "class" ); if ( classNode != null ) { @@ -1823,7 +1826,7 @@ subnode, subpath, component.getOwner(), - mappings + mappings, inheritedMetas ); mappings.addCollection( collection ); value = collection; @@ -2048,7 +2051,7 @@ subnode, StringHelper.qualify( entityName, propertyName ), persistentClass, - mappings + mappings, inheritedMetas ); mappings.addCollection( collection ); value = collection; @@ -2639,8 +2642,8 @@ static class CollectionSecondPass extends org.hibernate.cfg.CollectionSecondPass { Element node; - CollectionSecondPass(Element node, Mappings mappings, Collection collection) { - super(mappings, collection); + CollectionSecondPass(Element node, Mappings mappings, Collection collection, java.util.Map inheritedMetas) { + super(mappings, collection, inheritedMetas); this.node = node; } @@ -2657,8 +2660,8 @@ } static class IdentifierCollectionSecondPass extends CollectionSecondPass { - IdentifierCollectionSecondPass(Element node, Mappings mappings, Collection collection) { - super( node, mappings, collection ); + IdentifierCollectionSecondPass(Element node, Mappings mappings, Collection collection, java.util.Map inheritedMetas) { + super( node, mappings, collection, inheritedMetas ); } public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) @@ -2675,8 +2678,8 @@ } static class MapSecondPass extends CollectionSecondPass { - MapSecondPass(Element node, Mappings mappings, Map collection) { - super( node, mappings, collection ); + MapSecondPass(Element node, Mappings mappings, Map collection, java.util.Map inheritedMetas) { + super( node, mappings, collection, inheritedMetas ); } public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) @@ -2707,8 +2710,8 @@ } static class ListSecondPass extends CollectionSecondPass { - ListSecondPass(Element node, Mappings mappings, List collection) { - super( node, mappings, collection ); + ListSecondPass(Element node, Mappings mappings, List collection, java.util.Map inheritedMetas) { + super( node, mappings, collection, inheritedMetas ); } public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas) @@ -2729,7 +2732,7 @@ private String xmlTag; public abstract Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException; + Mappings mappings, java.util.Map inheritedMetas) throws MappingException; CollectionType(String xmlTag) { this.xmlTag = xmlTag; @@ -2741,57 +2744,57 @@ private static final CollectionType MAP = new CollectionType( "map" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Map map = new Map( owner ); - bindCollection( node, map, owner.getEntityName(), path, mappings ); + bindCollection( node, map, owner.getEntityName(), path, mappings, inheritedMetas ); return map; } }; private static final CollectionType SET = new CollectionType( "set" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Set set = new Set( owner ); - bindCollection( node, set, owner.getEntityName(), path, mappings ); + bindCollection( node, set, owner.getEntityName(), path, mappings, inheritedMetas ); return set; } }; private static final CollectionType LIST = new CollectionType( "list" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { List list = new List( owner ); - bindCollection( node, list, owner.getEntityName(), path, mappings ); + bindCollection( node, list, owner.getEntityName(), path, mappings, inheritedMetas ); return list; } }; private static final CollectionType BAG = new CollectionType( "bag" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Bag bag = new Bag( owner ); - bindCollection( node, bag, owner.getEntityName(), path, mappings ); + bindCollection( node, bag, owner.getEntityName(), path, mappings, inheritedMetas ); return bag; } }; private static final CollectionType IDBAG = new CollectionType( "idbag" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { IdentifierBag bag = new IdentifierBag( owner ); - bindCollection( node, bag, owner.getEntityName(), path, mappings ); + bindCollection( node, bag, owner.getEntityName(), path, mappings, inheritedMetas ); return bag; } }; private static final CollectionType ARRAY = new CollectionType( "array" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Array array = new Array( owner ); - bindArray( node, array, owner.getEntityName(), path, mappings ); + bindArray( node, array, owner.getEntityName(), path, mappings, inheritedMetas ); return array; } }; private static final CollectionType PRIMITIVE_ARRAY = new CollectionType( "primitive-array" ) { public Collection create(Element node, String path, PersistentClass owner, - Mappings mappings) throws MappingException { + Mappings mappings, java.util.Map inheritedMetas) throws MappingException { PrimitiveArray array = new PrimitiveArray( owner ); - bindArray( node, array, owner.getEntityName(), path, mappings ); + bindArray( node, array, owner.getEntityName(), path, mappings, inheritedMetas ); return array; } }; @@ -2854,10 +2857,18 @@ String name = metaNode.attributeValue( "attribute" ); MetaAttribute meta = (MetaAttribute) map.get( name ); - if ( meta == null ) { + MetaAttribute inheritedAttribute = (MetaAttribute) inheritedMeta.get( name ); + if ( meta == null ) { meta = new MetaAttribute( name ); map.put( name, meta ); - } + } else if (meta == inheritedAttribute) { // to prevent mutation of the inherited meta attribute. + meta = new MetaAttribute( name ); + map.put( name, meta ); + java.util.List values = inheritedAttribute.getValues(); + for (Iterator iterator = values.iterator(); iterator.hasNext();) { + meta.addValue( (String) iterator.next() ); + } + } meta.addValue( metaNode.getText() ); } return map; Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java =================================================================== --- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java 2006-08-02 13:41:02 UTC (rev 10190) +++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/NonReflectiveBinderTest.java 2006-08-02 15:05:40 UTC (rev 10191) @@ -10,7 +10,9 @@ import org.hibernate.MappingException; import org.hibernate.cfg.Configuration; +import org.hibernate.mapping.Bag; import org.hibernate.mapping.Collection; +import org.hibernate.mapping.Component; import org.hibernate.mapping.MetaAttribute; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; @@ -30,7 +32,7 @@ } public String[] getMappings() { - return new String[] { "legacy/Wicked.hbm.xml" }; + return new String[] { "legacy/Wicked.hbm.xml"}; } void buildConfiguration(String[] files) throws MappingException { @@ -46,7 +48,6 @@ throw e; } - } protected void setUp() throws Exception { @@ -108,6 +109,91 @@ } + // HBX-718 + public void testNonMutatedInheritance() { + Configuration cfg = getCfg(); + cfg.buildMappings(); + + PersistentClass cm = cfg.getClassMapping("org.hibernate.test.legacy.Wicked"); + MetaAttribute metaAttribute = cm.getMetaAttribute( "globalmutated" ); + + assertNotNull(metaAttribute); + assertEquals( metaAttribute.getValues().size(), 2 ); + assertEquals( "top level", metaAttribute.getValues().get(0) ); + assertEquals( "wicked level", metaAttribute.getValues().get(1) ); + + Property property = cm.getProperty( "component" ); + MetaAttribute propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 3 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount level", propertyAttribute.getValues().get(2) ); + + org.hibernate.mapping.Component component = (Component)property.getValue(); + property = component.getProperty( "x" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 4 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount level", propertyAttribute.getValues().get(2) ); + assertEquals( "monetaryamount x level", propertyAttribute.getValues().get(3) ); + + property = cm.getProperty( "sortedEmployee" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 3 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "sortedemployee level", propertyAttribute.getValues().get(2) ); + + property = cm.getProperty( "anotherSet" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 2 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + + Bag bag = (Bag) property.getValue(); + component = (Component)bag.getElement(); + + assertEquals(4,component.getMetaAttributes().size()); + + metaAttribute = component.getMetaAttribute( "globalmutated" ); + assertEquals( metaAttribute.getValues().size(), 3 ); + assertEquals( "top level", metaAttribute.getValues().get(0) ); + assertEquals( "wicked level", metaAttribute.getValues().get(1) ); + assertEquals( "monetaryamount anotherSet composite level", metaAttribute.getValues().get(2) ); + + property = component.getProperty( "emp" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 4 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount anotherSet composite level", propertyAttribute.getValues().get(2) ); + assertEquals( "monetaryamount anotherSet composite property emp level", propertyAttribute.getValues().get(3) ); + + + property = component.getProperty( "empinone" ); + propertyAttribute = property.getMetaAttribute( "globalmutated" ); + + assertNotNull(propertyAttribute); + assertEquals( propertyAttribute.getValues().size(), 4 ); + assertEquals( "top level", propertyAttribute.getValues().get(0) ); + assertEquals( "wicked level", propertyAttribute.getValues().get(1) ); + assertEquals( "monetaryamount anotherSet composite level", propertyAttribute.getValues().get(2) ); + assertEquals( "monetaryamount anotherSet composite property empinone level", propertyAttribute.getValues().get(3) ); + + + } + public void testComparator() { Configuration cfg = getCfg(); cfg.buildMappings(); Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml =================================================================== --- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml 2006-08-02 13:41:02 UTC (rev 10190) +++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/Wicked.hbm.xml 2006-08-02 15:05:40 UTC (rev 10191) @@ -7,6 +7,8 @@ <hibernate-mapping default-lazy="false"> <meta attribute="global">global value</meta> <meta attribute="globalnoinherit" inherit="false">only visible at top level</meta> + <meta attribute="globalmutated">top level</meta> + <class name="org.hibernate.test.legacy.Wicked" table="WICKED" schema="HR"> @@ -14,7 +16,7 @@ <meta attribute="implements">java.lang.Observer</meta> <meta attribute="implements" inherit="false">org.foo.BogusVisitor</meta> <meta attribute="extends">AuditInfo</meta> - + <meta attribute="globalmutated">wicked level</meta> <id name="id" type="long" column="EMPLOYEE_ID"> @@ -31,14 +33,30 @@ <component name="component" class="net.sf.hibern8ide.test.MonetaryAmount"> <meta attribute="componentonly" inherit="true"/> <meta attribute="allcomponent"/> - <property name="x" type="string"/> + <meta attribute="globalmutated">monetaryamount level</meta> + <property name="x" type="string"> + <meta attribute="globalmutated">monetaryamount x level</meta> + </property> </component> <set name="sortedEmployee" sort="org.hibernate.test.legacy.NonExistingComparator"> + <meta attribute="globalmutated">sortedemployee level</meta> <key column="attrb_id"/> <many-to-many class="org.hibernate.test.legacy.Employee" column="id"/> </set> + <bag name="anotherSet"> + <key column="attrb2_id"/> + <composite-element class="org.hibernate.test.legacy.Employee"> + <meta attribute="globalmutated">monetaryamount anotherSet composite level</meta> + <property name="emp" type="string"> + <meta attribute="globalmutated">monetaryamount anotherSet composite property emp level</meta> + </property> + <many-to-one name="empinone" class="org.hibernate.test.legacy.Employee"> + <meta attribute="globalmutated">monetaryamount anotherSet composite property empinone level</meta> + </many-to-one> + </composite-element> + </bag> </class> |
From: <hib...@li...> - 2006-08-02 13:41:12
|
Author: scottmarlownovell Date: 2006-08-02 09:41:02 -0400 (Wed, 02 Aug 2006) New Revision: 10190 Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java Log: Fix HHH-1931 (verify that the instrument tasks actually work.) Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java =================================================================== --- branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java 2006-08-02 02:06:00 UTC (rev 10189) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/tool/instrument/cglib/InstrumentTask.java 2006-08-02 13:41:02 UTC (rev 10190) @@ -43,21 +43,22 @@ * Override the {@link AbstractTransformTask#getClassTransformer} method * in order to define field access interception transformation should occur. */ - protected ClassTransformer getClassTransformer(String[] classInfo) { + protected ClassTransformer getClassTransformer(final String[] classInfo) { if ( Arrays.asList( classInfo ).contains( InterceptFieldEnabled.class.getName() ) ) { // The class is already instrumented, so skip this step return null; } else { + // Class was not yet enhanced, so apply the transformation return new InterceptFieldTransformer( new InterceptFieldFilter() { public boolean acceptRead(Type owner, String name) { - return true; + return (owner.getClassName().equals(classInfo[0])); } public boolean acceptWrite(Type owner, String name) { - return true; + return (owner.getClassName().equals(classInfo[0])); } } ); |
From: <hib...@li...> - 2006-08-02 02:06:03
|
Author: scottmarlownovell Date: 2006-08-01 22:06:00 -0400 (Tue, 01 Aug 2006) New Revision: 10189 Modified: trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java Log: Applied patch for HHH-1750 and verified that "Out of cursors" error is resolved. Modified: trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-08-02 02:05:16 UTC (rev 10188) +++ trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-08-02 02:06:00 UTC (rev 10189) @@ -3543,23 +3543,32 @@ session.getBatcher().executeBatch(); //force immediate execution of the insert - PreparedStatement ps = null; try { - ps = session.getBatcher().prepareSelectStatement( selectionSQL ); - getIdentifierType().nullSafeSet( ps, id, 1, session ); - ResultSet rs = session.getBatcher().getResultSet( ps ); - if ( !rs.next() ) { - throw new HibernateException( - "Unable to locate row for retrieval of generated properties: " + - MessageHelper.infoString( this, id, getFactory() ) - ); - } - for ( int i = 0; i < getPropertySpan(); i++ ) { - if ( included[i] ) { - state[i] = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity ); - setPropertyValue( entity, i, state[i], session.getEntityMode() ); + PreparedStatement ps = session.getBatcher().prepareSelectStatement( selectionSQL ); + try { + getIdentifierType().nullSafeSet( ps, id, 1, session ); + ResultSet rs = session.getBatcher().getResultSet( ps ); + try { + if ( !rs.next() ) { + throw new HibernateException( + "Unable to locate row for retrieval of generated properties: " + + MessageHelper.infoString( this, id, getFactory() ) + ); + } + for ( int i = 0; i < getPropertySpan(); i++ ) { + if ( included[i] ) { + state[i] = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity ); + setPropertyValue( entity, i, state[i], session.getEntityMode() ); + } + } } + finally { + rs.close(); + } } + finally { + session.getBatcher().closeStatement(ps); + } } catch( SQLException sqle ) { JDBCExceptionHelper.convert( |
From: <hib...@li...> - 2006-08-02 02:05:19
|
Author: scottmarlownovell Date: 2006-08-01 22:05:16 -0400 (Tue, 01 Aug 2006) New Revision: 10188 Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java Log: Applied patch for HHH-1750 and verified that "Out of cursors" error is resolved. 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 2006-08-02 00:42:25 UTC (rev 10187) +++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-08-02 02:05:16 UTC (rev 10188) @@ -3543,23 +3543,32 @@ session.getBatcher().executeBatch(); //force immediate execution of the insert - PreparedStatement ps = null; try { - ps = session.getBatcher().prepareSelectStatement( selectionSQL ); - getIdentifierType().nullSafeSet( ps, id, 1, session ); - ResultSet rs = session.getBatcher().getResultSet( ps ); - if ( !rs.next() ) { - throw new HibernateException( - "Unable to locate row for retrieval of generated properties: " + - MessageHelper.infoString( this, id, getFactory() ) - ); - } - for ( int i = 0; i < getPropertySpan(); i++ ) { - if ( included[i] ) { - state[i] = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity ); - setPropertyValue( entity, i, state[i], session.getEntityMode() ); + PreparedStatement ps = session.getBatcher().prepareSelectStatement( selectionSQL ); + try { + getIdentifierType().nullSafeSet( ps, id, 1, session ); + ResultSet rs = session.getBatcher().getResultSet( ps ); + try { + if ( !rs.next() ) { + throw new HibernateException( + "Unable to locate row for retrieval of generated properties: " + + MessageHelper.infoString( this, id, getFactory() ) + ); + } + for ( int i = 0; i < getPropertySpan(); i++ ) { + if ( included[i] ) { + state[i] = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity ); + setPropertyValue( entity, i, state[i], session.getEntityMode() ); + } + } } + finally { + rs.close(); + } } + finally { + session.getBatcher().closeStatement(ps); + } } catch( SQLException sqle ) { JDBCExceptionHelper.convert( |