java - 如何实现Guava缓存来存储和获取不同类型的对象?

标签 java generics caching design-patterns guava

现在我的缓存如下所示:

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));
        }
    }
}

在上面的代码中,当我传递 String key 时(这是本地文件夹的路径)它获取该位置中存在的所有文件并将它们映射到 ObjectABC使用ObjectMapper .

现在我的问题是我想要一个通用的加载缓存,例如
LoadingCache<String, List<Object>> .

我想将不同文件夹中的文件映射到不同的对象,例如将 /root/Desktop/folder1 中的文件映射到 List<ObjectABC>并将 /root/Desktop/folder2 中的文件映射到 List<ObjectDEF>并能够从缓存中存储和检索该信息。

如何将要用于映射的对象的信息传递到缓存?

最佳答案

您可以创建一个自定义类来包装 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;
}

(为了简单起见,我使用了 Lombok 的 @Value 注释)

当然,这只是一个 stub ,您可能需要根据您的需要进行调整。主要问题可能是您无法获得 Class<List<ObjectABC>> - 你只能得到Class<List> 。最简单的方法是将 List<ObjectABC> 包裹起来。在某些自定义类型中。更难的方法(不推荐)是使用 Guava 的 TypeToken .

<小时/>

归属:此答案基于 Frank Appel 的帖子标题为How to Map Distinct Value Types Using Java Generics ,其本身基于 Joshua Blochtypesafe hetereogeneous containers来自Effective Java

<小时/>

编辑:完整的解决方案

因为OP想要List<T>结果,因为他需要 TypeReference<T> 的实例,我替换了Class<T>TypeReference<T>Key<T> :

@Value // provides constructor, getters, equals, hashCode
class Key<T> {
    private final String identifier;
    private final TypeReference<T> typeReference;
}

方法如下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());
    }
}

自从实现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>() {
    });
}

关于java - 如何实现Guava缓存来存储和获取不同类型的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53189520/

相关文章:

java - 谁能告诉我学习 spring 的最好方法是什么

java - 我写了一个程序来计算 pi 但出了点问题

c# - 将 IEnumerable 转换为 List 时出现问题

java - 如何限制泛型类型不扩展类?

IOS离线缓存WebView内容

caching - 使用 zrange 按时间段查询 Redis 时间序列

ios - NSURLCache 线程安全吗?

java - MVP 模式中的 Mockito 测试

用于生成 ConcurrentModificationException 的 Java 示例代码

java - 集合成为原始类型