Hallo i would like to find a way to elect programmatically a Candidate between different implementation present on the bean factory, at Spring Container Level.
With Profiles i can achieve that simply like this
I Have the following Profiles "CH" and "IT" and i want that if a Bean Profiled with IT is there, then will fallback to default.
Given those classes:
The Default Implementation
#Component
public class DefaultMapper {
public void doSomething() {
System.out.println("Map Default");
}
}
The Swiss Implementation
#Component
#Profile("CH")
public class SwissMapper extends DefaultMapper {
#Override
public void doSomething() {
System.out.println("do something swiss");
}
}
The Italian Implementation:
#Component
#Profile("IT")
public class ItalianMapper extends DefaultMapper {
#Override
public void doSomething() {
System.out.println("do pasta");
}
}
Now if i run it with #ActiveProfiles("IT") it throws a NoUniqueBeanDefinitionException, which is fair enough, since the Default is not profiled, and it will be registered without any further attention by the container.
Some Consideration:
if i add #Profile("default") to DefaultMapper this will work until i have another default bean has a subclass profiled ONLY with CH.
Default Implementation of another Bean:
#Component
#Profile("default")
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
Then the Swiss implementation (No italian is available, or better said the default fits for italian):
#Component
#Profile("CH")
public class SwissParser extends DefaultParser {
#Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
}
Now if i run it with #ActiveProfiles("IT") it throws a No BeanDefinitionException, which is fair enough, but not that fair, since the "default" is not chained as ActiveProfiles and for IT i have no implementation. the CH profile here will work since has a profiled implementation for each default class.
Said That
I would like a better way to cover this scenario without:
- Having to define on the Default Classes such #Profile({"default","IT", "<all other profiles which have NOT a specialized implementation"} , or #Profile("!CH") where i exclude those profiles which have a specialization.
- #Primary i think is not a soultion, because on the DefaultMapper i have to Specialization which will be marked as #Primary and the container doesn't like it at all ;)
Then
I would like to solve this where i can decide for ALL the injected Classes, when the resolution of the Beans is ambigous then i would like to programmatically decide (in container) which implementation i would like to pick. I think an Annotation likewise to #Profile , i.E #Candidate("CH") will suit compared to a value set in application.properties in a i.E nationality.cantidate=CH. Something like:
public class MyExtension extends UnknowSpringType {
#Override
Object resolveAmbigousDependency(final Context ctx, final Resolution resolution) {
final List<Class> clazzes = resolution.getResolvedClasses();
for (final Class clazz : clazzes) {
if (clazz.isAnnotationPresent(Candidate.class) && clazz.getAnnotation(Candidate.class).getVaue().equals(candidateApplicationPropertyValue)) {
return clazz;
}
return getDefaultImplementation(clazzes);
}
}
I've done in the past Something similar with CDI SPI extension wich is elegant, and also i could cover this in another way with #Specializes from CDI, but i cannot find the same easy way on Spring (i don't have so much experience on it), BeanFactory? BeanFactoryPostProcessor ?
Help ?
You can mark all your specific Parsers as #Primary this will make sure Spring autowires this one instead of the default one which is not marked as #Primary. When no specific Parsers exist for the chosen profile it will fall back to the non #Primary default component.
See: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html
#Component
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
#Component
#Primary
#Profile("CH")
public class SwissParser extends DefaultParser {
#Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
You can activate multiple profiles, CH and IT and your implementation will fail.
It is a internationalization problem.
Related
Simplified example to give you an idea, hope it's be clear.
I've already added inheritance for Service class to avoid switches I'm having now
class Config {}
class ConfigA extends Config {}
class ConfigB extends Config {}
// service class - different implementation for configA and ConfigB
// normally it would look like
class ServiceA {
public String run(ConfigA configA) {}
}
thus next then I need sth like
class ServiceRunner {
public String run(Config config) {
// if or switch doesn't matter now
if (config instanceof ConfigA) {
return serviceA.run((ConfigA)config);
}
}
}
// main
Config config = configFactory.create(...) // returns ConfigA or ConfigB
String result = serviceRunner.run(config);
Is there a better way to code it I mean without casting?
The only solution I can see is:
interface Service { String run(); }
#RequestScope
class ServiceA implements Service {
private ConfigA config;
public ServiceA(ConfigA configA) {this.configA = configA}
public String run() {
...
}
}
but I'm not convinced it's a good idea to implement service beans as state beans and I'm using CDI (quarkus actually) for DI which it seems doesn't support assisted injection via constructor
Why don't you hide the detail about which Config a given Service handles inside the Service itself? By doing so you could have something like the following:
interface Service {
boolean handlesConfig(Config config)
String run(Config config);
}
class ServiceRunner {
private List<Service> services;
public String run(Config config) {
for (service : services) {
if (service.handles(config)) {
return service.run(config);
}
}
}
}
Seems like it's a case for Bridge pattern. You have parallel hierarchies of service and config. So if tomorrow there is a ServiceC, there would supposedly be a ConfigC. There might be an abstraction which is common in both service and config. Try to find it and abstract it out. Then service would be using that abstraction. And ConfigA, ConfigB would be impls of that abstraction.
Or perhaps, as the replier above mentioned, service should be programmed to the abstract config instead of impls.
Does the Configs have different types of interfaces that can't be extracted into a common interface? In that case, it is violating the Liskov's substitution principle, which requires that all subclasses should be interchangeable. e.g. the hierarchy of Shape <- Rectangle <- Square is wrong, because square is not a type of rectangle (programmatically, of course) - because Rectangle has 2 dimensions, namely length and breadth, while square has one dimension of length only. Making this hierarchy would break the abstraction. Similarly, it might be your case that the hierarchy of Config may not be a hierarchy at all.
I would like to use goolge/guice inject a value based on a class i provide with the annotation.
AutoConfig annotation
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.PARAMETER, ElementType.FIELD })
public #interface AutoConfig {
// default null not possible
Class<? extends Provider<? extends ConfigLoader<?>>> provider() default XMLAutoConfigProvider.class;
}
This is my annotation which allows configuring the type of config, that should be used for the annotated fields.
Usecase:
#AutoConfig()
ConfigLoader<?> defaultConfig;
#AutoConfig(provider = JsonConfigProvider)
ConfigLoader<?> jsonConfig;
I want to have two configs, one default/xml one and a json one. They will probably never occur in the same class at the same time. But i don't know when the one or the other is used. I used the approach with a class because they are provided by some dependencies/libs and this annotation will be used for some (plugable) submodules.
MyGuiceModule
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<ConfigLoader<?>>() {})
.annotatedWith(AutoConfig.class)
.toProvider(autoConfig.provider());
}
}
This the critical part, i just cannot imagine how to implement it.
So basically i just want to use the provider class specified in the annotation.
Its not necessary to use the provider class here too. Because autoConfig.provider().newInstance() is basically all i need. (I need to use a setter on the new instance but thats all i want to do at this place)
To sum it up all i really want to do is push the annotation (or its values to the provider) either using the get(AutoConfig autoConfig) or in the constructor.
Currently i only use the constructor to inject the configFile value i want to set on the newly generated config instance.
If you know that #AutoConfig(provider = JsonConfigProvider) ConfigLoader<?> jsonConfig is going to return you exactly the results of jsonConfigProvider.get(), and JsonConfigProvider obviously has a public parameterless constructor for newInstance to work, why wouldn't you just ask for a JsonConfigProvider in the first place?
Fundamentally Guice is just a Map<Key, Provider> with fancy wrapping. The bad news is that this makes variable bindings like "bind Foo<T> for all T" impossible to express concisely, and that includes your "bind #Annotation(T) Foo for all T". The good news is that you still have two options.
Bind each provider separately
Though you can't inspect annotations during provision (or tell Guice to do so for you), Guice will compare annotations using their equals methods if you bind an annotation instance rather than an annotation class (the way you would with Names.named("some-name")). This means that you can bind a ConfigLoader<?> with each expected annotation in a Module. Of course, this also means you'll have to have a list of possible ConfigLoader Providers available at configuration time, but they have to be compile-time constants anyway if you're using them as annotation parameters.
This solution works with constructor injection as well, but for fields you'll need both #Inject and #AutoConfig(...), and AutoConfig will need to keep its #BindingAnnotation meta-annotation.
To do this, you're going to have to write an implementation of your annotation, the way Guice does with NamedImpl. Note that the implementations of equals and hashCode must match the ones Java provides in java.lang.Annotation. Then it's just a matter of (redundantly) binding like this:
for(Class<ConfigLoader<?>> clazz : loaders) {
bind(ConfigLoader.class).annotatedWith(new AutoConfigImpl(clazz))
.toProvider(clazz);
}
The definition of equals is up to you, which means you can (and should) bind #AutoConfig(ConfigEnum.JSON) and keep the Guice bindings in your modules rather than specifying your requested implementation all over your codebase.
Use custom injections
You can also use custom injections to search your injected types for custom annotations like #AutoConfig. At this point, you'd be using Guice as a platform to interpret #AutoConfig instead of #Inject, which means that constructor injection won't work but that you can control your injection based on the injected instance, field name, field annotation, annotation parameters, or any combination thereof. If you choose this style, you can drop #BindingAnnotation from AutoConfig.
Use the example in the wiki article linked above as your template, but at minimum you'll need to:
Use bindListener on Binder or AbstractModule to match types that need this custom injection.
In the TypeListener you bind, search injected types for #AutoConfig-annotated fields, and if they have any matching methods then bind those matching methods to a MembersInjector or InjectionListener. You'll probably want to tease the class literal out of the annotation instance here, and pass in the Field and Class as constructor arguments to the MembersInjector/InjectionListener.
In the MembersInjector or InjectionListener you write, instantiate the provider and set the field to the instance the provider provides.
This is a very powerful feature, which would futher allow you to--for instance--automatically provide the configuration based on which instance you're injecting into or based on the name of the field. However, use it carefully and document it heavily, because it may be counter-intuitive to your coworkers that Guice is providing for an annotation other than #Inject. Also bear in mind that this won't work for constructor injection, so refactoring from field injection to constructor injection will cause Guice to complain that it's missing a required binding to instantiate the class.
I had a similar problem. I wanted to use a custom annotation that receives a enum param to choose the implementation. After a lot of research, debug and testing, I came to the following solution:
//enum to define authentication types
public enum AuthType {
Ldap, Saml
}
//custom annotation to be used in injection
#Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
#BindingAnnotation
public #interface Auth {
AuthType value();
}
//defintion of authenticator
public interface Authenticator {
public void doSomehting();
}
//Authenticator implementations
public class LdapAuthenticator implements Authenticator {
#Override
public void doSomehting() {
// doing ldap stuff
}
}
public class SamlAuthenticator implements Authenticator {
#Override
public void doSomehting() {
// doing saml stuff
}
}
public class MyModule extends AbstractModule {
// annotate fields to bind to implementations
private #Auth(AuthType.Ldap) Authenticator ldap;
private #Auth(AuthType.Saml) Authenticator saml;
#Override
protected void configure() {
//bind the implementation to the annotation from field
bindAnnotated("ldap", LdapAuthenticator.class);
bindAnnotated("saml", SamlAuthenticator.class);
}
private void bindAnnotated(String fieldName, Class<? extends Authenticator> implementation) {
try {
//get the annotation from fields, then bind it to implementation
Annotation ann = MyModule.class.getDeclaredField(fieldName).getAnnotation(Auth.class);
bind(Authenticator.class).annotatedWith(ann).to(implementation);
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
//usage: add #Auth(<AuthType>) to the dependency
public class ClientClass {
private Authenticator authenticator;
#Inject
public ClientClass(#Auth(AuthType.Ldap) Authenticator authenticator) {
this.authenticator = authenticator;
}
}
Check the documentation of Binder
I tested the Jeff Bowman solution, but it apparently works only binding to providers
As a BindingAnnotations#binding-annotations-with-attributes states equals() and hashCode() should be properly implemented. So given that there is MyAnnotation
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
public #interface MyAnnotation {
SomeEnum value() default SomeEnum.A;
}
which is used to specify SomeInterface implementation(SomeDefault and SomeOther), SomeModule class could look like
public class SomeModule extends AbstractModule {
#Override
protected void configure() {
bind(Key.get(SomeInterface.class, createAnnotationClass(A))).to(SomeDefault.class);
// more common binding expresion
bind(SomeInterface.class).annotatedWith(createAnnotationClass(B)).to(SomeDefault.class);
}
private Annotation createAnnotationClass(SomeEnum someEnum) {
return new MyAnnotation() {
#Override
public SomeEnum value() {
return someEnum;
}
#Override
public Class<? extends Annotation> annotationType() {
return MyAnnotation.class;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyAnnotationCl myAnnoCl = (MyAnnotationCl) o;
return A == myAnnoCl.getValue();
}
#Override
public int hashCode() {
// from java annotation documentation
return (127 * "value".hashCode()) ^ value().hashCode();
}
};
}
}
Then annotation could be used as follows:
public class DoSomethingWithSomething {
private final SomeInterface someImplementation;
#Inject
public DoSomethingWithSomething(
#MyAnnotation SomeInterface someDefault
// #MyAnnotation(A) SomeInterface someDefault
// #MyAnnotation(B) SomeInterface someOther
) {
this.someImplementation = someDefault;
}
}
I'd like to write some base classes that should be picked by default to autowire with Spring. Only if these classes are extended, thus a custom implementation is provided for them, I want the custom implementation to be picked up, instead of the default one.
How can I achieve it when I don't want to make my default classes abstract (as the application should be able to run without custom implementations, just by the default ones)?
The the following example: I want to provide a basic handler for any errors. But this setup would only work if I make the BaseHandler abstract, which I don't want (as in this case I would force anyone using my library to implement the class).
#MessageEndpoint
public class BaseHandler {
#ServiceActivator(inputChannel = "errorChannel")
public A_Stadisdatensatz handle(Message<MessageHandlingException> message) {
process(message.getPayload());
}
/**
* Override to supply specific processing
*/
void process(Payload payload) {
//do some default processing
}
}
#MessageEndpoint
public class CustomHandler extends BaseHandler {
#Override
void process(Payload payload) {
//custom processing
}
}
If I run it this way, CustomHandler will never be picked up.
So, is it impossible?
I supose that you are using #Autowired to inject the dependencies. In that case you could use #Primary annotation to override defaults ones, ie
#Primary
#MessageEndpoint
public class CustomHandler extends BaseHandler {
#Override
void process(Payload payload) {
//custom processing
}
}
I want expose instances managed by an external framework to CDI applications using #Inject. These instances must be provided this other framework since their lifecycle is based on various caching strategies.
Ex: same instance is visible within same thread scope, might live across many request scopes, session scope is not applicable. Seems I need to define a new scope targeting these kind of instances?
What is the best way to do this? An extension, is it possible with producer methods?
I almost got it to work with producer methods using the following:
#Inject
#CustomInject
FwObject obj;
#Produces
#CustomInject
FwObject createConfig(InjectionPoint p) {
return (FwObject) ctx.get((Class<?>) p.getType());
}
But this force me to be explicit about the type produced which is not possible since there is no common framework interface.
Any help appreciated.
Maybe with producer methods, all depends on what you need, but an extension is probably the best way to go. If you need to go with a new scope (if you're using JSF the Conversation scope may work) you will certainly need to create an extension.
I think I solved it by creating a custom scope. The following article was really helpful:
http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
This is a very brief description of how I solved it.
Create custom scope annotation.
import javax.enterprise.context.NormalScope;
#Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
#NormalScope
public #interface CustomScope {
}
Create custom context.
import javax.enterprise.context.spi.Context;
public class CustomContext implements Context {
private MyFw myFw = .... ;
#Override
public Class<? extends Annotation> getScope() {
return CustomScope.class;
}
#Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public <T> T get(Contextual<T> contextual) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public boolean isActive() {
return true;
}
}
Create extension and register context.
import javax.enterprise.inject.spi.Extension;
public class CustomContextExtension implements Extension {
public void afterBeanDiscovery(#Observes AfterBeanDiscovery event, BeanManager manager) {
event.addContext(new CustomContext());
}
}
Register extension.
Add CustomContextExtension to META-INF/javax.enterprise.inject.spi.Extension
Add CustomScope to framework object.
#CustomScope
public class FwObject { ... }
Inject FwObject using #Inject where needed.
public class MyService {
#Inject
FwObject obj;
}
Is there a way to declare default binding in Guice 3.0 ?
Here is an example of what I expected :
//Constructor for Class Impl1
#Inject
public Impl1 (#One IMyOwn own)
{
...
}
//Constructor for Class Impl2
#Inject
public Impl2 (#Two IMyOwn own)
{
...
}
//Declare a default binding
bind(IMyOwn.class).to(DefaultMyOwn.class);
//Then, if I want to bind a custom implementation for #Two
bind(IMyOwn.class).annotatedWith(Two.class).to(TwoMyOwn.class);
Actually, this example can't works because I must declare a binding for all annotation (#One, #Two).
Are there solutions to do that with Guice ?
Thanks.
Use the #Named binding.
From Guice Reference on Github:
Guice comes with a built-in binding annotation #Named that uses a string:
public class RealBillingService implements BillingService {
#Inject
public RealBillingService(#Named("Checkout") CreditCardProcessor processor) {
...
}
To bind a specific name, use Names.named() to create an instance to pass to annotatedWith:
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("Checkout"))
.to(CheckoutCreditCardProcessor.class);
So in your case,
//Constructor for Class Impl1
#Inject
public Impl1 (#Named("One") IMyOwn own)
{
...
}
//Constructor for Class Impl2
#Inject
public Impl2 (#Named("Two") IMyOwn own)
{
...
}
and your module will look like:
public class MyOwnModule extends AbstractModule {
#Override
protected void configure() {
bind(IMyOwn.class)
.annotatedWith(Names.named("One"))
.to(DefaultMyOwn.class);
bind(IMyOwn.class)
.annotatedWith(Names.named("Two"))
.to(TwoMyOwn.class);
}
}
With Guice 4.X there is Optional Binder.
public class FrameworkModule extends AbstractModule {
protected void configure() {
OptionalBinder.newOptionalBinder(binder(), Renamer.class);
}
}
public class FrameworkModule extends AbstractModule {
protected void configure() {
OptionalBinder.newOptionalBinder(
binder(),
Key.get(String.class, LookupUrl.class))
.setDefault().toInstance(DEFAULT_LOOKUP_URL);
}
}
In Guice 3.0 you may be able to exploit the automatic binding of the default constructor.
Use a single #Inject or public no-arguments constructor.
But this has constraints, as your default constructor needs to be of the same concrete class so derivation may become cumbersome.
Guice tries to check as much of your configuration (aka. Binding) as possible. This also means, that Guice cannot tell whether a missing binding for #One is an error or should map to some default case.
If you are interested in the details, lookup the BindingResolution sequence in Guice. Since step 4 and step 6 deal with binding annotation and step 6 explicitly forbids default, I think you are out of luck.
.6. If the dependency has a binding annotation, give up. Guice will not create default bindings for annotated dependencies.
So the best you can do is to provide Guice with a hint, that #One should map to the default like this:
bind(IMyOwn.class).annotatedWith(One.class).to(IMyOwn.class);
So you do not need to state the concrete default class DefaultMyOwn multiple times.