This project demonstrates a small proposal for conditional bean activation in CDI.
The goal is simple: allow a CDI bean to participate in typesafe resolution only when a condition matches the current deployment.
This is useful when an application has multiple implementations of the same contract, but only one of them should be enabled depending on the runtime environment, deployment configuration, available capability, or custom rule.
For example, an application may have:
@Inject
TaxCalculator taxCalculator;The application should not need a producer method, manual lookup, or conditional logic at the injection point. CDI should resolve the correct implementation based on the active deployment.
The sample introduces two annotations and one contract:
@RequiresSetting(name = "app.country", value = "BR")@RequiresCondition(BrazilCondition.class)@FunctionalInterface
public interface Condition {
boolean test();
}-
@RequiresSettingis intended for simple setting-based activation. -
@RequiresConditionis intended for custom logic.
The first sample demonstrates @RequiresCondition.
It defines a common contract:
public interface PaymentGateway {
boolean STRIPE_AVAILABLE = false;
void pay();
}There are two conditions.
The Stripe condition enables Stripe only when the flag is true:
public class StripeAvailableCondition implements Condition {
@Override
public boolean test() {
return PaymentGateway.STRIPE_AVAILABLE;
}
}The Paypal condition enables Paypal when the same flag is false:
public class PaypalAvailableCondition implements Condition {
@Override
public boolean test() {
return !PaymentGateway.STRIPE_AVAILABLE;
}
}The Stripe implementation is enabled only when the Stripe condition matches:
@RequiresCondition(StripeAvailableCondition.class)
@ApplicationScoped
public class StripePaymentGateway implements PaymentGateway {
@Override
public void pay() {
System.out.println("Processing payment with Stripe");
}
}The Paypal implementation is enabled only when the Paypal condition matches:
@RequiresCondition(PaypalAvailableCondition.class)
@ApplicationScoped
public class PaypalPaymentGateway implements PaymentGateway {
@Override
public void pay() {
System.out.println("Processing payment with Paypal");
}
}The application only selects the interface:
try (var container = SeContainerInitializer.newInstance().initialize()) {
PaymentGateway paymentGateway = container.select(PaymentGateway.class).get();
paymentGateway.pay();
}Because STRIPE_AVAILABLE is false, the Stripe bean is not enabled and the Paypal bean remains enabled.
Expected output:
Processing payment with PaypalTo switch the active implementation, change the flag to true.
The second sample demonstrates @RequiresSetting.
It defines a common contract:
public interface TaxCalculator {
BigDecimal calculate(BigDecimal amount);
}The Brazil implementation is enabled only when app.country resolves to BR:
@RequiresSetting(name = "app.country", value = "BR")
@ApplicationScoped
public class BrazilTaxCalculator implements TaxCalculator {
@Override
public BigDecimal calculate(BigDecimal amount) {
return amount.multiply(new BigDecimal("0.17"));
}
}The Portugal implementation is enabled only when app.country resolves to PT:
@RequiresSetting(name = "app.country", value = "PT")
@ApplicationScoped
public class PortugalTaxCalculator implements TaxCalculator {
@Override
public BigDecimal calculate(BigDecimal amount) {
return amount.multiply(new BigDecimal("0.23"));
}
}The application sets the country before bootstrapping CDI SE:
System.setProperty("app.country", "PT");
try (var container = SeContainerInitializer.newInstance().initialize()) {
TaxCalculator taxCalculator = container.select(TaxCalculator.class).get();
System.out.println("Tax for 100: "
+ taxCalculator.calculate(new BigDecimal("100")));
}Because app.country is PT, the Brazil bean is not enabled and the Portugal bean remains enabled.
Expected output:
Tax for 100: 23.00