This library provides a simplified interface for interacting with in-memory cache implementations on the JVM. Think: "SLF4J but for caching"
Need a simple in-memory cache for your application? This library allows you to easily switch between different backing implementations whenever you desire!
Need caching in your library? Don't want to marry a single1 implementation? Simply code against this straightforward API and users can choose whichever backing implementation they prefer!
1 Even if you prefer a specific implementation (we like Caffeine, for example), this choice may not be compatible for all environments (Caffeine doesn't play well with Android, for example), so it is safer to code against this API for long-term flexibility
The following backing cache implementations have bindings already provided by this library:
Backend | Provider | Artifact |
---|---|---|
Caffeine | CaffeineProvider |
cache-provider-caffeine |
Caffeine3 | Caffeine3Provider |
cache-provider-caffeine3 |
Guava | GuavaProvider |
cache-provider-guava |
Cache2k | Cache2kProvider |
cache-provider-cache2k |
AndroidX | AndroidLruProvider |
cache-provider-androidx |
ExpiringMap | ExpiringMapProvider |
cache-provider-expiringmap |
Ehcache v3 (heap) | EhcacheProvider |
cache-provider-ehcache |
Infinispan (heap) | InfinispanProvider |
cache-provider-infinispan |
Infinispan v14 (heap) | InfinispanProvider |
cache-provider-infinispan-java11 |
Infinispan v15 (heap) | InfinispanProvider |
cache-provider-infinispan-java17 |
Don't see your preferred implementation listed above? Fear not, it is not difficult to create your own binding, and we'd be happy to accept it in a PR!
We publish to Maven Central and provide a convenient BOM (Build of Materials) to keep dependency versions in sync from the api to the provider.
Library developers only need to depend on the cache-core
artifact, allowing application developers to specify which provider to use at runtime.
repositories {
mavenCentral()
}
dependencies {
api(platform("io.github.xanthic.cache:cache-bom:0.6.2")) // Specify the latest version here
api(group = "io.github.xanthic.cache", name = "cache-core") // For library devs
implementation(group = "io.github.xanthic.cache", name = "cache-provider-caffeine") // For application devs; can select any provider
}
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.xanthic.cache</groupId>
<artifactId>cache-bom</artifactId>
<!-- Specify the latest version here -->
<version>0.6.2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- For library devs -->
<dependency>
<groupId>io.github.xanthic.cache</groupId>
<artifactId>cache-core</artifactId>
</dependency>
<!-- For application devs (can select any provider) -->
<dependency>
<groupId>io.github.xanthic.cache</groupId>
<artifactId>cache-provider-caffeine</artifactId>
</dependency>
</dependencies>
Users should include at least one provider module in the runtime class-path.
Further, they can (optionally) do (but replace CaffeineProvider
with the desired provider):
CacheApiSettings.getInstance().setDefaultCacheProvider(new CaffeineProvider());
Define a generic cache:
Cache<String, Integer> cache = CacheApi.create(spec -> {
spec.maxSize(2048L); // setting a size constraint is highly recommended
spec.expiryTime(Duration.ofMinutes(5L));
spec.expiryType(ExpiryType.POST_ACCESS);
spec.removalListener((key, value, cause) -> {
if (cause.isEviction()) {
// do something
}
});
});
Here, the default provider will be used as CacheBuilder#provider(CacheProvider)
was not called (note: this builder option is meant for end users rather than library devs).
Aside: the removalListener
in the example above technically has no effect, but is included for illustration.
Note: Kotlin users can enjoy an even cleaner syntax via the extensions module!
As the JCache spec attempts to cover many other features from distributed caching to non-heap storage, it is less performant and arguably more bloated. Here, we simply focus on the heap caching scenario (as Caffeine does), which allows for a much more straightforward interface to interact with. As a result, our API can support many more implementations than are covered by JCache, including non-server-side use cases like Android.
As a maintainer of the twitch4j library, we used Caffeine as our preferred high-performance, in-memory cache across our major modules. While this worked well for the server-side use case, Android users later reported incompatibilities, rendering twitch4j unusable for this platform. Thus spawned the desire for a simple cache api where specific implementations can be dynamically chosen at runtime by the end developer's choice (allowing some to use Caffeine while others can use LruCache, for example).
The library name, Xanthic, is a reference to Xanthine. Taking inspiration from the Caffeine cache library, Xanthine broadly includes the class of methylated xanthines that numerous cognitive stimulants (such as caffeine) belong to. Further, these compounds have been shown to improve memory recall, creating an apt parallel for this library.