[[cache-jsr-107]]
= JCache (JSR-107) Annotations

Since version 4.1, Spring's caching abstraction fully supports the JCache standard
(JSR-107) annotations: `@CacheResult`, `@CachePut`, `@CacheRemove`, and `@CacheRemoveAll`
as well as the `@CacheDefaults`, `@CacheKey`, and `@CacheValue` companions.
You can use these annotations even without migrating your cache store to JSR-107.
The internal implementation uses Spring's caching abstraction and provides default
`CacheResolver` and `KeyGenerator` implementations that are compliant with the
specification. In other words, if you are already using Spring's caching abstraction,
you can switch to these standard annotations without changing your cache storage
(or configuration, for that matter).


[[cache-jsr-107-summary]]
== Feature Summary

For those who are familiar with Spring's caching annotations, the following table
describes the main differences between the Spring annotations and their JSR-107
counterparts:

.Spring vs. JSR-107 caching annotations
[cols="1,1,3"]
|===
| Spring | JSR-107 | Remark

| `@Cacheable`
| `@CacheResult`
| Fairly similar. `@CacheResult` can cache specific exceptions and force the
  execution of the method regardless of the content of the cache.

| `@CachePut`
| `@CachePut`
| While Spring updates the cache with the result of the method invocation, JCache
  requires that it be passed it as an argument that is annotated with `@CacheValue`.
  Due to this difference, JCache allows updating the cache before or after the
  actual method invocation.

| `@CacheEvict`
| `@CacheRemove`
| Fairly similar. `@CacheRemove` supports conditional eviction when the
  method invocation results in an exception.

| `@CacheEvict(allEntries=true)`
| `@CacheRemoveAll`
| See `@CacheRemove`.

| `@CacheConfig`
| `@CacheDefaults`
| Lets you configure the same concepts, in a similar fashion.
|===

JCache has the notion of `javax.cache.annotation.CacheResolver`, which is identical
to the Spring's `CacheResolver` interface, except that JCache supports only a single
cache. By default, a simple implementation retrieves the cache to use based on the
name declared on the annotation. It should be noted that, if no cache name is
specified on the annotation, a default is automatically generated. See the javadoc
of `@CacheResult#cacheName()` for more information.

`CacheResolver` instances are retrieved by a `CacheResolverFactory`. It is possible
to customize the factory for each cache operation, as the following example shows:

[source,java,indent=0,subs="verbatim,quotes"]
----
	@CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class) <1>
	public Book findBook(ISBN isbn)
----
<1> Customizing the factory for this operation.

NOTE: For all referenced classes, Spring tries to locate a bean with the given type.
If more than one match exists, a new instance is created and can use the regular
bean lifecycle callbacks, such as dependency injection.

Keys are generated by a `javax.cache.annotation.CacheKeyGenerator` that serves the
same purpose as Spring's `KeyGenerator`. By default, all method arguments are taken
into account, unless at least one parameter is annotated with `@CacheKey`. This is
similar to Spring's xref:integration/cache/annotations.adoc#cache-annotations-cacheable-key[custom key generation declaration]
. For instance, the following are identical operations, one using
Spring's abstraction and the other using JCache:

[source,java,indent=0,subs="verbatim,quotes"]
----
	@Cacheable(cacheNames="books", key="#isbn")
	public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

	@CacheResult(cacheName="books")
	public Book findBook(@CacheKey ISBN isbn, boolean checkWarehouse, boolean includeUsed)
----

You can also specify the `CacheKeyResolver` on the operation, similar to how you can
specify the `CacheResolverFactory`.

JCache can manage exceptions thrown by annotated methods. This can prevent an update of
the cache, but it can also cache the exception as an indicator of the failure instead of
calling the method again. Assume that `InvalidIsbnNotFoundException` is thrown if the
structure of the ISBN is invalid. This is a permanent failure (no book could ever be
retrieved with such a parameter). The following caches the exception so that further
calls with the same, invalid, ISBN throw the cached exception directly instead of
invoking the method again:

[source,java,indent=0,subs="verbatim,quotes"]
----
	@CacheResult(cacheName="books", exceptionCacheName="failures"
				cachedExceptions = InvalidIsbnNotFoundException.class)
	public Book findBook(ISBN isbn)
----


[[enabling-jsr-107-support]]
== Enabling JSR-107 Support

You do not need to do anything specific to enable the JSR-107 support alongside Spring's
declarative annotation support. Both `@EnableCaching` and the `cache:annotation-driven`
XML element automatically enable the JCache support if both the JSR-107 API and the
`spring-context-support` module are present in the classpath.

NOTE: Depending on your use case, the choice is basically yours. You can even mix and
match services by using the JSR-107 API on some and using Spring's own annotations on
others. However, if these services impact the same caches, you should use a consistent
and identical key generation implementation.
