HHH-8558 - Bytecode enhancer: testsuite reorganization with added lazy loading tests
This commit is contained in:
parent
c6fa2b1df1
commit
44a02e5efc
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue