scwanglijun / ehcache-spring-annotations

Automatically exported from code.google.com/p/ehcache-spring-annotations
0 stars 1 forks source link

HashCodeCachekeyGenerator generates different keys across JVM restarts #72

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hello,

I am using 1.1.2 version of ehcache-spring-annotaions lib. It seems that 
HashCodeCachekeyGenerator generates different cache keys during JVM Restarts.

I am using the default values for the HashCodeCacheKeyGenerator class i.e. it 
includes class, method, parameters and return type for hash key generation.

Also, all of my method parameters and return type implement the hashCode() 
using automatic hashCode() generation feature of IntelliJ IDE.

>> What is the expected output? What do you see instead?
I would expect the cache keys to be the same across JVM restarts. Due to 
current behavior my distributed cache/clustered cache does not work across JVM 
restarts.

>> What version of the product are you using? On what operating system?
Version 1.1.2 on Mac 10.6.4

Please provide any additional information below.

Original issue reported on code.google.com by Namrata....@gmail.com on 13 May 2011 at 1:01

GoogleCodeExporter commented 9 years ago
Can you give an example of the annotated method and its arguments? Even better 
if you can share the hashCode method on all of your method parameters. Not all 
Objects implement hashCode in a sane way which would be my guess.

Original comment by eric.dalquist on 17 May 2011 at 1:35

GoogleCodeExporter commented 9 years ago
Hi Eric,

Sure.
I have 2 cache annotations and both of these caches didn't work appropriately 
in distributed/clustered environment. i.e. each JVM generates different cache 
key and it differs even on restarts.

Here is an example:

1.  Method with the annotation:

@Cacheable(cacheName = "service.PricePointLookupSimple")
public List<PricePointLookupResponse> lookup(String clientRef, Country country, 
java.util.Currency requestCurrency)
{
//...
// method implementation 
// ..
}

2. In my spring configuration, i have following beans/property defined which 
configures HashCodeCacheKeyGenerator as the default cache key generator:

 <ehcache:annotation-driven cache-manager="facadeCacheManager"
                               default-cache-key-generator="cacheKeyGenerator" />

    <ehcache:config cache-manager="facadeCacheManager">
         <ehcache:evict-expired-elements interval="60" />
    </ehcache:config>

    <bean id="facadeCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation">
            <value>classpath:ehcache.xml</value>
        </property>
    </bean>

    <bean id="cacheKeyGenerator" class="com.googlecode.ehcache.annotations.key.HashCodeCacheKeyGenerator" />

3. hashCode() is implemented on all UDF parameters and UDF return type of the 
lookup method using auto hashCode() generation feature of Intellij IDE. Here 
are definations:

a.   UDF Country class: 

public class Country implements Serializable, Comparable<Country> {

    private static final long serialVersionUID = -6743295668298247663L; 
    private Locale country;

    @Override
    public int hashCode() {
        return country != null ? country.hashCode() : 0;
    }

   // ...

}

b.  UDF PricePointLookupResponse class:

public class PricePointLookupResponse implements Serializable {

    private static final long serialVersionUID = 1L;
    private final BigDecimal exactPrice;
    private final BigDecimal exchangeRate;
    private final BigDecimal outPayment;
    private final boolean plus;
    private final Currency priceCurrency;
    private final boolean priceMatched;
    private final BigDecimal requestedOutPayment;
    private final Set<SubPaymentProvider> subPaymentProviders;
    private final BigDecimal workingPrice;
        private final String recommended;
        private String currencyItems = null;

    @Override
    public int hashCode() {
        int result = exactPrice != null ? exactPrice.hashCode() : 0;
        result = 31 * result + (exchangeRate != null ? exchangeRate.hashCode() : 0);
        result = 31 * result + (outPayment != null ? outPayment.hashCode() : 0);
        result = 31 * result + (plus ? 1 : 0);
        result = 31 * result + (priceCurrency != null ? priceCurrency.hashCode() : 0);
        result = 31 * result + (priceMatched ? 1 : 0);
        result = 31 * result + (requestedOutPayment != null ? requestedOutPayment.hashCode() : 0);
        result = 31 * result + (subPaymentProviders != null ? subPaymentProviders.hashCode() : 0);
        result = 31 * result + (workingPrice != null ? workingPrice.hashCode() : 0);
        result = 31 * result + (recommended != null ? recommended.hashCode() : 0);
        result = 31 * result + (currencyItems != null ? currencyItems.hashCode() : 0);
        return result;
    }

   // ....

}

c.  UDF SubPaymentProvider class:

public class SubPaymentProvider implements Serializable {

        private static final long serialVersionUID = -7063127880970539567L;
    private String id;
    private String name;
    private String currencyItems;
    private boolean parityEnabled = false;

    @Override
    public int hashCode() {
        int result = id != null ? id.hashCode() : 0;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + (currencyItems != null ? currencyItems.hashCode() : 0);
        result = 31 * result + (parityEnabled ? 1 : 0);
        return result;
    }

   // ....

}

Let me know if you need anything else.

Original comment by Namrata....@gmail.com on 18 May 2011 at 9:00

GoogleCodeExporter commented 9 years ago
java.util.Currency does not override hashCode or equals and so it is doing 
object instance equality comparisons. You can file a new issue requesting that 
we add special handling for Currency but that will take a few weeks for us to 
get some spare time to update the key generators. Your other option is to 
extend one of the built in generators and add custom handling for the Currency 
class yourself.

Original comment by eric.dalquist on 18 May 2011 at 10:29

GoogleCodeExporter commented 9 years ago
Note that Currency does implement toString so you might be able to use the 
StringCacheKeyGenerator and have better luck

Original comment by eric.dalquist on 18 May 2011 at 10:34

GoogleCodeExporter commented 9 years ago
oh ok, that's good to know. StringCacheKeyGenerator is not a good fit currently 
for my cache key generation.  

I will make "useReflection = true" on HashCodeCacheKeyGenerator which will 
solve the issue i believe.

Original comment by Namrata....@gmail.com on 18 May 2011 at 10:51