AdrienW
AdrienW

Reputation: 3462

How to create custom @ConditionalOnProperty for simpler usage?

In a Spring-Boot project, I use @ConditionalOnProperty to choose whether some Beans get loaded or not. It looks like the following:

@ConditionalOnProperty(
    prefix = "myservice",
    name = "implversion",
    havingValue = "a"
)
@Service
public class MyServiceImplA implements MyService {
   // ...
}

This allows me to choose with specific profiles which Bean should be loaded, for example different implementations of an interface, depending on the value of myservice.implversion being a or b or whatever other value.

I'd like to achieve the same effect with a user-friendlier annotation like such:

@OnMyServiceVersion(value = "a")
@Service
public class MyServiceImplA implements MyService {
   // ...
}

How can one do this?


I've tried annotating my custom annotation with @Conditional and implementing the Condition interface but I don't understand how to check properties that way. The Spring-Boot OnPropertyCondition extends SpringBootCondition is not public so I cannot start from there, and extending annotations isn't allowed, so I'm kind of stuck.

I've also tried the following with no success:

// INVALID CODE, DO NOT USE
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@ConditionalOnProperty(
    prefix = "myservice",
    name = "implversion",
    havingValue = OnMyServiceVersion.value()
)
public @interface OnMyServiceVersion {
    String value();
}

Upvotes: 4

Views: 1623

Answers (2)

Andy Wilkinson
Andy Wilkinson

Reputation: 116311

You can annotate your @OnMyServiceVersion annotation with @ConditionalOnProperty and alias the value of your annotation to the havingValue attribute of @ConditionalOnProperty:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnProperty(prefix = "myservice", name = "implversion")
public @interface OnMyServiceVersion {

    @AliasFor(annotation = ConditionalOnProperty.class, attribute = "havingValue")
    String value() default "";

}

Here's a complete example that shows this in action:

package com.example.demo;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Service;

@SpringBootApplication
public class CustomPropertyConditionApplication {

    public static void main(String[] args) {
        SpringApplication.run(CustomPropertyConditionApplication.class, "--myservice.implversion=b");
    }
    
    @Service
    @OnMyServiceVersion("a")
    static class ServiceA {
        
        ServiceA() {
            System.out.println("Service A");
        }
        
    }
    
    @Service
    @OnMyServiceVersion("b")
    static class ServiceB {
        
        ServiceB() {
            System.out.println("Service B");
        }
        
    }
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @ConditionalOnProperty(prefix = "myservice", name = "implversion")
    static @interface OnMyServiceVersion {
        
        @AliasFor(annotation = ConditionalOnProperty.class, attribute = "havingValue")
        String value() default "";
        
    }

}

This will output Service B when run. If you change the arguments in the main method to --myservice.implversion=a it will output Service A. If you remove the argument, it won't output either.

Upvotes: 4

Gun Slinger
Gun Slinger

Reputation: 133

@Bean(name = "emailNotification")
@ConditionalOnProperty(prefix = "notification", name = "service")
public NotificationSender notificationSender() {
    return new EmailNotification();
}

for reference https://www.baeldung.com/spring-conditionalonproperty

Upvotes: 0

Related Questions