Вы можете создать собственный класс, обертывающий 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 )
Конечно, это всего лишь заглушка, и вам может понадобиться адаптировать ее к вашим потребностям. Основная проблема может заключаться в том, что вы не можете получить Class<List<ObjectABC>>
- вы можете получить только Class<List>
. Самый простой выход из этого - обернуть List<ObjectABC>
в некоторый пользовательский тип. Более сложный способ (не рекомендуется) - использовать TypeToken
.
от Guava.
Атрибуция : Этот ответ основан на посте Фрэнка Аппеля , озаглавленном Как сопоставить типы значений с использованием обобщенных данных Java , который сам основан на Joshua Bloch типобезопасных гетерогенных контейнеров от Effective Java .
Редактировать : полное решение
Поскольку ОП хочет получить 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>() {
});
}