From 44a02e5efc39c6953ca6dd631669d91293ab67f6 Mon Sep 17 00:00:00 2001 From: barreiro Date: Sun, 7 Jun 2015 00:40:14 +0100 Subject: [PATCH] HHH-8558 - Bytecode enhancer: testsuite reorganization with added lazy loading tests --- .../PersistentAttributesEnhancer.java | 31 +- .../enhancement/AbstractEnhancerTestTask.java | 58 ++++ .../enhancement/CustomerEnhancerTest.java | 198 ----------- .../bytecode/enhancement/DecompileUtils.java | 132 +++++++ .../bytecode/enhancement/EnhancerTest.java | 147 ++------ ...SuperEntity.java => EnhancerTestTask.java} | 18 +- .../enhancement/EnhancerTestUtils.java | 326 ++++++------------ .../enhancement/association/Customer.java | 123 +++++++ .../association/CustomerInventory.java | 103 ++++++ .../enhancement/association/Group.java | 55 +++ .../ManyToManyAssociationTestTask.java | 70 ++++ .../OneToManyAssociationTestTask.java | 65 ++++ .../OneToOneAssociationTestTask.java | 54 +++ .../enhancement/association/User.java | 75 ++++ .../basic/BasicEnhancementTestTask.java | 70 ++++ .../BasicInSessionTest.java} | 29 +- .../{entity => basic}/MyEntity.java | 12 +- .../ObjectAttributeMarkerInterceptor.java | 115 ++++++ .../SimpleEntity.java} | 50 ++- .../bytecode/enhancement/dirty/Address.java | 88 +++++ .../{entity => dirty}/Country.java | 16 +- .../dirty/DirtyTrackingTestTask.java | 91 +++++ .../{entity => dirty}/SimpleEntity.java | 70 ++-- .../bytecode/enhancement/entity/Address.java | 88 ----- .../enhancement/entity/SampleEntity.java | 124 ------- .../enhancement/entity/customer/Address.java | 107 ------ .../enhancement/entity/customer/Customer.java | 250 -------------- .../entity/customer/CustomerInventory.java | 140 -------- .../entity/customer/CustomerInventoryPK.java | 50 --- .../enhancement/entity/customer/Group.java | 60 ---- .../entity/customer/SupplierComponentPK.java | 54 --- .../enhancement/entity/customer/User.java | 83 ----- .../test/bytecode/enhancement/lazy/Child.java | 61 ++++ .../lazy/LazyLoadingIntegrationTestTask.java | 88 +++++ .../enhancement/lazy/LazyLoadingTestTask.java | 95 +++++ .../bytecode/enhancement/lazy/Parent.java | 48 +++ 36 files changed, 1665 insertions(+), 1579 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/AbstractEnhancerTestTask.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/CustomerEnhancerTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/DecompileUtils.java rename hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/{entity/SuperEntity.java => EnhancerTestTask.java} (55%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Customer.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/CustomerInventory.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Group.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/ManyToManyAssociationTestTask.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToManyAssociationTestTask.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToOneAssociationTestTask.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/User.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicEnhancementTestTask.java rename hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/{MostBasicEnhancementTest.java => basic/BasicInSessionTest.java} (69%) rename hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/{entity => basic}/MyEntity.java (96%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java rename hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/{entity/SubEntity.java => basic/SimpleEntity.java} (54%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Address.java rename hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/{entity => dirty}/Country.java (65%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/DirtyTrackingTestTask.java rename hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/{entity => dirty}/SimpleEntity.java (60%) delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Address.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SampleEntity.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Address.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Customer.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventory.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventoryPK.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Group.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/SupplierComponentPK.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/User.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingIntegrationTestTask.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Parent.java diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/PersistentAttributesEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/PersistentAttributesEnhancer.java index 3264806391..c8e1050f61 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/PersistentAttributesEnhancer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/PersistentAttributesEnhancer.java @@ -6,6 +6,15 @@ */ package org.hibernate.bytecode.enhance.internal; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Embedded; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + import javassist.CannotCompileException; import javassist.CtClass; import javassist.CtField; @@ -29,15 +38,6 @@ import org.hibernate.engine.spi.CompositeTracker; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; -import javax.persistence.Embedded; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import java.util.IdentityHashMap; -import java.util.LinkedList; -import java.util.List; - /** * enhancer for persistent attributes of any type of entity * @@ -225,7 +225,7 @@ public class PersistentAttributesEnhancer extends Enhancer { } final String mappedBy = getMappedBy( persistentField, targetEntity ); if ( mappedBy.isEmpty() ) { - log.debugf( + log.warnf( "Could not find bi-directional association for field [%s#%s]", managedCtClass.getName(), persistentField.getName() @@ -258,9 +258,10 @@ public class PersistentAttributesEnhancer extends Enhancer { } if ( persistentField.hasAnnotation( OneToMany.class ) ) { // only remove elements not in the new collection or else we would loose those elements + // don't use iterator to avoid ConcurrentModException fieldWriter.insertBefore( String.format( - "if ($0.%s != null) for (java.util.Iterator itr = $0.%. + */ +package org.hibernate.test.bytecode.enhancement; + +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.service.ServiceRegistry; + +import org.hibernate.testing.ServiceRegistryBuilder; + +/** + * @author Luis Barreiro + */ +public abstract class AbstractEnhancerTestTask implements EnhancerTestTask { + + private ServiceRegistry serviceRegistry; + private SessionFactory factory; + + public final void prepare(Configuration user) { + Configuration cfg = new Configuration(); + cfg.setProperties( user.getProperties() ); + cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); + + Class[] resources = getAnnotatedClasses(); + for ( Class resource : resources ) { + cfg.addAnnotatedClass( resource ); + } + + serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( cfg.getProperties() ); + factory = cfg.buildSessionFactory( serviceRegistry ); + } + + public final void complete() { + try { + cleanup(); + } + finally { + factory.close(); + factory = null; + if ( serviceRegistry != null ) { + ServiceRegistryBuilder.destroy( serviceRegistry ); + serviceRegistry = null; + } + } + } + + protected SessionFactory getFactory() { + return factory; + } + + protected abstract void cleanup(); + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/CustomerEnhancerTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/CustomerEnhancerTest.java deleted file mode 100644 index d8de53fbc5..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/CustomerEnhancerTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.ManagedEntity; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; - -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.test.bytecode.enhancement.entity.customer.Address; -import org.hibernate.test.bytecode.enhancement.entity.customer.Customer; -import org.hibernate.test.bytecode.enhancement.entity.customer.CustomerInventory; -import org.hibernate.test.bytecode.enhancement.entity.customer.Group; -import org.hibernate.test.bytecode.enhancement.entity.customer.SupplierComponentPK; -import org.hibernate.test.bytecode.enhancement.entity.customer.User; -import org.junit.Test; - -import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -/** - * @author Steve Ebersole - */ -public class CustomerEnhancerTest extends BaseUnitTestCase { - - @Test - public void testEnhancement() throws Exception { - testFor(Customer.class); - } - - private void testFor(Class entityClassToEnhance) throws Exception { - ClassLoader cl = new ClassLoader() { - }; - - // just for debugging - Class addressClass = EnhancerTestUtils.enhanceAndDecompile(Address.class, cl); - Class customerInventoryClass = EnhancerTestUtils.enhanceAndDecompile(CustomerInventory.class, cl); - Class supplierComponentPKCtClass = EnhancerTestUtils.enhanceAndDecompile(SupplierComponentPK.class, cl); - - Class entityClass = EnhancerTestUtils.enhanceAndDecompile(entityClassToEnhance, cl); - Object entityInstance = entityClass.newInstance(); - assertTyping(ManagedEntity.class, entityInstance); - - // call the new methods - Method setter = entityClass.getMethod(EnhancerConstants.ENTITY_ENTRY_SETTER_NAME, EntityEntry.class); - Method getter = entityClass.getMethod(EnhancerConstants.ENTITY_ENTRY_GETTER_NAME); - assertNull(getter.invoke(entityInstance)); - setter.invoke(entityInstance, EnhancerTestUtils.makeEntityEntry()); - assertNotNull(getter.invoke(entityInstance)); - setter.invoke(entityInstance, new Object[]{null}); - assertNull(getter.invoke(entityInstance)); - - Method entityInstanceGetter = entityClass.getMethod(EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME); - assertSame(entityInstance, entityInstanceGetter.invoke(entityInstance)); - - Method previousGetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_GETTER_NAME); - Method previousSetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_SETTER_NAME, ManagedEntity.class); - previousSetter.invoke(entityInstance, entityInstance); - assertSame(entityInstance, previousGetter.invoke(entityInstance)); - - Method nextGetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_GETTER_NAME); - Method nextSetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_SETTER_NAME, ManagedEntity.class); - nextSetter.invoke(entityInstance, entityInstance); - assertSame(entityInstance, nextGetter.invoke(entityInstance)); - - // add an attribute interceptor... - assertNull(entityClass.getMethod(EnhancerConstants.INTERCEPTOR_GETTER_NAME).invoke(entityInstance)); - entityClass.getMethod("getId").invoke(entityInstance); - - Method interceptorSetter = entityClass.getMethod(EnhancerConstants.INTERCEPTOR_SETTER_NAME, PersistentAttributeInterceptor.class); - interceptorSetter.invoke(entityInstance, new EnhancerTestUtils.LocalPersistentAttributeInterceptor()); - assertNotNull(entityClass.getMethod(EnhancerConstants.INTERCEPTOR_GETTER_NAME).invoke(entityInstance)); - - // dirty checking is unfortunately just printlns for now... just verify the test output - entityClass.getMethod("getId").invoke(entityInstance); - entityClass.getMethod("setId", Integer.class).invoke(entityInstance, entityClass.getMethod("getId").invoke(entityInstance)); - entityClass.getMethod("setId", Integer.class).invoke(entityInstance, 1); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "id"); - - entityClass.getMethod("setFirstName", String.class).invoke(entityInstance, "Erik"); - entityClass.getMethod("setLastName", String.class).invoke(entityInstance, "Mykland"); - - EnhancerTestUtils.checkDirtyTracking(entityInstance, "id", "firstName", "lastName"); - EnhancerTestUtils.clearDirtyTracking(entityInstance); - - // testing composite object - Object address = addressClass.newInstance(); - - entityClass.getMethod("setAddress", addressClass).invoke(entityInstance, address); - addressClass.getMethod("setCity", String.class).invoke(address, "Arendal"); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "address", "address.city"); - EnhancerTestUtils.clearDirtyTracking(entityInstance); - - //make sure that new composite instances are cleared - Object address2 = addressClass.newInstance(); - entityClass.getMethod("setAddress", addressClass).invoke(entityInstance, address2); - addressClass.getMethod("setStreet1", String.class).invoke(address, "Heggedalveien"); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "address"); - } - - - @Test - public void testBiDirectionalAssociationManagement() throws Exception { - ClassLoader cl = new ClassLoader() { - }; - - Class userClass = EnhancerTestUtils.enhanceAndDecompile(User.class, cl); - Class groupClass = EnhancerTestUtils.enhanceAndDecompile(Group.class, cl); - Class customerClass = EnhancerTestUtils.enhanceAndDecompile(Customer.class, cl); - Class customerInventoryClass = EnhancerTestUtils.enhanceAndDecompile(CustomerInventory.class, cl); - - Object userInstance = userClass.newInstance(); - assertTyping(ManagedEntity.class, userInstance); - - Object groupInstance = groupClass.newInstance(); - assertTyping(ManagedEntity.class, groupInstance); - - Object customerInstance = customerClass.newInstance(); - assertTyping(ManagedEntity.class, customerInstance); - - Object customerInventoryInstance = customerInventoryClass.newInstance(); - assertTyping(ManagedEntity.class, customerInventoryInstance); - - Method interceptorSetter = userClass.getMethod(EnhancerConstants.INTERCEPTOR_SETTER_NAME, PersistentAttributeInterceptor.class); - interceptorSetter.invoke(userInstance, new EnhancerTestUtils.LocalPersistentAttributeInterceptor()); - - /* --- @OneToOne */ - - userClass.getMethod("setLogin", String.class).invoke(userInstance, UUID.randomUUID().toString()); - - customerClass.getMethod("setUser", userClass).invoke(customerInstance, userInstance); - assertEquals(customerInstance, userClass.getMethod("getCustomer").invoke(userInstance)); - - // check dirty tracking is set automatically with bi-directional association management - EnhancerTestUtils.checkDirtyTracking(userInstance, "login", "customer"); - - Object anotherUser = userClass.newInstance(); - userClass.getMethod("setLogin", String.class).invoke(anotherUser, UUID.randomUUID().toString()); - - customerClass.getMethod("setUser", userClass).invoke(customerInstance, anotherUser); - assertEquals(null, userClass.getMethod("getCustomer").invoke(userInstance)); - assertEquals(customerInstance, userClass.getMethod("getCustomer").invoke(anotherUser)); - - userClass.getMethod("setCustomer", customerClass).invoke(userInstance, customerClass.newInstance()); - assertEquals(userInstance, customerClass.getMethod("getUser").invoke(userClass.getMethod("getCustomer").invoke(userInstance))); - - /* --- @OneToMany @ManyToOne */ - - assertTrue(((Collection) customerClass.getMethod("getInventories").invoke(customerInstance)).isEmpty()); - customerInventoryClass.getMethod("setCustomer", customerClass).invoke(customerInventoryInstance, customerInstance); - - Collection inventories = (Collection < ?>) customerClass.getMethod("getInventories").invoke(customerInstance); - assertTrue(inventories.size() == 1); - assertTrue(inventories.contains(customerInventoryInstance)); - - Object anotherCustomer = customerClass.newInstance(); - customerInventoryClass.getMethod("setCustomer", customerClass).invoke(customerInventoryInstance, anotherCustomer); - assertTrue(((Collection) customerClass.getMethod("getInventories").invoke(customerInstance)).isEmpty()); - - customerClass.getMethod("addInventory", customerInventoryClass).invoke(customerInstance, customerInventoryInstance); - assertTrue(customerInventoryClass.getMethod("getCustomer").invoke(customerInventoryInstance) == customerInstance); - - inventories = (Collection < ?>) customerClass.getMethod("getInventories").invoke(customerInstance); - assertTrue(inventories.size() == 1); - - customerClass.getMethod("addInventory", customerInventoryClass).invoke(customerInstance, customerInventoryClass.newInstance()); - assertTrue(((Collection) customerClass.getMethod("getInventories").invoke(customerInstance)).size() == 2); - - /* --- @ManyToMany */ - - Object anotherGroup = groupClass.newInstance(); - userClass.getMethod("addGroup", groupClass).invoke(userInstance, groupInstance); - userClass.getMethod("addGroup", groupClass).invoke(userInstance, anotherGroup); - userClass.getMethod("addGroup", groupClass).invoke(anotherUser, groupInstance); - - assertTrue(((Collection) groupClass.getMethod("getUsers").invoke(groupInstance)).size() == 2); - - groupClass.getMethod("setUsers", Set.class).invoke(groupInstance, new HashSet()); - assertTrue(((Collection) userClass.getMethod("getGroups").invoke(userInstance)).size() == 1); - - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/DecompileUtils.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/DecompileUtils.java new file mode 100644 index 0000000000..7bbd4be1f6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/DecompileUtils.java @@ -0,0 +1,132 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +import org.hibernate.bytecode.enhance.spi.EnhancerConstants; +import org.hibernate.engine.spi.CompositeOwner; +import org.hibernate.engine.spi.CompositeTracker; +import org.hibernate.engine.spi.ManagedEntity; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; +import org.hibernate.engine.spi.SelfDirtinessTracker; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; + +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.javap.JavapTask; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * utility class to use in bytecode enhancement tests + * + * @author Luis Barreiro + */ +public abstract class DecompileUtils { + + private static final CoreMessageLogger log = CoreLogging.messageLogger( DecompileUtils.class ); + + public static void decompileDumpedClass(String workingDir, String className) { + try { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null ); + fileManager.setLocation( + StandardLocation.CLASS_OUTPUT, + Collections.singletonList( new File( workingDir ) ) + ); + + JavapTask javapTask = new JavapTask(); + String filename = workingDir + File.separator + getFilenameForClassName( className ); + for ( JavaFileObject jfo : fileManager.getJavaFileObjects( filename ) ) { + try { + Set interfaceNames = new HashSet(); + Set fieldNames = new HashSet(); + Set methodNames = new HashSet(); + + JavapTask.ClassFileInfo info = javapTask.read( jfo ); + + log.infof( "decompiled class [%s]", info.cf.getName() ); + + for ( int i : info.cf.interfaces ) { + interfaceNames.add( info.cf.constant_pool.getClassInfo( i ).getName() ); + log.debugf( "declared iFace = ", info.cf.constant_pool.getClassInfo( i ).getName() ); + } + for ( com.sun.tools.classfile.Field f : info.cf.fields ) { + fieldNames.add( f.getName( info.cf.constant_pool ) ); + log.debugf( "declared field = ", f.getName( info.cf.constant_pool ) ); + } + for ( com.sun.tools.classfile.Method m : info.cf.methods ) { + methodNames.add( m.getName( info.cf.constant_pool ) ); + log.debugf( "declared method = ", m.getName( info.cf.constant_pool ) ); + } + + // checks signature against known interfaces + if ( interfaceNames.contains( PersistentAttributeInterceptor.class.getName() ) ) { + assertTrue( fieldNames.contains( EnhancerConstants.INTERCEPTOR_FIELD_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.INTERCEPTOR_GETTER_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.INTERCEPTOR_SETTER_NAME ) ); + } + if ( interfaceNames.contains( ManagedEntity.class.getName() ) ) { + assertTrue( methodNames.contains( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME ) ); + + assertTrue( fieldNames.contains( EnhancerConstants.ENTITY_ENTRY_FIELD_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.ENTITY_ENTRY_GETTER_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.ENTITY_ENTRY_SETTER_NAME ) ); + + assertTrue( fieldNames.contains( EnhancerConstants.PREVIOUS_FIELD_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.PREVIOUS_GETTER_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.PREVIOUS_SETTER_NAME ) ); + + assertTrue( fieldNames.contains( EnhancerConstants.NEXT_FIELD_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.NEXT_GETTER_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.NEXT_SETTER_NAME ) ); + } + if ( interfaceNames.contains( SelfDirtinessTracker.class.getName() ) ) { + assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_FIELD_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.TRACKER_GET_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CLEAR_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.TRACKER_HAS_CHANGED_NAME ) ); + } + if ( interfaceNames.contains( CompositeTracker.class.getName() ) ) { + assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER ) ); + assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER ) ); + } + if ( interfaceNames.contains( CompositeOwner.class.getName() ) ) { + assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) ); + assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) ); + } + } + catch (ConstantPoolException e) { + e.printStackTrace(); + } + } + } + catch (IOException ioe) { + assertNull( "Failed to open class file", ioe ); + } + catch (RuntimeException re) { + log.warnf( re, "WARNING: UNABLE DECOMPILE DUE TO %s", re.getMessage() ); + } + } + + private static String getFilenameForClassName(String className) { + return className.replace( '.', File.separatorChar ) + JavaFileObject.Kind.CLASS.extension; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java index 781b314c86..496a4c3cf7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java @@ -6,135 +6,42 @@ */ package org.hibernate.test.bytecode.enhancement; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.ManagedEntity; - import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.test.bytecode.enhancement.entity.Address; -import org.hibernate.test.bytecode.enhancement.entity.Country; -import org.hibernate.test.bytecode.enhancement.entity.SimpleEntity; -import org.hibernate.test.bytecode.enhancement.entity.SubEntity; +import org.hibernate.test.bytecode.enhancement.association.ManyToManyAssociationTestTask; +import org.hibernate.test.bytecode.enhancement.association.OneToManyAssociationTestTask; +import org.hibernate.test.bytecode.enhancement.association.OneToOneAssociationTestTask; +import org.hibernate.test.bytecode.enhancement.basic.BasicEnhancementTestTask; +import org.hibernate.test.bytecode.enhancement.dirty.DirtyTrackingTestTask; +import org.hibernate.test.bytecode.enhancement.lazy.LazyLoadingIntegrationTestTask; +import org.hibernate.test.bytecode.enhancement.lazy.LazyLoadingTestTask; import org.junit.Test; -import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; - /** - * @author Steve Ebersole + * @author Luis Barreiro */ public class EnhancerTest extends BaseUnitTestCase { - @Test - public void testEnhancement() throws Exception { - testFor(SimpleEntity.class); - testFor(SubEntity.class); - } + @Test + public void testBasic() { + EnhancerTestUtils.runEnhancerTestTask( BasicEnhancementTestTask.class ); + } - private void testFor(Class entityClassToEnhance) throws Exception { - ClassLoader cl = new ClassLoader() {}; - Class entityClass = EnhancerTestUtils.enhanceAndDecompile(entityClassToEnhance, cl); - Object entityInstance = entityClass.newInstance(); + @Test + public void testDirty() { + EnhancerTestUtils.runEnhancerTestTask( DirtyTrackingTestTask.class ); + } - assertTyping(ManagedEntity.class, entityInstance); + @Test + public void testAssociation() { + EnhancerTestUtils.runEnhancerTestTask( OneToOneAssociationTestTask.class ); + EnhancerTestUtils.runEnhancerTestTask( OneToManyAssociationTestTask.class ); + EnhancerTestUtils.runEnhancerTestTask( ManyToManyAssociationTestTask.class ); + } - // call the new methods - Method setter = entityClass.getMethod(EnhancerConstants.ENTITY_ENTRY_SETTER_NAME, EntityEntry.class); - Method getter = entityClass.getMethod(EnhancerConstants.ENTITY_ENTRY_GETTER_NAME); - - assertNull(getter.invoke(entityInstance)); - setter.invoke(entityInstance, EnhancerTestUtils.makeEntityEntry()); - assertNotNull(getter.invoke(entityInstance)); - setter.invoke(entityInstance, new Object[] { null } ); - assertNull(getter.invoke(entityInstance)); - - Method entityInstanceGetter = entityClass.getMethod(EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME); - assertSame(entityInstance, entityInstanceGetter.invoke(entityInstance)); - - Method previousGetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_GETTER_NAME); - Method previousSetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_SETTER_NAME, ManagedEntity.class); - previousSetter.invoke(entityInstance, entityInstance); - assertSame(entityInstance, previousGetter.invoke(entityInstance)); - - Method nextGetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_GETTER_NAME); - Method nextSetter = entityClass.getMethod(EnhancerConstants.PREVIOUS_SETTER_NAME, ManagedEntity.class); - nextSetter.invoke( entityInstance, entityInstance ); - assertSame( entityInstance, nextGetter.invoke( entityInstance ) ); - - entityClass.getMethod("getId").invoke(entityInstance); - entityClass.getMethod("setId", Long.class).invoke(entityInstance, entityClass.getMethod("getId").invoke(entityInstance)); - entityClass.getMethod("setId", Long.class).invoke(entityInstance, 1L); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "id"); - - entityClass.getMethod("isActive").invoke(entityInstance); - entityClass.getMethod("setActive", boolean.class).invoke(entityInstance, entityClass.getMethod("isActive").invoke(entityInstance)); - entityClass.getMethod("setActive", boolean.class).invoke(entityInstance, true); - - entityClass.getMethod("getSomeNumber").invoke(entityInstance); - entityClass.getMethod("setSomeNumber", long.class).invoke(entityInstance, entityClass.getMethod("getSomeNumber").invoke(entityInstance)); - entityClass.getMethod("setSomeNumber", long.class).invoke(entityInstance, 1L); - - EnhancerTestUtils.checkDirtyTracking(entityInstance, "id", "active", "someNumber"); - EnhancerTestUtils.clearDirtyTracking(entityInstance); - - // setting the same value should not make it dirty - entityClass.getMethod("setSomeNumber", long.class).invoke(entityInstance, 1L); - EnhancerTestUtils.checkDirtyTracking(entityInstance); - - if(entityClassToEnhance.getName().endsWith(SimpleEntity.class.getSimpleName())) { - cl = new ClassLoader() {}; - - Class addressClass = EnhancerTestUtils.enhanceAndDecompile(Address.class, cl); - Class countryClass = EnhancerTestUtils.enhanceAndDecompile(Country.class, cl); - - entityClass = EnhancerTestUtils.enhanceAndDecompile(entityClassToEnhance, cl); - entityInstance = entityClass.newInstance(); - - List strings = new ArrayList(); - strings.add("FooBar"); - entityClass.getMethod("setSomeStrings", List.class).invoke(entityInstance, strings); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "someStrings"); - EnhancerTestUtils.clearDirtyTracking(entityInstance); - - strings.add("JADA!"); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "someStrings"); - EnhancerTestUtils.clearDirtyTracking(entityInstance); - - // this should not set the entity to dirty - Set intSet = new HashSet(); - intSet.add(42); - entityClass.getMethod("setSomeInts", Set.class).invoke(entityInstance, intSet); - EnhancerTestUtils.checkDirtyTracking(entityInstance); - - // testing composite object - Object address = addressClass.newInstance(); - Object country = countryClass.newInstance(); - - entityClass.getMethod("setAddress", addressClass).invoke(entityInstance, address); - addressClass.getMethod("setCity", String.class).invoke(address, "Arendal"); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "address", "address.city"); - - entityClass.getMethod(EnhancerConstants.TRACKER_CLEAR_NAME).invoke(entityInstance); - - // make sure that new composite instances are cleared - Object address2 = addressClass.newInstance(); - - entityClass.getMethod("setAddress", addressClass).invoke(entityInstance, address2); - addressClass.getMethod("setStreet1", String.class).invoke(address, "Heggedalveien"); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "address"); - - addressClass.getMethod("setCountry", countryClass).invoke(address2, country); - countryClass.getMethod("setName", String.class).invoke(country, "Norway"); - EnhancerTestUtils.checkDirtyTracking(entityInstance, "address", "address.country", "address.country.name"); - } - } + @Test + public void testLazy() { + EnhancerTestUtils.runEnhancerTestTask( LazyLoadingTestTask.class ); + EnhancerTestUtils.runEnhancerTestTask( LazyLoadingIntegrationTestTask.class ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SuperEntity.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestTask.java similarity index 55% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SuperEntity.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestTask.java index ba122813e1..a21d0a6d01 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SuperEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestTask.java @@ -4,13 +4,19 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.bytecode.enhancement.entity; - -import javax.persistence.Entity; +package org.hibernate.test.bytecode.enhancement; /** - * @author Steve Ebersole + * @author Luis Barreiro */ -@Entity -public class SuperEntity { +public interface EnhancerTestTask { + + Class[] getAnnotatedClasses(); + + void prepare(); + + void execute(); + + void complete(); + } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestUtils.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestUtils.java index 3347d6cdec..9ef4899a79 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestUtils.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTestUtils.java @@ -6,34 +6,30 @@ */ package org.hibernate.test.bytecode.enhancement; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; -import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import javax.tools.JavaCompiler; +import javax.persistence.Embeddable; +import javax.persistence.Entity; import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; -import javax.tools.ToolProvider; import javassist.ClassPool; import javassist.CtClass; import javassist.LoaderClassPath; +import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.enhance.spi.Enhancer; -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.engine.internal.MutableEntityEntryFactory; -import org.hibernate.engine.spi.CompositeOwner; -import org.hibernate.engine.spi.CompositeTracker; import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.ManagedEntity; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.engine.spi.Status; import org.hibernate.internal.CoreLogging; @@ -41,13 +37,9 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.testing.junit4.BaseUnitTestCase; -import com.sun.tools.classfile.ConstantPoolException; -import com.sun.tools.javap.JavapTask; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -67,7 +59,7 @@ public abstract class EnhancerTestUtils extends BaseUnitTestCase { * method that performs the enhancement of a class * also checks the signature of enhanced entities methods using 'javap' decompiler */ - static Class enhanceAndDecompile(Class classToEnhance, ClassLoader cl) throws Exception { + public static Class enhanceAndDecompile(Class classToEnhance, ClassLoader cl) throws Exception { CtClass entityCtClass = generateCtClassForAnEntity( classToEnhance ); byte[] original = entityCtClass.toBytecode(); @@ -80,115 +72,110 @@ public abstract class EnhancerTestUtils extends BaseUnitTestCase { CtClass enhancedCtClass = cp.makeClass( new ByteArrayInputStream( enhanced ) ); enhancedCtClass.debugWriteFile( workingDir ); - decompileDumpedClass( classToEnhance.getName() ); + DecompileUtils.decompileDumpedClass( workingDir, classToEnhance.getName() ); Class enhancedClass = enhancedCtClass.toClass( cl, EnhancerTestUtils.class.getProtectionDomain() ); assertNotNull( enhancedClass ); return enhancedClass; } - private static void decompileDumpedClass(String className) { - try { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null ); - fileManager.setLocation( - StandardLocation.CLASS_OUTPUT, - Collections.singletonList( new File( workingDir ) ) - ); - - JavapTask javapTask = new JavapTask(); - for ( JavaFileObject jfo : fileManager.getJavaFileObjects( - workingDir + File.separator + getFilenameForClassName( - className - ) - ) ) { - try { - Set interfaceNames = new HashSet(); - Set fieldNames = new HashSet(); - Set methodNames = new HashSet(); - - JavapTask.ClassFileInfo info = javapTask.read( jfo ); - - log.infof( "decompiled class [%s]", info.cf.getName() ); - - for ( int i : info.cf.interfaces ) { - interfaceNames.add( info.cf.constant_pool.getClassInfo( i ).getName() ); - log.debugf( "declared iFace = ", info.cf.constant_pool.getClassInfo( i ).getName() ); - } - for ( com.sun.tools.classfile.Field f : info.cf.fields ) { - fieldNames.add( f.getName( info.cf.constant_pool ) ); - log.debugf( "declared field = ", f.getName( info.cf.constant_pool ) ); - } - for ( com.sun.tools.classfile.Method m : info.cf.methods ) { - methodNames.add( m.getName( info.cf.constant_pool ) ); - log.debugf( "declared method = ", m.getName( info.cf.constant_pool ) ); - } - - // checks signature against known interfaces - if ( interfaceNames.contains( PersistentAttributeInterceptor.class.getName() ) ) { - assertTrue( fieldNames.contains( EnhancerConstants.INTERCEPTOR_FIELD_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.INTERCEPTOR_GETTER_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.INTERCEPTOR_SETTER_NAME ) ); - } - if ( interfaceNames.contains( ManagedEntity.class.getName() ) ) { - assertTrue( methodNames.contains( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME ) ); - - assertTrue( fieldNames.contains( EnhancerConstants.ENTITY_ENTRY_FIELD_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.ENTITY_ENTRY_GETTER_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.ENTITY_ENTRY_SETTER_NAME ) ); - - assertTrue( fieldNames.contains( EnhancerConstants.PREVIOUS_FIELD_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.PREVIOUS_GETTER_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.PREVIOUS_SETTER_NAME ) ); - - assertTrue( fieldNames.contains( EnhancerConstants.NEXT_FIELD_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.NEXT_GETTER_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.NEXT_SETTER_NAME ) ); - } - if ( interfaceNames.contains( SelfDirtinessTracker.class.getName() ) ) { - assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_FIELD_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.TRACKER_GET_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CLEAR_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.TRACKER_HAS_CHANGED_NAME ) ); - } - if ( interfaceNames.contains( CompositeTracker.class.getName() ) ) { - assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER ) ); - assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER ) ); - } - if ( interfaceNames.contains( CompositeOwner.class.getName() ) ) { - assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) ); - assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) ); - } - } - catch (ConstantPoolException e) { - e.printStackTrace(); - } - } - } - catch (IOException ioe) { - assertNull( "Failed to open class file", ioe ); - } - catch (RuntimeException re) { - log.warnf( re, "WARNING: UNABLE DECOMPILE DUE TO %s", re.getMessage() ); - } - } - private static CtClass generateCtClassForAnEntity(Class entityClassToEnhance) throws Exception { ClassPool cp = new ClassPool( false ); - return cp.makeClass( - EnhancerTestUtils.class.getClassLoader().getResourceAsStream( - getFilenameForClassName( - entityClassToEnhance.getName() - ) - ) - ); + ClassLoader cl = EnhancerTestUtils.class.getClassLoader(); + return cp.makeClass( cl.getResourceAsStream( getFilenameForClassName( entityClassToEnhance.getName() ) ) ); } private static String getFilenameForClassName(String className) { return className.replace( '.', File.separatorChar ) + JavaFileObject.Kind.CLASS.extension; } + /* --- */ + + @SuppressWarnings("unchecked") + public static void runEnhancerTestTask(final Class task) { + + EnhancerTestTask taskObject = null; + ClassLoader defaultCL = Thread.currentThread().getContextClassLoader(); + try { + ClassLoader cl = EnhancerTestUtils.getEnhancerClassLoader( task.getPackage().getName() ); + EnhancerTestUtils.setupClassLoader( cl, task ); + EnhancerTestUtils.setupClassLoader( cl, task.newInstance().getAnnotatedClasses() ); + + Thread.currentThread().setContextClassLoader( cl ); + taskObject = ( (Class) cl.loadClass( task.getName() ) ).newInstance(); + + taskObject.prepare(); + taskObject.execute(); + } + catch (Exception e) { + throw new HibernateException( "could not execute task", e ); + } + finally { + try { + if ( taskObject != null ) { + taskObject.complete(); + } + } + catch (Throwable ignore) { + } + Thread.currentThread().setContextClassLoader( defaultCL ); + } + } + + private static void setupClassLoader(ClassLoader cl, Class... classesToLoad) { + for ( Class classToLoad : classesToLoad ) { + try { + cl.loadClass( classToLoad.getName() ); + } + catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + + private static ClassLoader getEnhancerClassLoader(final String packageName) { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if ( !name.startsWith( packageName ) ) { + return getParent().loadClass( name ); + } + final Class c = findLoadedClass( name ); + if ( c != null ) { + return c; + } + + final InputStream is = this.getResourceAsStream( getFilenameForClassName( name ) ); + if ( is == null ) { + throw new ClassNotFoundException( name + " not found" ); + } + + try { + final byte[] original = new byte[is.available()]; + new BufferedInputStream( is ).read( original ); + + // Only enhance classes annotated with Entity or Embeddable + final Class p = getParent().loadClass( name ); + if ( p.getAnnotation( Entity.class ) != null || p.getAnnotation( Embeddable.class ) != null ) { + final byte[] enhanced = new Enhancer( enhancementContext ).enhance( name, original ); + + Path debugOutput = Paths.get( workingDir + File.separator + getFilenameForClassName( name ) ); + Files.createDirectories( debugOutput.getParent() ); + Files.write( debugOutput, enhanced, StandardOpenOption.CREATE ); + + return defineClass( name, enhanced, 0, enhanced.length ); + } + else { + return defineClass( name, original, 0, original.length ); + } + } + catch (Throwable t) { + throw new ClassNotFoundException( name + " not found", t ); + } + } + }; + } + /** * clears the dirty set for an entity */ @@ -207,7 +194,7 @@ public abstract class EnhancerTestUtils extends BaseUnitTestCase { assertTrue( Arrays.asList( tracked ).containsAll( Arrays.asList( dirtyFields ) ) ); } - static EntityEntry makeEntityEntry() { + public static EntityEntry makeEntityEntry() { return MutableEntityEntryFactory.INSTANCE.createEntityEntry( Status.MANAGED, null, @@ -223,115 +210,4 @@ public abstract class EnhancerTestUtils extends BaseUnitTestCase { ); } - public static class LocalPersistentAttributeInterceptor implements PersistentAttributeInterceptor { - - @Override - public boolean readBoolean(Object obj, String name, boolean oldValue) { - log.infof( "Reading boolean [%s]", name ); - return oldValue; - } - - @Override - public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) { - log.infof( "Writing boolean []", name ); - return newValue; - } - - @Override - public byte readByte(Object obj, String name, byte oldValue) { - log.infof( "Reading byte [%s]", name ); - return oldValue; - } - - @Override - public byte writeByte(Object obj, String name, byte oldValue, byte newValue) { - log.infof( "Writing byte [%s]", name ); - return newValue; - } - - @Override - public char readChar(Object obj, String name, char oldValue) { - log.infof( "Reading char [%s]", name ); - return oldValue; - } - - @Override - public char writeChar(Object obj, String name, char oldValue, char newValue) { - log.infof( "Writing char [%s]", name ); - return newValue; - } - - @Override - public short readShort(Object obj, String name, short oldValue) { - log.infof( "Reading short [%s]", name ); - return oldValue; - } - - @Override - public short writeShort(Object obj, String name, short oldValue, short newValue) { - log.infof( "Writing short [%s]", name ); - return newValue; - } - - @Override - public int readInt(Object obj, String name, int oldValue) { - log.infof( "Reading int [%s]", name ); - return oldValue; - } - - @Override - public int writeInt(Object obj, String name, int oldValue, int newValue) { - log.infof( "Writing int [%s]", name ); - return newValue; - } - - @Override - public float readFloat(Object obj, String name, float oldValue) { - log.infof( "Reading float [%s]", name ); - return oldValue; - } - - @Override - public float writeFloat(Object obj, String name, float oldValue, float newValue) { - log.infof( "Writing float [%s]", name ); - return newValue; - } - - @Override - public double readDouble(Object obj, String name, double oldValue) { - log.infof( "Reading double [%s]", name ); - return oldValue; - } - - @Override - public double writeDouble(Object obj, String name, double oldValue, double newValue) { - log.infof( "Writing double [%s]", name ); - return newValue; - } - - @Override - public long readLong(Object obj, String name, long oldValue) { - log.infof( "Reading long [%s]", name ); - return oldValue; - } - - @Override - public long writeLong(Object obj, String name, long oldValue, long newValue) { - log.infof( "Writing long [%s]", name ); - return newValue; - } - - @Override - public Object readObject(Object obj, String name, Object oldValue) { - log.infof( "Reading Object [%s]", name ); - return oldValue; - } - - @Override - public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { - log.infof( "Writing Object [%s]", name ); - return newValue; - } - } - } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Customer.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Customer.java new file mode 100644 index 0000000000..bfc9fc9f52 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Customer.java @@ -0,0 +1,123 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +/** + * @author Ståle W. Pedersen + */ +@Entity +public class Customer { + + @Id + private int id; + + @OneToOne + private User user; + + private String firstName; + + private String lastName; + + @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private List customerInventories; + + @Version + private int version; + + public Customer() { + } + + public Integer getId() { + return id; + } + + public void setId(Integer customerId) { + this.id = customerId; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public List getInventories() { + if ( customerInventories == null ) { + customerInventories = new ArrayList(); + } + return customerInventories; + } + + public void setInventories (List inventories) { + this.customerInventories = inventories; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public void addInventory(CustomerInventory inventory) { + List list = getInventories(); + list.add( inventory ); + customerInventories = list; + } + + public CustomerInventory addInventory(String item) { + CustomerInventory inventory = new CustomerInventory( this, item ); + getInventories().add( inventory ); + return inventory; + } + + public int getVersion() { + return version; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + return id == ( (Customer) o ).id; + } + + @Override + public int hashCode() { + return new Integer( id ).hashCode(); + } + + @Override + public String toString() { + return this.getFirstName() + " " + this.getLastName(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/CustomerInventory.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/CustomerInventory.java new file mode 100644 index 0000000000..4a34098c8f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/CustomerInventory.java @@ -0,0 +1,103 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +/** + * @author Ståle W. Pedersen + */ + +import java.util.Comparator; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +@Entity +public class CustomerInventory implements Comparator { + + @Id + private Long id; + + @Id + private int custId; + + @ManyToOne(cascade = CascadeType.MERGE) + private Customer customer; + + @ManyToOne(cascade = CascadeType.MERGE) + private String vehicle; + + @Version + private int version; + + public CustomerInventory() { + } + + CustomerInventory(Customer customer, String vehicle) { + this.customer = customer; + this.vehicle = vehicle; + ; + } + + public String getVehicle() { + return vehicle; + } + + public Long getId() { + return id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public int getCustId() { + return custId; + } + + public int getVersion() { + return version; + } + + public int compare(CustomerInventory cdb1, CustomerInventory cdb2) { + return cdb1.id.compareTo( cdb2.id ); + } + + @Override + public boolean equals(Object obj) { + if ( obj == this ) { + return true; + } + if ( obj == null || !( obj instanceof CustomerInventory ) ) { + return false; + } + if ( this.id == ( (CustomerInventory) obj ).id ) { + return true; + } + if ( this.id != null && ( (CustomerInventory) obj ).id == null ) { + return false; + } + if ( this.id == null && ( (CustomerInventory) obj ).id != null ) { + return false; + } + + return this.id.equals( ( (CustomerInventory) obj ).id ); + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + custId; + return result; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Group.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Group.java new file mode 100644 index 0000000000..713f1da241 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/Group.java @@ -0,0 +1,55 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToMany; + +/** + * @author Ståle W. Pedersen + */ +@Entity +public class Group { + + @Id + private int id; + + @Column + private String name; + + @ManyToMany(mappedBy = "groups") + private Set users = new HashSet(); + + public Group() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getUsers() { + return users; + } + + public void setUsers(Set users) { + this.users = users; + } + + public void removeUser(User user) { + Set set = this.users; + set.remove( user ); + this.users = set; + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/ManyToManyAssociationTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/ManyToManyAssociationTestTask.java new file mode 100644 index 0000000000..8b0cb6714d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/ManyToManyAssociationTestTask.java @@ -0,0 +1,70 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.junit.Assert; + +/** + * @author Luis Barreiro + */ +public class ManyToManyAssociationTestTask extends AbstractEnhancerTestTask { + + public Class[] getAnnotatedClasses() { + return new Class[] {Group.class, User.class}; + } + + public void prepare() { + } + + public void execute() { + Group group = new Group(); + Group anotherGroup = new Group(); + + User user = new User(); + User anotherUser = new User(); + + user.addGroup( group ); + user.addGroup( anotherGroup ); + anotherUser.addGroup( group ); + + Assert.assertTrue( group.getUsers().size() == 2 ); + Assert.assertTrue( anotherGroup.getUsers().size() == 1 ); + + group.setUsers( new HashSet() ); + + Assert.assertTrue( user.getGroups().size() == 1 ); + Assert.assertTrue( anotherUser.getGroups().size() == 0 ); + + // Test remove + user.addGroup( group ); + anotherUser.addGroup( group ); + + Assert.assertTrue( group.getUsers().size() == 2 ); + Assert.assertTrue( anotherGroup.getUsers().size() == 1 ); + + Set groups = new HashSet( user.getGroups() ); + groups.remove( group ); + user.setGroups( groups ); + + Assert.assertTrue( group.getUsers().size() == 1 ); + Assert.assertTrue( anotherGroup.getUsers().size() == 1 ); + + groups.remove( anotherGroup ); + user.setGroups( groups ); + + Assert.assertTrue( group.getUsers().size() == 1 ); + // This happens (and is expected) because there was no snapshot taken before remove + Assert.assertTrue( anotherGroup.getUsers().size() == 1 ); + } + + protected void cleanup() { + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToManyAssociationTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToManyAssociationTestTask.java new file mode 100644 index 0000000000..6093ff566d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToManyAssociationTestTask.java @@ -0,0 +1,65 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +import java.util.List; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.junit.Assert; + +/** + * @author Luis Barreiro + */ +public class OneToManyAssociationTestTask extends AbstractEnhancerTestTask { + + public Class[] getAnnotatedClasses() { + return new Class[] {Customer.class, CustomerInventory.class, Group.class, User.class}; + } + + public void prepare() { + } + + public void execute() { + Customer customer = new Customer(); + Assert.assertTrue( customer.getInventories().isEmpty() ); + + CustomerInventory customerInventory = new CustomerInventory(); + customerInventory.setCustomer( customer ); + + Assert.assertTrue( customer.getInventories().size() == 1 ); + Assert.assertTrue( customer.getInventories().contains( customerInventory ) ); + + Customer anotherCustomer = new Customer(); + Assert.assertTrue( anotherCustomer.getInventories().isEmpty() ); + customerInventory.setCustomer( anotherCustomer ); + + Assert.assertTrue( customer.getInventories().isEmpty() ); + Assert.assertTrue( anotherCustomer.getInventories().size() == 1 ); + Assert.assertTrue( anotherCustomer.getInventories().get( 0 ) == customerInventory ); + + customer.addInventory( customerInventory ); + + Assert.assertTrue( customerInventory.getCustomer() == customer ); + Assert.assertTrue( anotherCustomer.getInventories().isEmpty() ); + Assert.assertTrue( customer.getInventories().size() == 1 ); + + customer.addInventory( new CustomerInventory() ); + Assert.assertTrue( customer.getInventories().size() == 2 ); + + // Test remove + + List inventories = customer.getInventories(); + inventories.remove( customerInventory ); + customer.setInventories( inventories ); + + // This happens (and is expected) because there was no snapshot taken before remove + Assert.assertNotNull( customerInventory.getCustomer() ); + } + + protected void cleanup() { + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToOneAssociationTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToOneAssociationTestTask.java new file mode 100644 index 0000000000..f860465b24 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/OneToOneAssociationTestTask.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +import java.util.UUID; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils; +import org.junit.Assert; + +/** + * @author Luis Barreiro + */ +public class OneToOneAssociationTestTask extends AbstractEnhancerTestTask { + + public Class[] getAnnotatedClasses() { + return new Class[] {Customer.class, User.class}; + } + + public void prepare() { + } + + public void execute() { + User user = new User(); + user.setLogin( UUID.randomUUID().toString() ); + + Customer customer = new Customer(); + customer.setUser( user ); + + Assert.assertEquals( customer, user.getCustomer() ); + + // check dirty tracking is set automatically with bi-directional association management + EnhancerTestUtils.checkDirtyTracking( user, "login", "customer" ); + + User anotherUser = new User(); + anotherUser.setLogin( UUID.randomUUID().toString() ); + + customer.setUser( anotherUser ); + + Assert.assertNull( user.getCustomer() ); + Assert.assertEquals( customer, anotherUser.getCustomer() ); + + user.setCustomer( new Customer() ); + + Assert.assertEquals( user, user.getCustomer().getUser() ); + } + + protected void cleanup() { + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/User.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/User.java new file mode 100644 index 0000000000..67049adabb --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/association/User.java @@ -0,0 +1,75 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.association; + +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.OneToOne; + +/** + * @author Ståle W. Pedersen + */ +@Entity +public class User { + + @Id + private int id; + + private String login; + + private String password; + + @OneToOne(mappedBy = "user") + private Customer customer; + + @ManyToMany + private Set groups; + + public User() { + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public void addGroup(Group group) { + Set groups = ( this.groups == null ? new HashSet() : this.groups ); + groups.add( group ); + this.groups = groups; + } + + public Set getGroups() { + return groups; + } + + public void setGroups(Set groups) { + this.groups = groups; + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicEnhancementTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicEnhancementTestTask.java new file mode 100644 index 0000000000..76aa577472 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicEnhancementTestTask.java @@ -0,0 +1,70 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.basic; + +import org.hibernate.engine.spi.ManagedEntity; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils; + +import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +/** + * @author Luis Barreiro + */ +public class BasicEnhancementTestTask extends AbstractEnhancerTestTask { + + public Class[] getAnnotatedClasses() { + return new Class[] {SimpleEntity.class}; + } + + public void prepare() { + } + + public void execute() { + SimpleEntity entity = new SimpleEntity(); + + // Call the new ManagedEntity methods + assertTyping( ManagedEntity.class, entity ); + ManagedEntity managedEntity = (ManagedEntity) entity; + assertSame( entity, managedEntity.$$_hibernate_getEntityInstance() ); + + assertNull( managedEntity.$$_hibernate_getEntityEntry() ); + managedEntity.$$_hibernate_setEntityEntry( EnhancerTestUtils.makeEntityEntry() ); + assertNotNull( managedEntity.$$_hibernate_getEntityEntry() ); + managedEntity.$$_hibernate_setEntityEntry( null ); + assertNull( managedEntity.$$_hibernate_getEntityEntry() ); + + managedEntity.$$_hibernate_setNextManagedEntity( managedEntity ); + managedEntity.$$_hibernate_setPreviousManagedEntity( managedEntity ); + assertSame( managedEntity, managedEntity.$$_hibernate_getNextManagedEntity() ); + assertSame( managedEntity, managedEntity.$$_hibernate_getPreviousManagedEntity() ); + + // Add an attribute interceptor... + assertTyping( PersistentAttributeInterceptable.class, entity ); + PersistentAttributeInterceptable interceptableEntity = (PersistentAttributeInterceptable) entity; + + assertNull( interceptableEntity.$$_hibernate_getInterceptor() ); + interceptableEntity.$$_hibernate_setInterceptor( new ObjectAttributeMarkerInterceptor() ); + assertNotNull( interceptableEntity.$$_hibernate_getInterceptor() ); + + assertNull( entity.anUnspecifiedObject ); + entity.setAnObject( new Object() ); + assertSame( entity.anUnspecifiedObject, ObjectAttributeMarkerInterceptor.WRITE_MARKER ); + assertSame( entity.getAnObject(), ObjectAttributeMarkerInterceptor.READ_MARKER ); + entity.setAnObject( null ); + assertSame( entity.anUnspecifiedObject, ObjectAttributeMarkerInterceptor.WRITE_MARKER ); + + } + + protected void cleanup() { + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/MostBasicEnhancementTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicInSessionTest.java similarity index 69% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/MostBasicEnhancementTest.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicInSessionTest.java index f7fdd3702e..dce1a74ea6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/MostBasicEnhancementTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/BasicInSessionTest.java @@ -4,14 +4,17 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.bytecode.enhancement; +package org.hibernate.test.bytecode.enhancement.basic; + +import java.net.URL; +import java.net.URLClassLoader; import org.hibernate.Session; -import org.hibernate.test.bytecode.enhancement.entity.MyEntity; -import org.junit.Test; - import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils; +import org.junit.Assert; +import org.junit.Test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -20,10 +23,10 @@ import static org.junit.Assert.assertSame; /** * @author Steve Ebersole */ -public class MostBasicEnhancementTest extends BaseCoreFunctionalTestCase { +public class BasicInSessionTest extends BaseCoreFunctionalTestCase { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { MyEntity.class }; + return new Class[] {MyEntity.class}; } @Test @@ -37,8 +40,8 @@ public class MostBasicEnhancementTest extends BaseCoreFunctionalTestCase { s = openSession(); s.beginTransaction(); - MyEntity myEntity1 = (MyEntity) s.get( MyEntity.class, 1L ); - MyEntity myEntity2 = (MyEntity) s.get( MyEntity.class, 2L ); + MyEntity myEntity1 = s.get( MyEntity.class, 1L ); + MyEntity myEntity2 = s.get( MyEntity.class, 2L ); assertNotNull( myEntity1.$$_hibernate_getEntityInstance() ); assertSame( myEntity1, myEntity1.$$_hibernate_getEntityInstance() ); @@ -59,5 +62,15 @@ public class MostBasicEnhancementTest extends BaseCoreFunctionalTestCase { assertNull( myEntity1.$$_hibernate_getEntityEntry() ); } + @Test + public void enhacementTest() { + try { + EnhancerTestUtils.enhanceAndDecompile( SimpleEntity.class, new URLClassLoader( new URL[0] ) ); + } + catch (Exception e) { + e.printStackTrace(); + Assert.fail( "Unexpected exception in EnhancerTestUtils.enhanceAndDecompile(): " + e.getMessage() ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/MyEntity.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/MyEntity.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/MyEntity.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/MyEntity.java index ee4975b7d7..1f09c33228 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/MyEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/MyEntity.java @@ -4,20 +4,21 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.bytecode.enhancement.entity; - -import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.ManagedEntity; +package org.hibernate.test.bytecode.enhancement.basic; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Transient; +import org.hibernate.engine.spi.EntityEntry; +import org.hibernate.engine.spi.ManagedEntity; + /** * @author Steve Ebersole */ @Entity public class MyEntity implements ManagedEntity { + @Transient private transient EntityEntry entityEntry; @Transient @@ -25,7 +26,9 @@ public class MyEntity implements ManagedEntity { @Transient private transient ManagedEntity next; + @Id private Long id; + private String name; public MyEntity() { @@ -35,7 +38,6 @@ public class MyEntity implements ManagedEntity { this.id = id; } - @Id public Long getId() { return id; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java new file mode 100644 index 0000000000..5df883a183 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/ObjectAttributeMarkerInterceptor.java @@ -0,0 +1,115 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.test.bytecode.enhancement.basic; + +import org.hibernate.engine.spi.PersistentAttributeInterceptor; + +/** + * Interceptor that stores a marker object on write, instead of the provided value. + * Also returns another marker object on read. Marks only non-primitive fields. + * + * @author Luis Barreiro + */ +public class ObjectAttributeMarkerInterceptor implements PersistentAttributeInterceptor { + + public static final Object READ_MARKER = new Object(); + public static final Object WRITE_MARKER = new Object(); + + public ObjectAttributeMarkerInterceptor() { + } + + @Override + public boolean readBoolean(Object obj, String name, boolean oldValue) { + return oldValue; + } + + @Override + public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) { + return newValue; + } + + @Override + public byte readByte(Object obj, String name, byte oldValue) { + return oldValue; + } + + @Override + public byte writeByte(Object obj, String name, byte oldValue, byte newValue) { + return newValue; + } + + @Override + public char readChar(Object obj, String name, char oldValue) { + return oldValue; + } + + @Override + public char writeChar(Object obj, String name, char oldValue, char newValue) { + return newValue; + } + + @Override + public short readShort(Object obj, String name, short oldValue) { + return oldValue; + } + + @Override + public short writeShort(Object obj, String name, short oldValue, short newValue) { + return newValue; + } + + @Override + public int readInt(Object obj, String name, int oldValue) { + return oldValue; + } + + @Override + public int writeInt(Object obj, String name, int oldValue, int newValue) { + return newValue; + } + + @Override + public float readFloat(Object obj, String name, float oldValue) { + return oldValue; + } + + @Override + public float writeFloat(Object obj, String name, float oldValue, float newValue) { + return newValue; + } + + @Override + public double readDouble(Object obj, String name, double oldValue) { + return oldValue; + } + + @Override + public double writeDouble(Object obj, String name, double oldValue, double newValue) { + return newValue; + } + + @Override + public long readLong(Object obj, String name, long oldValue) { + return oldValue; + } + + @Override + public long writeLong(Object obj, String name, long oldValue, long newValue) { + return newValue; + } + + @Override + public Object readObject(Object obj, String name, Object oldValue) { + return READ_MARKER; + } + + @Override + public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { + return WRITE_MARKER; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SubEntity.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/SimpleEntity.java similarity index 54% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SubEntity.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/SimpleEntity.java index 8965cd9d8f..652fd8b0ee 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SubEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/SimpleEntity.java @@ -4,22 +4,36 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.bytecode.enhancement.entity; +package org.hibernate.test.bytecode.enhancement.basic; +import java.util.List; +import java.util.Set; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.OneToMany; /** * @author Steve Ebersole */ @Entity -public class SubEntity extends SuperEntity { - private Long id; - private String name; - private boolean active; - private long someNumber; +public class SimpleEntity { @Id + private Long id; + + private String name; + + private boolean active; + + private long someNumber; + + Object anUnspecifiedObject; + + private List someStrings; + + @OneToMany + private Set someInts; + public Long getId() { return id; } @@ -51,4 +65,28 @@ public class SubEntity extends SuperEntity { public void setSomeNumber(long someNumber) { this.someNumber = someNumber; } + + public Object getAnObject() { + return anUnspecifiedObject; + } + + public void setAnObject(Object providedObject) { + this.anUnspecifiedObject = providedObject; + } + + public List getSomeStrings() { + return someStrings; + } + + public void setSomeStrings(List someStrings) { + this.someStrings = someStrings; + } + + public Set getSomeInts() { + return someInts; + } + + public void setSomeInts(Set someInts) { + this.someInts = someInts; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Address.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Address.java new file mode 100644 index 0000000000..98ace502f5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Address.java @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.dirty; + +import java.io.Serializable; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; + +/** + * @author Ståle W. Pedersen + */ +@Embeddable +public class Address implements Serializable { + + private String street1; + private String street2; + private String city; + private String state; + private String zip; + private String phone; + + @Embedded + private Country country; + + public Address() { + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Country getCountry() { + return country; + } + + public void setCountry(Country country) { + this.country = country; + } + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Country.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Country.java similarity index 65% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Country.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Country.java index 020faed1eb..ea9ff9231a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Country.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/Country.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.bytecode.enhancement.entity; +package org.hibernate.test.bytecode.enhancement.dirty; import javax.persistence.Embeddable; @@ -14,13 +14,13 @@ import javax.persistence.Embeddable; @Embeddable public class Country { - private String name; + private String name; - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/DirtyTrackingTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/DirtyTrackingTestTask.java new file mode 100644 index 0000000000..96d1586a4b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/DirtyTrackingTestTask.java @@ -0,0 +1,91 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.dirty; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils; + +/** + * @author Luis Barreiro + */ +public class DirtyTrackingTestTask extends AbstractEnhancerTestTask { + + public Class[] getAnnotatedClasses() { + return new Class[] {SimpleEntity.class}; + } + + public void prepare() { + } + + public void execute() { + SimpleEntity entity = new SimpleEntity(); + + // Basic single field + entity.getId(); + EnhancerTestUtils.checkDirtyTracking( entity ); + entity.setId( 1l ); + EnhancerTestUtils.checkDirtyTracking( entity, "id" ); + EnhancerTestUtils.clearDirtyTracking( entity ); + entity.setId( entity.getId() ); + EnhancerTestUtils.checkDirtyTracking( entity ); + + // Basic multi-field + entity.setId( 2l ); + entity.setActive( !entity.isActive() ); + entity.setSomeNumber( 193L ); + EnhancerTestUtils.checkDirtyTracking( entity, "id", "active", "someNumber" ); + EnhancerTestUtils.clearDirtyTracking( entity ); + + // Setting the same value should not make it dirty + entity.setSomeNumber( 193L ); + EnhancerTestUtils.checkDirtyTracking( entity ); + + // Collection + List strings = new ArrayList(); + strings.add( "FooBar" ); + entity.setSomeStrings( strings ); + EnhancerTestUtils.checkDirtyTracking( entity, "someStrings" ); + EnhancerTestUtils.clearDirtyTracking( entity ); + + strings.add( "BarFoo" ); + EnhancerTestUtils.checkDirtyTracking( entity, "someStrings" ); + EnhancerTestUtils.clearDirtyTracking( entity ); + + // Association: this should not set the entity to dirty + Set intSet = new HashSet(); + intSet.add( 42 ); + entity.setSomeInts( intSet ); + EnhancerTestUtils.checkDirtyTracking( entity ); + + // testing composite object + Address address = new Address(); + entity.setAddress( address ); + address.setCity( "Arendal" ); + EnhancerTestUtils.checkDirtyTracking( entity, "address", "address.city" ); + EnhancerTestUtils.clearDirtyTracking( entity ); + + // make sure that new composite instances are cleared + Address address2 = new Address(); + entity.setAddress( address2 ); + address.setStreet1( "Heggedalveien" ); + EnhancerTestUtils.checkDirtyTracking( entity, "address" ); + + Country country = new Country(); + address2.setCountry( country ); + country.setName( "Norway" ); + EnhancerTestUtils.checkDirtyTracking( entity, "address", "address.country", "address.country.name" ); + + } + + protected void cleanup() { + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/SimpleEntity.java similarity index 60% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SimpleEntity.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/SimpleEntity.java index 62a5e056ac..c11763040d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SimpleEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/dirty/SimpleEntity.java @@ -4,33 +4,38 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.bytecode.enhancement.entity; +package org.hibernate.test.bytecode.enhancement.dirty; +import java.util.List; +import java.util.Set; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToMany; -import java.util.List; -import java.util.Set; /** * @author Steve Ebersole */ @Entity public class SimpleEntity { - private Long id; - private String name; - private boolean active; - private long someNumber; - private List someStrings; - - @OneToMany - private Set someInts; - - @Embedded - private Address address; @Id + private Long id; + + private String name; + + private boolean active; + + private long someNumber; + + private List someStrings; + + @OneToMany + private Set someInts; + + @Embedded + private Address address; + public Long getId() { return id; } @@ -63,27 +68,28 @@ public class SimpleEntity { this.someNumber = someNumber; } - public List getSomeStrings() { - return someStrings; - } + public List getSomeStrings() { + return someStrings; + } - public void setSomeStrings(List someStrings) { - this.someStrings = someStrings; - } + public void setSomeStrings(List someStrings) { + this.someStrings = someStrings; + } - public Address getAddress() { - return address; - } + public Address getAddress() { + return address; + } - public void setAddress(Address address) { - this.address = address; - } + public void setAddress(Address address) { + this.address = address; + } - public Set getSomeInts() { - return someInts; - } + public Set getSomeInts() { + return someInts; + } + + public void setSomeInts(Set someInts) { + this.someInts = someInts; + } - public void setSomeInts(Set someInts) { - this.someInts = someInts; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Address.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Address.java deleted file mode 100644 index 626f06e0fa..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/Address.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity; - -import javax.persistence.Embeddable; -import javax.persistence.Embedded; -import java.io.Serializable; - -/** - * @author Ståle W. Pedersen - */ -@Embeddable -public class Address implements Serializable { - - private String street1; - private String street2; - private String city; - private String state; - - @Embedded - private Country country; - private String zip; - private String phone; - - public Address() { - } - - public String getStreet1() { - return street1; - } - - public void setStreet1(String street1) { - this.street1 = street1; - } - - public String getStreet2() { - return street2; - } - - public void setStreet2(String street2) { - this.street2 = street2; - } - - public String getCity() { - return city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - public Country getCountry() { - return country; - } - - public void setCountry(Country country) { - this.country = country; - } - - public String getZip() { - return zip; - } - - public void setZip(String zip) { - this.zip = zip; - } - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SampleEntity.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SampleEntity.java deleted file mode 100644 index 0acbdad845..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/SampleEntity.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity; - -import javax.persistence.Id; -import javax.persistence.Transient; - -import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.ManagedEntity; -import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; - -/** - * @author Steve Ebersole - */ -public class SampleEntity implements ManagedEntity, PersistentAttributeInterceptable { - @Transient - private transient EntityEntry entityEntry; - @Transient - private transient ManagedEntity previous; - @Transient - private transient ManagedEntity next; - @Transient - private transient PersistentAttributeInterceptor interceptor; - - private Long id; - private String name; - - @Id - public Long getId() { - return hibernate_read_id(); - } - - public void setId(Long id) { - hibernate_write_id( id ); - } - - public String getName() { - return hibernate_read_name(); - } - - public void setName(String name) { - hibernate_write_name( name ); - } - - private Long hibernate_read_id() { - if ( $$_hibernate_getInterceptor() != null ) { - this.id = (Long) $$_hibernate_getInterceptor().readObject( this, "id", this.id ); - } - return id; - } - - private void hibernate_write_id(Long id) { - Long localVar = id; - if ( $$_hibernate_getInterceptor() != null ) { - localVar = (Long) $$_hibernate_getInterceptor().writeObject( this, "id", this.id, id ); - } - this.id = localVar; - } - - private String hibernate_read_name() { - if ( $$_hibernate_getInterceptor() != null ) { - this.name = (String) $$_hibernate_getInterceptor().readObject( this, "name", this.name ); - } - return name; - } - - private void hibernate_write_name(String name) { - String localName = name; - if ( $$_hibernate_getInterceptor() != null ) { - localName = (String) $$_hibernate_getInterceptor().writeObject( this, "name", this.name, name ); - } - this.name = localName; - } - - @Override - public Object $$_hibernate_getEntityInstance() { - return this; - } - - @Override - public EntityEntry $$_hibernate_getEntityEntry() { - return entityEntry; - } - - @Override - public void $$_hibernate_setEntityEntry(EntityEntry entityEntry) { - this.entityEntry = entityEntry; - } - - @Override - public ManagedEntity $$_hibernate_getNextManagedEntity() { - return next; - } - - @Override - public void $$_hibernate_setNextManagedEntity(ManagedEntity next) { - this.next = next; - } - - @Override - public ManagedEntity $$_hibernate_getPreviousManagedEntity() { - return previous; - } - - @Override - public void $$_hibernate_setPreviousManagedEntity(ManagedEntity previous) { - this.previous = previous; - } - - @Override - public PersistentAttributeInterceptor $$_hibernate_getInterceptor() { - return interceptor; - } - - @Override - public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor interceptor) { - this.interceptor = interceptor; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Address.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Address.java deleted file mode 100644 index b1f89d2d9d..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Address.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */package org.hibernate.test.bytecode.enhancement.entity.customer; - -import javax.persistence.Embeddable; -import java.io.Serializable; - -/** - * @author Ståle W. Pedersen - */ -@Embeddable -public class Address implements Serializable { - private String street1; - private String street2; - private String city; - private String state; - private String country; - private String zip; - private String phone; - - public Address() { - } - public Address(String street1, String street2, String city, String state, - String country, String zip, String phone) { - this.street1 = street1; - this.street2 = street2; - this.city = city; - this.state = state; - this.country = country; - setZip(zip); - setPhone(phone); - } - - public String toString() { - return street1 + "\n" + street2 + "\n" + city + "," + state + " " + zip + "\n" + phone; - } - - public String getStreet1() { - return street1; - } - - public void setStreet1(String street1) { - this.street1 = street1; - } - - public String getStreet2() { - return street2; - } - - public void setStreet2(String street2) { - this.street2 = street2; - } - - public String getCity() { - return city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - public String getCountry() { - return country; - } - - public void setCountry(String country) { - this.country = country; - } - - public String getZip() { - return zip; - } - - public void setZip(String zip) { - assertNumeric(zip, "Non-numeric zip "); - this.zip = zip; - - } - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - assertNumeric(zip, "Non-numeric phone "); - this.phone = phone; - } - - void assertNumeric(String s, String error) { - for (int i=0; i. - */ -package org.hibernate.test.bytecode.enhancement.entity.customer; - -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Version; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; - -/** - * @author Ståle W. Pedersen - */ -@Entity -@Table(name="O_CUSTOMER") -public class Customer { - public static final String QUERY_ALL = "Customer.selectAll"; - public static final String QUERY_COUNT = "Customer.count"; - public static final String QUERY_BY_CREDIT = "Customer.selectByCreditLimit"; - - public static final String BAD_CREDIT = "BC"; - - @Id - @Column(name="C_ID") - private int id; - - @OneToOne - private User user; - - @Column(name="C_FIRST") - private String firstName; - - @Column(name="C_LAST") - private String lastName; - - @Column(name="C_CONTACT") - private String contact; - - @Column(name="C_CREDIT") - private String credit; - - @Column(name="C_CREDIT_LIMIT") - private BigDecimal creditLimit; - - @Column(name="C_SINCE") - @Temporal(TemporalType.DATE) - private Calendar since; - - @Column(name="C_BALANCE") - private BigDecimal balance; - - @Column(name="C_YTD_PAYMENT") - private BigDecimal ytdPayment; - - @OneToMany(mappedBy="customer", cascade= CascadeType.ALL, fetch= FetchType.EAGER) - private List customerInventories; - - @Embedded - @AttributeOverrides( - {@AttributeOverride(name="street1",column=@Column(name="C_STREET1")), - @AttributeOverride(name="street2",column=@Column(name="C_STREET2")), - @AttributeOverride(name="city", column=@Column(name="C_CITY")), - @AttributeOverride(name="state", column=@Column(name="C_STATE")), - @AttributeOverride(name="country",column=@Column(name="C_COUNTRY")), - @AttributeOverride(name="zip", column=@Column(name="C_ZIP")), - @AttributeOverride(name="phone", column=@Column(name="C_PHONE"))}) - private Address address; - - @Version - @Column(name = "C_VERSION") - private int version; - - public Customer() { - } - - public Customer(String first, String last, Address address, - String contact, String credit, BigDecimal creditLimit, - BigDecimal balance, BigDecimal YtdPayment) { - - this.firstName = first; - this.lastName = last; - this.address = address; - this.contact = contact; - this.since = Calendar.getInstance(); - this.credit = credit; - this.creditLimit = creditLimit; - this.balance = balance; - this.ytdPayment = YtdPayment; - } - - public Integer getId() { - return id; - } - - public void setId(Integer customerId) { - this.id = customerId; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Address getAddress() { - return address; - } - - public void setAddress(Address address) { - this.address = address; - } - - public String getContact() { - return contact; - } - - public void setContact(String contact) { - this.contact = contact; - } - - public String getCredit() { - return credit; - } - - public void setCredit(String credit) { - this.credit = credit; - } - - public BigDecimal getCreditLimit() { - return creditLimit; - } - - public void setCreditLimit(BigDecimal creditLimit) { - this.creditLimit = creditLimit; - } - - public Calendar getSince() { - return since; - } - - public void setSince(Calendar since) { - this.since = since; - } - - public BigDecimal getBalance() { - return balance; - } - - public void setBalance(BigDecimal balance) { - this.balance = balance; - } - - public void changeBalance(BigDecimal change) { - setBalance(balance.add(change).setScale(2, BigDecimal.ROUND_DOWN)); - } - - public BigDecimal getYtdPayment() { - return ytdPayment; - } - - public void setYtdPayment(BigDecimal ytdPayment) { - this.ytdPayment = ytdPayment; - } - - public List getInventories() { - if (customerInventories == null){ - customerInventories = new ArrayList(); - } - return customerInventories; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public void addInventory(CustomerInventory inventory) { - List list = getInventories(); - list.add(inventory); - customerInventories = list; - } - - public CustomerInventory addInventory(String item, int quantity, - BigDecimal totalValue) { - - CustomerInventory inventory = new CustomerInventory(this, item, - quantity, totalValue); - getInventories().add(inventory); - return inventory; - } - - public int getVersion() { - return version; - } - - public boolean hasSufficientCredit(BigDecimal amount) { - return !BAD_CREDIT.equals(getCredit()) - && creditLimit != null - && creditLimit.compareTo(amount) >= 0; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - return id == ((Customer) o).id; - } - - @Override - public int hashCode() { - return new Integer(id).hashCode(); - } - - @Override - public String toString() { - return this.getFirstName() + " " + this.getLastName(); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventory.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventory.java deleted file mode 100644 index b65b635434..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventory.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity.customer; - -/** - * @author Ståle W. Pedersen - */ - -import java.io.Serializable; -import java.math.BigDecimal; -import java.util.Comparator; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Version; - -@SuppressWarnings("serial") -@Entity -@Table(name="O_CUSTINVENTORY") -@IdClass(CustomerInventoryPK.class) -public class CustomerInventory implements Serializable, Comparator { - - public static final String QUERY_COUNT = "CustomerInventory.count"; - - @Id - @TableGenerator(name="inventory", - table="U_SEQUENCES", - pkColumnName="S_ID", - valueColumnName="S_NEXTNUM", - pkColumnValue="inventory", - allocationSize=1000) - @GeneratedValue(strategy= GenerationType.TABLE,generator="inventory") - @Column(name="CI_ID") - private Long id; - - @Id - @Column(name = "CI_CUSTOMERID", insertable = false, updatable = false) - private int custId; - - @ManyToOne(cascade= CascadeType.MERGE) - @JoinColumn(name="CI_CUSTOMERID") - private Customer customer; - - @ManyToOne(cascade=CascadeType.MERGE) - @JoinColumn(name = "CI_ITEMID") - private String vehicle; - - @Column(name="CI_VALUE") - private BigDecimal totalCost; - - @Column(name="CI_QUANTITY") - private int quantity; - - @Version - @Column(name = "CI_VERSION") - private int version; - - public CustomerInventory() { - } - - CustomerInventory(Customer customer, String vehicle, int quantity, - BigDecimal totalValue) { - this.customer = customer; - this.vehicle = vehicle; - this.quantity = quantity; - this.totalCost = totalValue; - } - - public String getVehicle() { - return vehicle; - } - - public BigDecimal getTotalCost() { - return totalCost; - } - - public int getQuantity() { - return quantity; - } - - public Long getId() { - return id; - } - - public Customer getCustomer() { - return customer; - } - - public void setCustomer(Customer customer) { - this.customer = customer; - } - - public int getCustId() { - return custId; - } - - public int getVersion() { - return version; - } - - public int compare(CustomerInventory cdb1, CustomerInventory cdb2) { - return cdb1.id.compareTo(cdb2.id); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) - return true; - if (obj == null || !(obj instanceof CustomerInventory)) - return false; - if (this.id == ((CustomerInventory)obj).id) - return true; - if (this.id != null && ((CustomerInventory)obj).id == null) - return false; - if (this.id == null && ((CustomerInventory)obj).id != null) - return false; - - return this.id.equals(((CustomerInventory)obj).id); - } - - @Override - public int hashCode() { - int result = id.hashCode(); - result = 31 * result + custId; - return result; - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventoryPK.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventoryPK.java deleted file mode 100644 index 682b28e88f..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/CustomerInventoryPK.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity.customer; - -import java.io.Serializable; - -/** - * @author Ståle W. Pedersen - */ -public class CustomerInventoryPK implements Serializable { - - private Long id; - private int custId; - - public CustomerInventoryPK() { - } - - public CustomerInventoryPK(Long id, int custId) { - this.id = id; - this.custId = custId; - } - - public boolean equals(Object other) { - if (other == this) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - CustomerInventoryPK cip = (CustomerInventoryPK) other; - return (custId == cip.custId && (id == cip.id || - ( id != null && id.equals(cip.id)))); - } - - public int hashCode() { - return (id == null ? 0 : id.hashCode()) ^ custId; - } - - public Long getId() { - return id; - } - - public int getCustId() { - return custId; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Group.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Group.java deleted file mode 100644 index 461ad89323..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/Group.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity.customer; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.ManyToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import java.util.HashSet; -import java.util.Set; - -/** - * @author Ståle W. Pedersen - */ -@Entity -@Table(name = "GROUP") -@SequenceGenerator(name = "GROUP_SEQUENCE", sequenceName = "GROUP_SEQUENCE", allocationSize = 1, initialValue = 0) -public class Group { - - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GROUP_SEQUENCE") - private int id; - - @Column - private String name; - - @ManyToMany(mappedBy = "groups") - private Set users = new HashSet(); - - public Group() { - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Set getUsers() { - return users; - } - - public void setUsers(Set users) { - this.users = users; - } - - public void removeUser(User user) { - Set set = this.users; - set.remove(user); - this.users = set; - } -} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/SupplierComponentPK.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/SupplierComponentPK.java deleted file mode 100644 index 699a12b66e..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/SupplierComponentPK.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity.customer; - -import javax.persistence.Embeddable; - -/** - * @author Ståle W. Pedersen - */ -@Embeddable -public class SupplierComponentPK { - - String componentID; - int supplierID; - - public SupplierComponentPK() { - } - - public SupplierComponentPK(String suppCompID, int suppCompSuppID) { - this.componentID = suppCompID; - this.supplierID = suppCompSuppID; - } - - public String getComponentID() { - return componentID; - } - - public int getSupplierID() { - return supplierID; - } - - @Override - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + componentID.hashCode(); - result = PRIME * result + supplierID; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - final SupplierComponentPK other = (SupplierComponentPK) obj; - return componentID.equals(other.componentID); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/User.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/User.java deleted file mode 100644 index 5789e13c4a..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/entity/customer/User.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.entity.customer; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.ManyToMany; -import javax.persistence.OneToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import java.util.HashSet; -import java.util.Set; - -/** - * @author Ståle W. Pedersen - */ -@Entity -@Table(name = "USER") -@SequenceGenerator(name = "USER_SEQUENCE", sequenceName = "USER_SEQUENCE", allocationSize = 1, initialValue = 0) -public class User { - - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQUENCE") - private int id; - - @Column - private String login; - - @Column - private String password; - - @OneToOne(mappedBy = "user") - private Customer customer; - - @ManyToMany - private Set groups; - - public User() { - } - - public Customer getCustomer() { - return customer; - } - - public void setCustomer(Customer customer) { - this.customer = customer; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public void addGroup(Group group) { - Set set = (groups == null ? new HashSet() : groups); - set.add(group); - groups = set; - } - - public Set getGroups() { - return groups; - } - - public void setGroups(Set groups) { - this.groups = groups; - } -} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java new file mode 100644 index 0000000000..b57824d936 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Child.java @@ -0,0 +1,61 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import org.hibernate.annotations.LazyToOne; +import org.hibernate.annotations.LazyToOneOption; + +/** + * @author Luis Barreiro + */ + +@Entity +public class Child { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + Long id; + + String name; + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @LazyToOne(LazyToOneOption.NO_PROXY) + Parent parent; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingIntegrationTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingIntegrationTestTask.java new file mode 100644 index 0000000000..5fe860ea03 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingIntegrationTestTask.java @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils; +import org.junit.Assert; + +/** + * @author Luis Barreiro + */ +public class LazyLoadingIntegrationTestTask extends AbstractEnhancerTestTask { + + private static final int CHILDREN_SIZE = 10; + private Long parentID; + private Long lastChildID; + + public Class[] getAnnotatedClasses() { + return new Class[] {Parent.class, Child.class}; + } + + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + super.prepare( cfg ); + + Session s = getFactory().openSession(); + s.beginTransaction(); + + Parent parent = new Parent(); + parent.setChildren( new ArrayList( CHILDREN_SIZE ) ); + for ( int i = 0; i < CHILDREN_SIZE; i++ ) { + final Child child = new Child(); + // Association management should kick in here + child.setParent( parent ); + s.persist( child ); + lastChildID = child.getId(); + } + s.persist( parent ); + parentID = parent.getId(); + + s.getTransaction().commit(); + s.clear(); + s.close(); + } + + public void execute() { + Session s = getFactory().openSession(); + s.beginTransaction(); + + Child loadedChild = s.load( Child.class, lastChildID ); + EnhancerTestUtils.checkDirtyTracking( loadedChild ); + + loadedChild.setName( "Barrabas" ); + EnhancerTestUtils.checkDirtyTracking( loadedChild, "name" ); + + Parent loadedParent = loadedChild.getParent(); + EnhancerTestUtils.checkDirtyTracking( loadedChild, "name" ); + EnhancerTestUtils.checkDirtyTracking( loadedParent ); + + List loadedChildren = new ArrayList( loadedParent.getChildren() ); + loadedChildren.remove( 0 ); + loadedChildren.remove( loadedChild ); + loadedParent.setChildren( loadedChildren ); + + EnhancerTestUtils.checkDirtyTracking( loadedParent ); + Assert.assertNull( loadedChild.parent ); + + s.getTransaction().commit(); + s.close(); + } + + protected void cleanup() { + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java new file mode 100644 index 0000000000..6b7d422858 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTestTask.java @@ -0,0 +1,95 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.proxy.HibernateProxy; + +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils; +import org.junit.Assert; + +/** + * @author Luis Barreiro + */ +public class LazyLoadingTestTask extends AbstractEnhancerTestTask { + + private static final int CHILDREN_SIZE = 10; + private Long parentID; + private Long lastChildID; + + public Class[] getAnnotatedClasses() { + return new Class[] {Parent.class, Child.class}; + } + + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + super.prepare( cfg ); + + Session s = getFactory().openSession(); + s.beginTransaction(); + + Parent parent = new Parent(); + parent.setChildren(new ArrayList()); + for ( int i = 0; i < CHILDREN_SIZE; i++ ) { + final Child child = new Child(); + child.setParent( parent ); + s.persist( child ); + lastChildID = child.getId(); + } + s.persist( parent ); + parentID = parent.getId(); + + s.getTransaction().commit(); + s.clear(); + s.close(); + } + + public void execute() { + Session s = getFactory().openSession(); + s.beginTransaction(); + + Child loadedChild = s.load( Child.class, lastChildID ); + + Assert.assertNull( "Lazy field 'parent' is initialized", loadedChild.parent ); + Assert.assertFalse( loadedChild instanceof HibernateProxy ); + + Parent loadedParent = loadedChild.getParent(); + + EnhancerTestUtils.checkDirtyTracking( loadedChild ); + + Assert.assertNotNull( "Lazy field 'parent' is not loaded", loadedChild.parent ); + Assert.assertNull( "Lazy field 'children' is initialized", loadedParent.children ); + Assert.assertFalse( loadedParent instanceof HibernateProxy ); + Assert.assertTrue( parentID.equals( loadedParent.id ) ); + + Collection loadedChildren = loadedParent.getChildren(); + + EnhancerTestUtils.checkDirtyTracking( loadedChild ); + EnhancerTestUtils.checkDirtyTracking( loadedParent ); + + Assert.assertNotNull( "Lazy field 'children' is not loaded", loadedParent.children ); + Assert.assertFalse( loadedChildren instanceof HibernateProxy ); + Assert.assertEquals( CHILDREN_SIZE, loadedChildren.size() ); + Assert.assertTrue( loadedChildren.contains( loadedChild ) ); + + s.getTransaction().commit(); + s.close(); + } + + protected void cleanup() { + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Parent.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Parent.java new file mode 100644 index 0000000000..e2d374a695 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/Parent.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy; + +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +/** + * @author Luis Barreiro + */ + +@Entity +public class Parent { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + Long id; + + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + List children; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + +}