12

I'm trying to use a Java 8 stream and lambda expression in a Spring @Cache annotation.

I'm trying to use the following:

@CacheEvict(value = "tags", allEntries = true, 
condition = "#entity.getTags().stream().anyMatch(tag -> tag.getId() == null)")

It is failing with:

SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
org.springframework.expression.spel.SpelParseException: 
EL1042E:(pos 40): Problem parsing right operand

However, I am able to get it to work if I move the stream into a method on the entity. The annotation then works as follows without error:

@CacheEvict(value = "tags", beforeInvocation=true, allEntries = true, 
condition = "#entity.containsNewTag()")

I would prefer not to need the 'containtsNewTag()' method and use the stream directly in the SpEL expression if possible. Can this be done?

Justin
  • 6,031
  • 11
  • 48
  • 82

2 Answers2

9

Don't let naysayers get in your way, even if they author accepted answers! :) You can accomplish your intention with a little creativity! The following syntax (using Collection Selection and 'this')

here #root is your entity, and inside the selection, #this refers to a tag.

Example anyMatch:

"#root.getTags().?[#this.getId() == null].size() > 0"

Example allMatch:

"#root.getTags().?[#this.getId() == null].size() eq #root.getTags().size()"
mancini0
  • 4,285
  • 1
  • 29
  • 31
8

Spring Expression Language is defined in the developer guide. What you're trying to do isn't supported by the language at the moment. I'd also argue that this is a very weird place to put such code: an isolated method that you can unit test is much better indeed.

Mark Chesney
  • 1,082
  • 12
  • 20
Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89