Issue
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();
}
Solution
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.
Answered By - Andy Wilkinson
Answer Checked By - Mildred Charles (JavaFixing Admin)