[英]How to implement Guava cache to store and get different types of objects?
Right now my cache looks like the following: 现在,我的缓存如下所示:
public class TestCache {
private LoadingCache<String, List<ObjectABC>> cache;
TestCache() {
cache = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(25)
.build(new CacheLoader<String, List<ObjectABC>>(
) {
@Override
public List<ObjectABC> load(String key) throws Exception {
// TODO Auto-generated method stub
return addCache(key);
}
});
}
private List<ObjectABC> addCache(String key) {
final JoiObjectMapper mapper = new JoiObjectMapper();
final Collection<File> allConfigFiles = FileUtils.listFiles(new File(key), null, true);
final List<ObjectABC> configsList = new ArrayList<>();
allConfigFiles.forEach(configFile -> {
try {
configsList.add(mapper.readValue(configFile, new TypeReference<ObjectABC>() {
}));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
return configsList;
}
public List<ObjectABC> getEntry(String key) {
try {
return cache.get(key);
} catch (ExecutionException e) {
throw new NonRetriableException(String.format(
"Exception occured while trying to get data from cache for the key : {} Exception: {}",
key.toString(), e));
}
}
}
In the above code, when I pass a String key
(which is path to a local folder) it takes all the files present in that location and maps them to ObjectABC
using ObjectMapper
. 在上面的代码中,当我传递一个String key
(这是本地文件夹的路径)时,它将获取该位置中存在的所有文件,并使用ObjectMapper
将它们映射到ObjectABC
。
Now my problem is that I want to instead have a generic loading cache like 现在我的问题是我想改为拥有一个通用的加载缓存,例如
LoadingCache<String, List<Object>>
. LoadingCache<String, List<Object>>
And I want to map files in different folders to different Objects, eg map files in /root/Desktop/folder1 to List<ObjectABC>
and map files in /root/Desktop/folder2 to List<ObjectDEF>
and be able to store and retrieve that information from the cache. 而且我想将不同文件夹中的文件映射到不同的对象,例如,将/ root / Desktop / folder1中的文件映射到List<ObjectABC>
,将/ root / Desktop / folder2中的文件映射到List<ObjectDEF>
并能够存储和检索缓存中的信息。
How can I pass to the cache the information of which object to use for mapping? 如何将用于映射的对象的信息传递给缓存?
You can create a custom class wrapping a LoadingCache<Key<?>, Object>
like that: 您可以像这样创建一个自定义类,该类包装一个LoadingCache<Key<?>, Object>
:
class HeterogeneousCache {
private final LoadingCache<Key<?>, Object> cache;
public <T> T get(Key<T> key) throws ExecutionException {
return key.getType().cast(cache.get(key));
}
}
@Value // provides constructor, getters, equals, hashCode
class Key<T> {
private final String identifier;
private final Class<T> type;
}
(I used Lombok's @Value annotation for simplicity) (为简单起见,我使用了Lombok的@Value注释)
Of course, this is just a stub and you might need to adapt this to your needs. 当然,这只是一个存根,您可能需要根据自己的需要进行调整。 The main problem might be that you can't get a Class<List<ObjectABC>>
- you can only get a Class<List>
. 主要问题可能是您无法获得Class<List<ObjectABC>>
-您只能获得Class<List>
。 The easiest way out of this is to wrap the List<ObjectABC>
in some custom type. 最简单的方法是将List<ObjectABC>
包装为某些自定义类型。 The harder way (not recommended) is to use Guava's TypeToken
. 较难的方法(不推荐)是使用Guava的TypeToken
。
Attribution : This answer is based on the post by Frank Appel entitled How to Map Distinct Value Types Using Java Generics , which itself is based on Joshua Bloch 's typesafe hetereogeneous containers from Effective Java . 出处 :答案基于Frank Appel的帖子,标题为“ 如何使用Java泛型映射不同的值类型 ”,该帖子本身基于Joshua Bloch的来自有效Java的类型安全的异构容器 。
Since the OP wants List<T>
as result, and since he needs instances of TypeReference<T>
, I replaced Class<T>
with TypeReference<T>
in Key<T>
: 由于OP希望将List<T>
作为结果,并且由于他需要TypeReference<T>
实例, TypeReference<T>
我在Key<T>
中用TypeReference<T>
替换了Class<T>
Key<T>
:
@Value // provides constructor, getters, equals, hashCode
class Key<T> {
private final String identifier;
private final TypeReference<T> typeReference;
}
Here's how CustomHeterogeneousCache
looks now: 这是CustomHeterogeneousCache
现在的外观:
class CustomHeterogeneousCache {
private final LoadingCache<Key<?>, List<?>> cache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.maximumSize(25)
.build(CacheLoader.from(this::computeEntry));
@SuppressWarnings("unchecked")
public <T> List<T> getEntry(Key<T> key) {
return (List<T>) cache.getUnchecked(key);
}
private <T> List<T> computeEntry(Key<T> key) {
final JoiObjectMapper mapper = new JoiObjectMapper();
final Collection<File> allConfigFiles = FileUtils.listFiles(new File(key.getIdentifier()), null, true);
return allConfigFiles.stream()
.map(configFile -> {
try {
return mapper.readValue(configFile, key.getTypeReference());
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
}
Since implementations of TypeReference
do not have value semantics, the user must make sure that every Key
is created once, and then only referenced, eg: 由于TypeReference
实现不具有值语义,因此用户必须确保每个Key
都创建一次,然后仅被引用,例如:
class Keys {
public static final Key<ObjectABC> ABC = new Key<>("/root/Desktop/folder1", new TypeReference<ObjectABC>() {
});
public static final Key<ObjectDEF> DEF = new Key<>("/root/Desktop/folder2", new TypeReference<ObjectDEF>() {
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.