ClassCastException 在使用某些缓存加载器配置的直读缓存的情况下
ClassCastException in case of configured read-through cache with some cache loader
最近我 运行 遇到了 Infinispan 8.2 的问题。1.Final。我在配置缓存加载器的失效模式下有一些通读缓存。该缓存的配置由两部分组成。第一部分是 XML 中的以下模板:
<?xml version="1.0" encoding="UTF-8"?>
<infinispan xmlns="urn:infinispan:config:8.2">
<cache-container default-cache="default">
<transport cluster="jcache-cluster"/>
<invalidation-cache-configuration name="user" mode="SYNC" statistics="true"/>
</cache-container>
</infinispan>
第二部分是使用 classes 和来自 JCache 的接口的编程配置 API:
new MutableConfiguration<String, User>()
.setReadThrough(true).setStoreByValue(true)
.setCacheLoaderFactory(FactoryBuilder.factoryOf(UserCacheLoader.class));
UserCacheLoader
非常简单。它只是在每次调用时创建一个 User
的新实例。
一切正常,直到我调用 javax.cache.Cache.removeAll()
方法。它会导致以下异常:
Caused by: java.lang.ClassCastException: org.infinispan.test.User cannot be cast to java.lang.String
at org.infinispan.test.UserCacheLoader.load(UserCacheLoader.java:40)
at org.infinispan.jcache.embedded.JCacheLoaderAdapter.loadKey(JCacheLoaderAdapter.java:65)
... 40 more
经过一些调查,我在 class org.infinispan.jcache.embedded.JCacheLoaderAdapter
中找到了以下代码:
@Override
public MarshalledEntry load(Object key) throws PersistenceException {
V value = loadKey(key);
if (value != null) {
Duration expiry = Expiration.getExpiry(expiryPolicy, Expiration.Operation.CREATION);
long now = ctx.getTimeService().wallClockTime(); // ms
if (expiry == null || expiry.isEternal()) {
return ctx.getMarshalledEntryFactory().newMarshalledEntry(value, value, null);
} else {
long exp = now + expiry.getTimeUnit().toMillis(expiry.getDurationAmount());
JCacheInternalMetadata meta = new JCacheInternalMetadata(now, exp);
return ctx.getMarshalledEntryFactory().newMarshalledEntry(value, value, meta);
}
}
return null;
}
如您所见,使用 value
作为键和值调用 newMarshalledEntry
。
这是错误还是功能?有人遇到同样的问题吗?
P.S。似乎这个问题对于最新版本的 Infinispan 也是实际的。
这确实是一个 bug,现在已被 @brianheart 修复:)。它将包含在下一个版本中。
最近我 运行 遇到了 Infinispan 8.2 的问题。1.Final。我在配置缓存加载器的失效模式下有一些通读缓存。该缓存的配置由两部分组成。第一部分是 XML 中的以下模板:
<?xml version="1.0" encoding="UTF-8"?>
<infinispan xmlns="urn:infinispan:config:8.2">
<cache-container default-cache="default">
<transport cluster="jcache-cluster"/>
<invalidation-cache-configuration name="user" mode="SYNC" statistics="true"/>
</cache-container>
</infinispan>
第二部分是使用 classes 和来自 JCache 的接口的编程配置 API:
new MutableConfiguration<String, User>()
.setReadThrough(true).setStoreByValue(true)
.setCacheLoaderFactory(FactoryBuilder.factoryOf(UserCacheLoader.class));
UserCacheLoader
非常简单。它只是在每次调用时创建一个 User
的新实例。
一切正常,直到我调用 javax.cache.Cache.removeAll()
方法。它会导致以下异常:
Caused by: java.lang.ClassCastException: org.infinispan.test.User cannot be cast to java.lang.String
at org.infinispan.test.UserCacheLoader.load(UserCacheLoader.java:40)
at org.infinispan.jcache.embedded.JCacheLoaderAdapter.loadKey(JCacheLoaderAdapter.java:65)
... 40 more
经过一些调查,我在 class org.infinispan.jcache.embedded.JCacheLoaderAdapter
中找到了以下代码:
@Override
public MarshalledEntry load(Object key) throws PersistenceException {
V value = loadKey(key);
if (value != null) {
Duration expiry = Expiration.getExpiry(expiryPolicy, Expiration.Operation.CREATION);
long now = ctx.getTimeService().wallClockTime(); // ms
if (expiry == null || expiry.isEternal()) {
return ctx.getMarshalledEntryFactory().newMarshalledEntry(value, value, null);
} else {
long exp = now + expiry.getTimeUnit().toMillis(expiry.getDurationAmount());
JCacheInternalMetadata meta = new JCacheInternalMetadata(now, exp);
return ctx.getMarshalledEntryFactory().newMarshalledEntry(value, value, meta);
}
}
return null;
}
如您所见,使用 value
作为键和值调用 newMarshalledEntry
。
这是错误还是功能?有人遇到同样的问题吗?
P.S。似乎这个问题对于最新版本的 Infinispan 也是实际的。
这确实是一个 bug,现在已被 @brianheart 修复:)。它将包含在下一个版本中。