Skip to content

Commit

Permalink
Add ExpressionLanguage condition to cache annotations (#692)
Browse files Browse the repository at this point in the history
This adds a conditional field to `@Cacheable`, `@CachePut` and `@CacheInvalidate`.

Whenever the cache interceptor is invoked via a method annotated with one of these,
the conditional is evaluated to a boolean as to whether caching should be performed.

As this would slow down existing apps, or those not using conditional, we check to
see if the annotations contain a conditional, and if not the additional processing is
shortcircuited to go back to the old behavior.

Closes #572
  • Loading branch information
timyates committed Nov 20, 2023
1 parent 492bab2 commit cdddfe0
Show file tree
Hide file tree
Showing 61 changed files with 1,876 additions and 141 deletions.
4 changes: 3 additions & 1 deletion buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ plugins {
}

repositories {
gradlePluginPortal()
mavenCentral()
}

dependencies {
implementation "org.graalvm.buildtools.native:org.graalvm.buildtools.native.gradle.plugin:0.9.28"
implementation(libs.gradle.graal)
implementation(libs.gradle.kotlin)
}
7 changes: 7 additions & 0 deletions buildSrc/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files("../gradle/libs.versions.toml"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.micronaut.cache

import io.micronaut.context.annotation.Property
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest
@Property(name = "spec.name", value = "ConditionalCacheSpec")
class ConditionalCacheSpec extends Specification {

@Inject
ConditionalService service

void "test conditional cache"() {
when:
List<String> results = (1..10).collect { service.get(it) }
sleep(10)
List<String> secondResults = (1..10).collect { service.get(it) }

then: "condition results in the last 5 results being cached"
results.drop(5) == secondResults.drop(5)

and: "the first 5 results are not cached"
results.take(5).every {!secondResults.contains(it) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.micronaut.cache;

import io.micronaut.cache.annotation.CacheConfig;
import io.micronaut.cache.annotation.Cacheable;
import io.micronaut.context.annotation.Requires;
import jakarta.inject.Singleton;

@Singleton
@CacheConfig(cacheNames = {"conditional"})
@Requires(property = "spec.name", value = "ConditionalCacheSpec")
public class ConditionalService {

DocRepo repository = new DocRepo();

// tag::conditional[]
@Cacheable(condition = "#{id > 5}")
public String get(Integer id) {
return repository.get(id);
}
// end::conditional[]

// here to make the docs look nice when we extract the function above
private static class DocRepo {

String get(Integer id) {
return "test " + id + " " + System.currentTimeMillis();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2020 original authors
* Copyright 2017-2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -89,4 +89,14 @@
* @return True if should be done asynchronously
*/
boolean async() default false;

/**
* Evaluated expression that can be used to indicate whether the value should be cached.
* Will be evaluated each time the method is called, and if the condition evaluates to false the cache will not be used.
*
* @see <a href="https://docs.micronaut.io/latest/guide/#evaluatedExpressions">Evaluated Expressions</a>.
* @return The condition
* @since 4.2.0
*/
String condition() default "";
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2020 original authors
* Copyright 2017-2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -97,4 +97,13 @@
* @return True if cache writes should be done asynchronously
*/
boolean async() default false;

/**
* Evaluated expression that can be used to indicate whether the value should be cached.
* Will be evaluated each time the method is called, and if the condition evaluates to false the cache will not be used.
* @see <a href="https://docs.micronaut.io/latest/guide/#evaluatedExpressions">Evaluated Expressions</a>.
* @return The condition
* @since 4.2.0
*/
String condition() default "";
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2020 original authors
* Copyright 2017-2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -87,4 +87,13 @@
* @return True if an atomic operation should be attempted
*/
boolean atomic() default false;

/**
* Evaluated expression that can be used to indicate whether the value should be cached.
* Will be evaluated each time the method is called, and if the condition evaluates to false the cache will not be used.
* @see <a href="https://docs.micronaut.io/latest/guide/#evaluatedExpressions">Evaluated Expressions</a>.
* @return The condition
* @since 4.2.0
*/
String condition() default "";
}

0 comments on commit cdddfe0

Please sign in to comment.