javaspring-boot

Spring Boot @ConditionalOnProperty value in array


I have an application that needs to run for multiple tenants. There is some validation logic, but not all tenants have the same checks.

I would like to have a list of strings in my application.yml and conditional beans implementing the same interface that check if a certain string is contained:

application.yml

my-app:
  checks:
    check-one,
    check-two

Bean

@Component
@ConditionalOnProperty(value = "my-app.checks", havingValue = "check-one")
public class CheckOne implements Check {}

But this doesn't seem to work.

Do I really have to use something like this (which works):

my-app:
  checks:
    check-one: true
    check-two: true

And then @ConditionalOnProperty(value = "my-app.checks.check-one", havingValue = "true")


Solution

  • Based on @pebble units comment I made a custom annotation:

    Annotation

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Documented
    @Conditional({OnPropertyContains.class})
    public @interface ConditionalOnPropertyContains {
      String containsValue();
    
      String name();
    }
    

    Implementation

    public class OnPropertyContains extends SpringBootCondition {
      OnPropertyContains() {}
    
      @Override
      public ConditionOutcome getMatchOutcome(
          final ConditionContext context, final AnnotatedTypeMetadata metadata) {
        final String name =
            (String)
                metadata
                    .getAnnotationAttributes(ConditionalOnPropertyContains.class.getName())
                    .get("name");
        final String value =
            (String)
                metadata
                    .getAnnotationAttributes(ConditionalOnPropertyContains.class.getName())
                    .get("containsValue");
        final Environment env = context.getEnvironment();
        final String[] values = env.getProperty(name, String[].class, new String[0]);
        if (Arrays.asList(values).contains(value)) {
          return ConditionOutcome.match();
        }
        return ConditionOutcome.noMatch("Property '" + name + "' does not contain '" + value + "'");
      }
    }
    

    Usage

    @ConditionalOnPropertyContains(name= "my-app.checks", containsValue = "check-one")