Skip to content

@Cacheable throws NullPointerException when RuntimeException is thrown inside annotated code #33492

@drg2000

Description

@drg2000

Hi, I have a piece of code in a reactive project that looks something like that (similar code for demo purposes):

@Cacheable(value = RedisCacheNames.CONSTANT, cacheManager = "redisCacheManager")
public Mono<String> get(Integer id) {
      return Mono.just("result")
          .doOnSuccess(s -> throwException())
  }

  private void throwException() {
    throw new RuntimeException();
  }

I have a specific exception, but it basically extends from RuntimeException.

I've been debugging a little, and it seems that CacheAspectSupport had a piece of code added in commit 8974da2 that changed ReactiveCachingHandler from this:

return adapter.fromPublisher(Mono.fromFuture(cachedFuture)
							.switchIfEmpty(Mono.defer(() -> (Mono) evaluate(null, invoker, method, contexts)))
							.flatMap(v -> evaluate(Mono.justOrEmpty(unwrapCacheValue(v)), invoker, method, contexts)));

to this:

return adapter.fromPublisher(Mono.fromFuture(cachedFuture)
							.switchIfEmpty(Mono.defer(() -> (Mono) evaluate(null, invoker, method, contexts)))
							.flatMap(v -> evaluate(Mono.justOrEmpty(unwrapCacheValue(v)), invoker, method, contexts))
							.onErrorResume(RuntimeException.class, ex -> {
								try {
									getErrorHandler().handleCacheGetError((RuntimeException) ex, cache, key);
									return evaluate(null, invoker, method, contexts);
								}
								catch (RuntimeException exception) {
									return Mono.error(exception);
								}
							}));

The thing is, first evaluate call before the method execution sets the contexts.processed to true, and after my method throws the runtime exception, is caught by this onErrorResume, which calls evaluate with cacheHit set to null, and

if (contexts.processed) {
	return cacheHit;
}

returns null.

Is this an actual issue or I am missing something?

As of now I've done a couple of extra tests, and it seems that I cannot throw a RuntimeException. I have two CacheManagers configured in my Spring Boot project, one for Caffeine and the other one for Redis. This only happens when using the RedisCacheManager as seen above.

I think this might be because CaffeineCache implementation of Cache returns null when the element is not present whereas RedisCache implementation returns a cachedFuture.

Thanks in advance for any help provided!

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions