package org.hibernate.tool.hbm2x; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.net.URLClassLoader; import org.hibernate.boot.MetadataSources; import org.hibernate.cfg.Configuration; import org.hibernate.tool.NonReflectiveTestCase; import org.hibernate.tool.test.TestHelper; public class Hbm2JavaEqualsTest extends NonReflectiveTestCase { private static final String TEST_ENTITY_HBM_XML = "<hibernate-mapping package='org.hibernate.tool.hbm2x'> "+ " <class name='UnProxiedTestEntity'> "+ " <id name='id' type='int'> "+ " <meta attribute='use-in-equals'>true</meta> "+ " </id> "+ " </class> "+ " <class name='ProxiedTestEntity' proxy='TestEntityProxy'>"+ " <id name='id' type='int'> "+ " <meta attribute='use-in-equals'>true</meta> "+ " </id> "+ " </class> "+ "</hibernate-mapping> "; private static final String TEST_ENTITY_PROXY_JAVA = "package org.hibernate.tool.hbm2x;"+ System.lineSeparator() + "interface TestEntityProxy { "+ System.lineSeparator() + " int getId(); "+ System.lineSeparator() + "} "; public Hbm2JavaEqualsTest(String name) { super(name, "hbm2javaoutput"); } protected void setUp() throws Exception { // create output folder if(getOutputDir()!=null) { getOutputDir().mkdirs(); } // export class ProxiedTestEntity.java and UnProxiedTestEntity MetadataSources mds = new MetadataSources(); mds.addInputStream(new ByteArrayInputStream(TEST_ENTITY_HBM_XML.getBytes())); new POJOExporter(new Configuration(mds), getOutputDir()).start(); // copy interface EntityProxy.java File file = new File(getOutputDir(), "org/hibernate/tool/hbm2x/TestEntityProxy.java"); FileWriter writer = new FileWriter(file); writer.write(TEST_ENTITY_PROXY_JAVA); writer.close(); // compile the source files TestHelper.compile(getOutputDir(), getOutputDir()); } public void testEqualsWithoutProxy() throws Exception { // load the entity class and lookup the setId method URL[] urls = new URL[] { getOutputDir().toURI().toURL() }; ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); URLClassLoader ucl = new URLClassLoader(urls, oldLoader ); Class<?> entityClass = ucl.loadClass("org.hibernate.tool.hbm2x.UnProxiedTestEntity"); Method setId = entityClass.getMethod("setId", new Class[] { int.class }); // create a first entity and check the 'normal' behavior: // - 'true' when comparing against itself // - 'false' when comparing against null // - 'false' when comparing against an object of a different class Object firstEntity = entityClass.newInstance(); setId.invoke(firstEntity, new Object[] { Integer.MAX_VALUE }); assertTrue(firstEntity.equals(firstEntity)); assertFalse(firstEntity.equals(null)); assertFalse(firstEntity.equals(new Object())); // create a second entity and check the 'normal behavior // - 'true' if the id property is the same // - 'false' if the id property is different Object secondEntity = entityClass.newInstance(); setId.invoke(secondEntity, new Object[] { Integer.MAX_VALUE }); assertTrue(firstEntity.equals(secondEntity)); assertTrue(secondEntity.equals(firstEntity)); setId.invoke(secondEntity, new Object[] { Integer.MIN_VALUE }); assertFalse(firstEntity.equals(secondEntity)); assertFalse(secondEntity.equals(firstEntity)); ucl.close(); } public void testEqualsWithProxy() throws Exception { // load the entity and proxy classes, lookup the setId method and create a proxy object URL[] urls = new URL[] { getOutputDir().toURI().toURL() }; ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); URLClassLoader ucl = new URLClassLoader(urls, oldLoader ); Class<?> entityClass = ucl.loadClass("org.hibernate.tool.hbm2x.ProxiedTestEntity"); Class<?> entityProxyInterface = ucl.loadClass("org.hibernate.tool.hbm2x.TestEntityProxy"); Method setId = entityClass.getMethod("setId", new Class[] { int.class }); TestEntityProxyInvocationHandler handler = new TestEntityProxyInvocationHandler(); Object testEntityProxy = Proxy.newProxyInstance( ucl, new Class[] { entityProxyInterface }, handler); // create a first proxied entity and check the 'normal' behavior: // - 'true' when comparing against itself // - 'false' when comparing against null // - 'false' when comparing against an object of a different class (that is not the proxy class) Object firstEntity = entityClass.newInstance(); setId.invoke(firstEntity, new Object[] { Integer.MAX_VALUE }); assertTrue(firstEntity.equals(firstEntity)); assertFalse(firstEntity.equals(null)); assertFalse(firstEntity.equals(new Object())); // create a second proxied entity and check the 'normal behavior // - 'true' if the id property is the same // - 'false' if the id property is different Object secondEntity = entityClass.newInstance(); setId.invoke(secondEntity, new Object[] { Integer.MAX_VALUE }); assertTrue(firstEntity.equals(secondEntity)); assertTrue(secondEntity.equals(firstEntity)); setId.invoke(secondEntity, new Object[] { Integer.MIN_VALUE }); assertFalse(firstEntity.equals(secondEntity)); assertFalse(secondEntity.equals(firstEntity)); // compare both proxied entities with the proxy handler.id = Integer.MAX_VALUE; assertTrue(firstEntity.equals(testEntityProxy)); assertFalse(secondEntity.equals(testEntityProxy)); handler.id = Integer.MIN_VALUE; assertFalse(firstEntity.equals(testEntityProxy)); assertTrue(secondEntity.equals(testEntityProxy)); ucl.close(); } @Override protected String[] getMappings() { return null; } private class TestEntityProxyInvocationHandler implements InvocationHandler { public int id = 0; @Override public Object invoke( Object proxy, Method method, Object[] args) throws Throwable { if ("getId".equals(method.getName())) { return id; } return null; } } }