From fbe7d325e264e7f927f086f4abebbdd2bd2393e4 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 30 Jul 2010 21:28:15 +0000 Subject: [PATCH] HHH-2510 HHH-4011 : Override hashCode and equals() in AliasToBeanResultTransformer and make serializable git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20093 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../AliasToBeanResultTransformer.java | 80 ++++++++++++++----- .../org/hibernate/cache/QueryKeyTest.java | 26 ++++++ 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java b/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java index e6adf665ec..58d93cbaf4 100644 --- a/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java +++ b/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java @@ -24,6 +24,8 @@ */ package org.hibernate.transform; +import java.io.Serializable; +import java.util.Arrays; import java.util.List; import org.hibernate.HibernateException; @@ -52,42 +54,36 @@ import org.hibernate.property.Setter; * * @author max */ -public class AliasToBeanResultTransformer implements ResultTransformer { +public class AliasToBeanResultTransformer implements ResultTransformer, Serializable { // IMPL NOTE : due to the delayed population of setters (setters cached // for performance), we really cannot properly define equality for // this transformer private final Class resultClass; - private final PropertyAccessor propertyAccessor; + private boolean isInitialized; + private String[] aliases; private Setter[] setters; public AliasToBeanResultTransformer(Class resultClass) { if ( resultClass == null ) { throw new IllegalArgumentException( "resultClass cannot be null" ); } + isInitialized = false; this.resultClass = resultClass; - propertyAccessor = new ChainedPropertyAccessor( - new PropertyAccessor[] { - PropertyAccessorFactory.getPropertyAccessor( resultClass, null ), - PropertyAccessorFactory.getPropertyAccessor( "field" ) - } - ); } public Object transformTuple(Object[] tuple, String[] aliases) { Object result; try { - if ( setters == null ) { - setters = new Setter[aliases.length]; - for ( int i = 0; i < aliases.length; i++ ) { - String alias = aliases[i]; - if ( alias != null ) { - setters[i] = propertyAccessor.getSetter( resultClass, alias ); - } - } + if ( ! isInitialized ) { + initialize( aliases ); } + else { + check( aliases ); + } + result = resultClass.newInstance(); for ( int i = 0; i < aliases.length; i++ ) { @@ -106,14 +102,60 @@ public class AliasToBeanResultTransformer implements ResultTransformer { return result; } + private void initialize(String[] aliases) { + PropertyAccessor propertyAccessor = new ChainedPropertyAccessor( + new PropertyAccessor[] { + PropertyAccessorFactory.getPropertyAccessor( resultClass, null ), + PropertyAccessorFactory.getPropertyAccessor( "field" ) + } + ); + this.aliases = new String[ aliases.length ]; + setters = new Setter[ aliases.length ]; + for ( int i = 0; i < aliases.length; i++ ) { + String alias = aliases[ i ]; + if ( alias != null ) { + this.aliases[ i ] = alias; + setters[ i ] = propertyAccessor.getSetter( resultClass, alias ); + } + } + isInitialized = true; + } + + private void check(String[] aliases) { + if ( ! Arrays.equals( aliases, this.aliases ) ) { + throw new IllegalStateException( + "aliases are different from what is cached; aliases=" + Arrays.asList( aliases ) + + " cached=" + Arrays.asList( this.aliases ) ); + } + } + public List transformList(List collection) { return collection; } + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + AliasToBeanResultTransformer that = ( AliasToBeanResultTransformer ) o; + + if ( ! resultClass.equals( that.resultClass ) ) { + return false; + } + if ( ! Arrays.equals( aliases, that.aliases ) ) { + return false; + } + + return true; + } + public int hashCode() { - int result; - result = resultClass.hashCode(); - result = 31 * result + propertyAccessor.hashCode(); + int result = resultClass.hashCode(); + result = 31 * result + ( aliases != null ? Arrays.hashCode( aliases ) : 0 ); return result; } } diff --git a/core/src/test/java/org/hibernate/cache/QueryKeyTest.java b/core/src/test/java/org/hibernate/cache/QueryKeyTest.java index 1795d46690..bad6a570bc 100644 --- a/core/src/test/java/org/hibernate/cache/QueryKeyTest.java +++ b/core/src/test/java/org/hibernate/cache/QueryKeyTest.java @@ -24,12 +24,14 @@ */ package org.hibernate.cache; +import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import junit.framework.TestCase; import org.hibernate.EntityMode; +import org.hibernate.transform.AliasToBeanResultTransformer; import org.hibernate.transform.RootEntityResultTransformer; import org.hibernate.transform.ResultTransformer; import org.hibernate.transform.DistinctRootEntityResultTransformer; @@ -47,6 +49,18 @@ import org.hibernate.util.ArrayHelper; public class QueryKeyTest extends TestCase { private static final String QUERY_STRING = "the query string"; + public static class AClass implements Serializable { + private String propAccessedByField; + private String propAccessedByMethod; + + public String getPropAccessedByMethod() { + return propAccessedByMethod; + } + + public void setPropAccessedByMethod(String propAccessedByMethod) { + this.propAccessedByMethod = propAccessedByMethod; + } + } public void testSerializedEquality() { doTest( buildBasicKey( null ) ); } @@ -57,6 +71,18 @@ public class QueryKeyTest extends TestCase { doTest( buildBasicKey( DistinctResultTransformer.INSTANCE ) ); doTest( buildBasicKey( AliasToEntityMapResultTransformer.INSTANCE ) ); doTest( buildBasicKey( PassThroughResultTransformer.INSTANCE ) ); + + // settings are lazily initialized when calling transformTuple(), + // so they have not been initialized for the following test + // (it *should* be initialized before creating a QueryKey) + doTest( buildBasicKey( new AliasToBeanResultTransformer( AClass.class ) ) ); + + // initialize settings for the next test + AliasToBeanResultTransformer transformer = new AliasToBeanResultTransformer( AClass.class ); + transformer.transformTuple( + new Object[] { "abc", "def" }, + new String[] { "propAccessedByField", "propAccessedByMethod" } ); + doTest( buildBasicKey( transformer ) ); } private QueryKey buildBasicKey(ResultTransformer resultTransformer) {