Java – JCache creates a cache with a list of items for each key (generic)

JCache creates a cache with a list of items for each key (generic)… here is a solution to the problem.

JCache creates a cache with a list of items for each key (generic)

I want a cache with a list of items. Here is my bean definition:

public Cache<Integer, List<Application>> getMyCacheManager(CacheManager manager) {
    Cache<Integer, List<Application>> cache = manager.getCache("myCache");
    if (Objects.isNull(cache)) {
        var config = new MutableConfiguration<Integer, List<Application>>()
                .setTypes(Integer.class, List.class)
                .setStoreByValue(false)
                .setStatisticsEnabled(true)
                .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, myCacheExpiry)));
        cache = manager.createCache("myCache", config);
    }
    return cache;
}

The problem is the .setTypes line. Here you have to specify the key and value types for the cache. Key is simple, but the value is of the List<Application> type. You can’t just say: List<Application>.class because that’s not allowed. And you can’t use List.class because the compiler hints that the types are not compatible.

I

really want to keep specific types (e.g. List<Application> otherwise I would have to convert the value from Object to the correct type every time.

Any ideas?

Solution

The JSR107/JCache specification attempts to include types in the configuration. For collection types, this can cause confusion just like you do.

Unfortunately, you need to add a cast for the correct type to use. The compiler disables direct conversion, so you need to convert to Object or just Cache first.

<pre class=”lang-java prettyprint-override”>public Cache<Integer, List<Application>> getMyCacheManager(CacheManager manager) {
Cache<Integer, List<Application>> cache = manager.getCache("myCache");
if (Objects.isNull(cache)) {
var config = new MutableConfiguration<Integer, List<Application>>()
.setTypes(Integer.class, List.class)
.setStoreByValue(false)
.setStatisticsEnabled(true)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, myCacheExpiry)));
cache = (Cache<Integer, List<Application>>) ((Object) manager.createCache("myCache", config));
}
return cache;
}

The cache may check for types or use the type information you provide to make some optimizations. For example. cache2k will optimize integer keys and store keys as primitive types, not objects.

Explicit type checking in the cache is not part of the JSR107 specification. This means that for different JCache implementations, you may or may not store any type of object, regardless of what you specify in the configuration. Typically, a cache (setStoreByValue (false)) stores any object references without additional checks. The latter is just unnecessary overhead.

Some parts of JSR107 do talk about runtime type checking. This is to ensure that the cache manager returns a type-compatible cache, rather than forcing only objects of the specified type into the cache. The strict type checking was removed in the service release because it proved to be impractical. Related discussions can be found at: https://github.com/jsr107/jsr107spec/issues/340

Related Problems and Solutions