HHH-8558 - Bytecode enhancer: testsuite reorganization with added lazy loading tests

This commit is contained in:
barreiro 2015-06-07 00:40:14 +01:00 committed by Steve Ebersole
parent c6fa2b1df1
commit 44a02e5efc
36 changed files with 1665 additions and 1579 deletions

View File

@ -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.%<s.iterator(); itr.hasNext(); ) { %s target = (%<s) itr.next(); if ($1 == null || !$1.contains(target)) target.%s(null); }%n",
"if ($0.%s != null) { Object[] array = $0.%<s.toArray(); for (int i = 0; i < array.length; i++) { %s target = (%<s) array[i]; if ($1 == null || !$1.contains(target)) target.%s(null); } }%n",
persistentField.getName(),
targetEntity.getName(),
mappedBySetterName
@ -268,7 +269,7 @@ public class PersistentAttributesEnhancer extends Enhancer {
);
fieldWriter.insertAfter(
String.format(
"if ($1 != null) for (java.util.Iterator itr = $1.iterator(); itr.hasNext(); ) { %s target = (%<s) itr.next(); if (target.%s() != $0) target.%s((%s)$0); }%n",
"if ($1 != null) { Object[] array = $1.toArray(); for (int i = 0; i < array.length; i++) { %s target = (%<s) array[i]; if (target.%s() != $0) target.%s((%s)$0); } }%n",
targetEntity.getName(),
mappedByGetterName,
mappedBySetterName,
@ -287,7 +288,7 @@ public class PersistentAttributesEnhancer extends Enhancer {
// check .contains($0) to avoid double inserts (but preventing duplicates)
fieldWriter.insertAfter(
String.format(
"if ($1 != null && $1.%s() != null && !$1.%<s().contains($0) ) $1.%<s().add($0);%n",
"if ($1 != null) { java.util.Collection c = $1.%s(); if (c != null && !c.contains($0)) c.add($0); }%n",
mappedByGetterName
)
);
@ -295,7 +296,7 @@ public class PersistentAttributesEnhancer extends Enhancer {
if ( persistentField.hasAnnotation( ManyToMany.class ) ) {
fieldWriter.insertBefore(
String.format(
"if ($0.%s != null) for (java.util.Iterator itr = $0.%<s.iterator(); itr.hasNext(); ) { %s target = (%<s) itr.next(); if ($1 == null || !$1.contains(target)) target.%s().remove($0); }%n",
"if ($0.%s != null) { Object[] array = $0.%<s.toArray(); for (int i = 0; i < array.length; i++) { %s target = (%<s) array[i]; if ($1 == null || !$1.contains(target)) target.%s().remove($0); } }%n",
persistentField.getName(),
targetEntity.getName(),
mappedByGetterName
@ -303,7 +304,7 @@ public class PersistentAttributesEnhancer extends Enhancer {
);
fieldWriter.insertAfter(
String.format(
"if ($1 != null) for (java.util.Iterator itr = $1.iterator(); itr.hasNext(); ) { %s target = (%<s) itr.next(); if (target.%s() != $0 && target.%<s() != null) target.%<s().add($0); }%n",
"if ($1 != null) { Object[] array = $1.toArray(); for (int i = 0; i < array.length; i++) { %s target = (%<s) array[i]; java.util.Collection c = target.%s(); if ( c != $0 && c != null) c.add($0); } }%n",
targetEntity.getName(),
mappedByGetterName
)

View File

@ -0,0 +1,58 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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();
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<String> interfaceNames = new HashSet<String>();
Set<String> fieldNames = new HashSet<String>();
Set<String> methodNames = new HashSet<String>();
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;
}
}

View File

@ -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<String> strings = new ArrayList<String>();
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<Integer> intSet = new HashSet<Integer>();
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 );
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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();
}

View File

@ -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<String> interfaceNames = new HashSet<String>();
Set<String> fieldNames = new HashSet<String>();
Set<String> methodNames = new HashSet<String>();
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<? extends EnhancerTestTask> 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<? extends EnhancerTestTask>) 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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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<CustomerInventory> 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<CustomerInventory> getInventories() {
if ( customerInventories == null ) {
customerInventories = new ArrayList<CustomerInventory>();
}
return customerInventories;
}
public void setInventories (List<CustomerInventory> inventories) {
this.customerInventories = inventories;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void addInventory(CustomerInventory inventory) {
List<CustomerInventory> 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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.association;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
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<CustomerInventory> {
@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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@Entity
public class Group {
@Id
private int id;
@Column
private String name;
@ManyToMany(mappedBy = "groups")
private Set<User> users = new HashSet<User>();
public Group() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void removeUser(User user) {
Set<User> set = this.users;
set.remove( user );
this.users = set;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<User>() );
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<Group> groups = new HashSet<Group>( 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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<CustomerInventory> 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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@Entity
public class User {
@Id
private int id;
private String login;
private String password;
@OneToOne(mappedBy = "user")
private Customer customer;
@ManyToMany
private Set<Group> 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<Group> groups = ( this.groups == null ? new HashSet<Group>() : this.groups );
groups.add( group );
this.groups = groups;
}
public Set<Group> getGroups() {
return groups;
}
public void setGroups(Set<Group> groups) {
this.groups = groups;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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() );
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<String> someStrings;
@OneToMany
private Set<Integer> 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<String> getSomeStrings() {
return someStrings;
}
public void setSomeStrings(List<String> someStrings) {
this.someStrings = someStrings;
}
public Set<Integer> getSomeInts() {
return someInts;
}
public void setSomeInts(Set<Integer> someInts) {
this.someInts = someInts;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.dirty;
import java.io.Serializable;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<String> strings = new ArrayList<String>();
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<Integer> intSet = new HashSet<Integer>();
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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<String> someStrings;
@OneToMany
private Set<Integer> someInts;
@Embedded
private Address address;
@Id
private Long id;
private String name;
private boolean active;
private long someNumber;
private List<String> someStrings;
@OneToMany
private Set<Integer> someInts;
@Embedded
private Address address;
public Long getId() {
return id;
}
@ -63,27 +68,28 @@ public class SimpleEntity {
this.someNumber = someNumber;
}
public List<String> getSomeStrings() {
return someStrings;
}
public List<String> getSomeStrings() {
return someStrings;
}
public void setSomeStrings(List<String> someStrings) {
this.someStrings = someStrings;
}
public void setSomeStrings(List<String> 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<Integer> getSomeInts() {
return someInts;
}
public Set<Integer> getSomeInts() {
return someInts;
}
public void setSomeInts(Set<Integer> someInts) {
this.someInts = someInts;
}
public void setSomeInts(Set<Integer> someInts) {
this.someInts = someInts;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.entity;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import java.io.Serializable;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/package org.hibernate.test.bytecode.enhancement.entity.customer;
import javax.persistence.Embeddable;
import java.io.Serializable;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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<s.length(); i++) {
if (!Character.isDigit(s.charAt(i))) {
throw new IllegalArgumentException(error + s);
}
}
}
}

View File

@ -1,250 +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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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<CustomerInventory> 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<CustomerInventory> getInventories() {
if (customerInventories == null){
customerInventories = new ArrayList<CustomerInventory>();
}
return customerInventories;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void addInventory(CustomerInventory inventory) {
List<CustomerInventory> 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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.entity.customer;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
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<CustomerInventory> {
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.entity.customer;
import java.io.Serializable;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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<User> users = new HashSet<User>();
public Group() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void removeUser(User user) {
Set<User> set = this.users;
set.remove(user);
this.users = set;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.entity.customer;
import javax.persistence.Embeddable;
/**
* @author <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 <a href="mailto:stale.pedersen@jboss.org">Ståle W. Pedersen</a>
*/
@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<Group> 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<Group> set = (groups == null ? new HashSet<Group>() : groups);
set.add(group);
groups = set;
}
public Set<Group> getGroups() {
return groups;
}
public void setGroups(Set<Group> groups) {
this.groups = groups;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Child>( 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<Child> loadedChildren = new ArrayList<Child>( 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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Child>());
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<Child> 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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Child> children;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Child> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
}