Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments.
Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit.
Issue: SPR-15540
This commit introduces 2 new @Nullable and @NonNullApi
annotations that leverage JSR 305 (dormant but available via
Findbugs jsr305 dependency and already used by libraries
like OkHttp) meta-annotations to specify explicitly
null-safety of Spring Framework parameters and return values.
In order to avoid adding too much annotations, the
default is set at package level with @NonNullApi and
@Nullable annotations are added when needed at parameter or
return value level. These annotations are intended to be used
on Spring Framework itself but also by other Spring projects.
@Nullable annotations have been introduced based on Javadoc
and search of patterns like "return null;". It is expected that
nullability of Spring Framework API will be polished with
complementary commits.
In practice, this will make the whole Spring Framework API
null-safe for Kotlin projects (when KT-10942 will be fixed)
since Kotlin will be able to leverage these annotations to
know if a parameter or a return value is nullable or not. But
this is also useful for Java developers as well since IntelliJ
IDEA, for example, also understands these annotations to
generate warnings when unsafe nullable usages are detected.
Issue: SPR-15540
This commit makes sure that the `ErrorHandler` is invoked if the cache
fails to put an element (be it in the main cache or the exception cache).
See gh-1292
Issue: SPR-15188
This commit removes `GuavaCache` and support classes. Caffeine supersedes
the caching support in the Google Guava library with an actively maintained
Java 8+ version in standalone form.
As it is the only Guava feature Spring framework integrates with, this
commit removes effectively any reference to Guava.
Issue: SPR-13797
This commit allows to create a Quartz trigger implementation via
either `CronTriggerFactoryBean` or `SimpleTriggerFactoryBean` even if no
job detail is provided.
Issue: SPR-13604
Previously, if a `@Cacheable` method was accessed with the same key by
multiple threads, the underlying method was invoked several times instead
of blocking the threads while the value is computed. This scenario
typically affects users that enable caching to avoid calling a costly
method too often. When said method can be invoked by an arbitrary number
of clients on startup, caching has close to no effect.
This commit adds a new method on `Cache` that implements the read-through
pattern:
```
<T> T get(Object key, Callable<T> valueLoader);
```
If an entry for a given key is not found, the specified `Callable` is
invoked to "load" the value and cache it before returning it to the
caller. Because the entire operation is managed by the underlying cache
provider, it is much more easier to guarantee that the loader (e.g. the
annotated method) will be called only once in case of concurrent access.
A new `sync` attribute to the `@Cacheable` annotation has been addded.
When this flag is enabled, the caching abstraction invokes the new
`Cache` method define above. This new mode bring a set of limitations:
* It can't be combined with other cache operations
* Only one `@Cacheable` operation can be specified
* Only one cache is allowed
* `condition` and `unless` attribute are not supported
The rationale behind those limitations is that the underlying Cache is
taking care of the actual caching operation so we can't really apply
any SpEL or multiple caches handling there.
Issue: SPR-9254
Even though the JSR-107 spec forbids to store null values, our cache
abstraction allows that behaviour with a special handled (and this is
the default behaviour).
While this was working fine with our own set of annotations, the
JSR-107 interceptor counterpart was interpreting the spec sensu strictu.
We now allow for that special case as well.
Issue: SPR-13641
This is a rework of 314b069 that may still lead to issue if a Cacheable
annotated bean is inspected on startup. Instead of resolving the default
exception CacheResolver if a cache operation is parsed, we resolve it as
late as possible (i.e. when an exception is thrown and the relevant
exception cache needs to be resolved)
Issue: SPR-12850
Previously, a cache infrastructure with only a CacheResolver would have
worked fine until the JSR-107 API is added to the classpath. When this is
the case, the JCache support kicks in and an exception cache resolver is
all of the sudden required.
The CacheResolver _is_ different as the default implementation does look
different attributes so if a custom CacheResolver is set, it is not
possible to "reuse" it as a fallback exception CacheResolver.
Now, an exception CacheResolver is only required if a JSR-107 annotation
with an "exceptionCacheName" attribute is processed (i.e. the exception
CacheResolver is lazily instantiated if necessary).
The use case of having a CachingConfigurerSupport with only a
CacheResolver was still broken though since the JCache support only looks
for a JCacheConfigurer bean (per the generic type set on
AbstractCachingConfiguration). This has been fixed as well.
Issue: SPR-12850
Since Guava 11, CacheLoader is only invoked with a LoadingCache but the
GuavaCache wrapper is always invoking getIfPresent(), available on the
main Guava Cache interface.
Update GuavaCache#get to check for the presence of a LoadingCache and
call the appropriate method.
Issue: SPR-12842