Affects: \5.1.5.RELEASE (via Boot 2.1.3.RELEASE)


Dear Spring Team!

Spring Cache overall works as expected for a long time in our services, but today I've noticed that there is an issue with a @Cacheable condition passing 'null' instead of a method argument into a root.target method.

I'm having the following two methods in a Spring Bean that is marked as @Component:

@Cacheable(value = CacheConstants.CODE_BY_TITLE_CACHE_NM, key="#codeSetId + #title + #authority",
        condition="#root.target.isCodeSetSmall(#codeSetId) && T(com.myOrg.code.CodeConstants).SYSTEM_AUTHORITY.equals(#authority)")
public Code getCodeByTitle(String authority, Long codeSetId, String title)
{
    // not relevant code
}

public boolean isCodeSetSmall(Long codeSetId)
{
    // codeSetId is null here
}

The result is that method isCodeSetSmall complains about null being passed as input argument, while I'm certain that its source codeSetId is not null at the point when cacheable getCodeByTitle is called.

I've tried to debug to find where the issue may be and it appears that org.springframework.expression.spel.ast.MethodReference.getArguments is the one to blame. It is called from MethodReference.getValueRef(ExpressionState state) method. It looks like at that point ExpressionState has proper values for all three arguments of my cacheable method getCodeByTitle, although getArguments(state) returns array of one element which is null.

Here you can see I debug getArguments(state) and state.relatedContext.arguments has values that I pass to my cacheable getCodeByTitle method: 1

Here you can see that this.children[i].getValueInternal(state).getValue() returned null (see first line in Variables window on the right): 2

And here return value is finally array of single null: 3

Please let me know if I'm doing something wrong here or if I can help with any other debug information.

Thank you very much in advance!

Comment From: ykartsev

Knowing that the same code worked fine in the past in our application, I tried to see if I could reproduce this issue from a stable release branch of the same application of ours, but via a custom test GET endpoint that makes a direct call to my cacheable method getCodeByTitle. I stashed all my local changes, switched to that stable branch, added test endpoint that simply hard-codes same values and makes a call. To my surprise everything worked fine and that Long value was passed as is, not as null. I then switched back to my dev branch, restored my stashed changes, rebuild the app and made the same call again - it worked. And finally, the call that was causing the original issue surprisingly now works as well! I am not sure what may be the reason of that, but I hope the information above can help identify it. I really can't think of anything that may have caused it...

Comment From: snicoll

Sorry, but without a sample that reproduces the problem, we can't justify spending time trying to figure out what the problem was based on screenshots. If you manage to reproduce this in small sample, please reopen and we'll have a look.