1
votes

Question is : how can I handle a chain of fallback values in Spring expression, allowing me to fallback on higher level configuration until I got a defined value ?

To explain a little, let's illustrate this with my own use case : I was intending to create a Spring application using the @Scheduled annotation to run some processes. Thing is I have many scheduled tasks and I would let the running frequency to be easily configurable for all of them, or only for a subset.

So I was looking for something like

@Component
public class SpecificTaskRunner {

   @Scheduled(cron = "${ specific-task-cron ?: task-families-cron ?: default-cron }")
   public void specificTask() {
      doSomething();
   }

}

Letting application configure either the frequency of all the Scheduled task at once by overriding the default-cron value, or only a subset of them by overriding the task family property, or finally, specifying on a task basis. Advantage of this approach is that it allows to play with multiple configuration levels as every scheduled task looks for the appropriate property starting from the most specific, and looking for a more generic until it got something defined, ultimately fall-backing on a default global value.

Unfortunately... this do not work. When evaluated, if the first element is not defined, then if fallback on the whole remaining. In this example, it would mean that if configuration misses a value for specific-task-cron, then the resolved value is : task-families-cron ?: default-cron which unfortunately is not what I'm looking for!

1

1 Answers

0
votes

I found 2 way to handle it :

The first one, is purely based on Spring expression. Spring seems to re-evaluates the result of the Elvis operator if it also is a Spring expression. So my working configuration was :

@Component
public class SpecificTaskRunner {

   @Scheduled(cron = "${ specific-task-cron ?: ${ task-families-cron ?: default-cron }}")
   public void specificTask() {
      doSomething();
   }

}

Which in my real use case, with one more fallback, was not really convenient...

So I switched to a simpler solution that relies on configuration by defining a chain of values this way :

#application.yml

default-cron: '0 */5 0 0 0 0' #every 5 minutes
task-families-cron: ${default-cron}
specific-task-cron: ${task-families-cron}

Combined with

@Component
public class SpecificTaskRunner {

   @Scheduled(cron = "${specific-task-cron}")
   public void specificTask() {
      doSomething();
   }

}

This way any override of a property apply to hierarchical sub-levels, unless they got themselves overridden.

Both solutions seems to works, so at the end, yes Spring expression language handle multiple fallback. Whether it should be used, or is the configuration approach better readable... I let you decide.