Sarav
Sarav

Reputation: 265

Spring cache for specific values @Cacheable annotation

I want to cache a result of a method only when the attribute of the result contains specific values. For example

Class APIOutput(code: Int, message: String)
sealed class Response<out T : Any> : Serializable {
    data class Success<out T : Any>(val data: T) : Response<T>()
    data class Error(val errorText: String, val errorCode: Int) : Response<Nothing>()
}
@Cacheable(
        key = "api-key",
        unless = "do something here"
    )
fun doApicall(uniqueId: Long): Response<APIOutput> {
        //make API call
        val output = callAPI(uniqueId)
        return Response.Success(output)
}

In the above method, I want to cache the response only when Response.Success.data.code == (long list of codes). Please note, in the previous line data is nothing but APIOutput object. How could I achieve it using unless or any other approach. I was thinking of writing a function that takes a doApicall method result as input and would return true or false and call that method it as unless="call a method". But I'm not sure how to do it. Any help is highly appreciated.

Upvotes: 0

Views: 1645

Answers (2)

Sarav
Sarav

Reputation: 265

Thanks Yatharth and John! Below is the condition that worked for me. resultcodes in the below expression is a list

@Cacheable(
            key = "api-key",
            unless = "!(#result instanceof T(com.abc.Response\$Success)) 
            or (#result instanceof T(com.abc.Response\$Success) 
            and !(T(com.abc.APIStatus).resultCodes.contains(#result.data.code)))"
)
fun doApicall(uniqueId: Long): Response<APIOutput> {
    //make API call
    val output = callAPI(uniqueId)
    return Response.Success(output)
}

Upvotes: 0

Yatharth Ranjan
Yatharth Ranjan

Reputation: 471

You can specify an expression to be evaluated in unless using SpEL. The returned value is available as result so you can do something like -

@Cacheable(
        key = "api-key",
        unless = "#result!=null or #result.success.data.code!=200"
    )
fun doApicall(uniqueId: Long): Response<APIOutput> {
        //make API call
        val output = callAPI(uniqueId)
        return Response.Success(output)
}

You can even use Regex in SpEL and can create custom Expression parsers if the existing functionality is not enough for your usecase.

Upvotes: 3

Related Questions