I have the following interface:
public interface ResultEvaluationInterface {
public void evaluateResults(Event e);
}
and I want to inject in my class depending on my Event.type different classes with the same implementation. Something like that:
#Stateless
#LocalBean
public class ResultEvaluation implements ResultEvaluationInterface {
#Override
public void evaluateResults(Event e) {
switch (e.getType()) {
case Type.Running:
// inject and call ResultEvaluationRunningEJB.evaluateResults(e)
case Type.Swimming:
// inject and call ResultEvaluationSwimmingEJB.evaluateResults(e)
default:
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
ResultEvaluationRunningEJB and ResultEvaluationSwimmingEJB both implement the interface. Anybody has got a good idea how to do that in a good way?
If you really want to use a hard coded if statement to switch between prod and dev events you could use CDI Qualifiers simply inject the two implementations into a Facade:
#Stateless
#LocalBean
public class ResultEvaluationFacade {
#Inject
#Development
private ResultEvalutationInterface dev;
#Inject
#Production
private ResultEvalutionInterface prod;
#Override
public void evaluateResults(Event e) {
switch (e.getType()) {
case Type.Production:
prod.evaluteResult(e);
break;
case Type.Development:
dev.evaluteResult(e);
break;
default:
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
And define your two implementations:
#Development
public class ResultEvaluationDevelopment implements ResultEvaluationInterface {
...
}
#Production
public class ResultEvaluationDevelopment implements ResultEvaluationInterface {
...
}
However I would consider using a mock maven project to house the two separate implementations instead.
Alternatively you could use different CDI Event types, something like this.
public void observeDevEvent(#Observe DevEvent event) {
//do stuff.
}
public void observeProdEvent(#Observe ProdEvent event) {
//do stuff
}
Firing the event would look something like this:
#Inject
private Event<ProdEvent> prodEvent;
public void someMethod() {
ProdEvent pe = new ProdEvent()
// set some data on ProdEvent
prodEvent.fire(pe);
}
Note events can also work with Qualifiers, so you could also add a Qualifier annotation to the Event instead of implementing two different types of event.
#Inject
#Production
private Event<MyEvent> event;
And listen for #Prodcution events;
public void handleProdEvent(#Observer #Production MyEvent myEvent) {
// do Stuff.
}
For lazy instantiation of beans you can use CDI Instance injection.
#Inject
private Instance<BeanA> beanA;
....
public void doStuff(Event e) {
...
case Type.Production:
//lazily evaluates and instantiatiates bean.
beanA.get().evaluateResult(e);
}
Note: I have not confirmed that this works, but you should be able to work something out with this.
You could use dynamic CDI event dispatching:
public class EventDispatcher {
#Inject
BeanManager beanManager;
public void handle(MyEvents mytype) {
beanManager.fireEvent(mytype, mytype.getQualifiyer());
}
}
You can reference your qualifiers in your event enum something like this:
public enum MyEvents {
EVENTA(new EventA() {
#Override
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
}),
EVENTB (new EventB() {
#Override
public Class<? extends Annotation> annotationType() {
return this.getClass();
}
});
private final Annotation annotation;
MyEvents(Annotation annotation) {
this.annotation = annotation;
}
public Annotation getQualifiyer() {
return annotation;
}
};
The qualifiers look something like this:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PARAMETER,ElementType.FIELD})
public #interface EventA {
}
That way you could simply add observer methods to the event processing beans:
public class EventProcessorA {
...
public void handleEvent(#Observer #BeanA MyEvents myevent) {
...
}
}
Instead of injecting 20-30 in one dispatcher with a giant switch statement.
Related
So far, I had a very simple bean definition that looked like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return new ImplementationOne();
}
However, I now have situation where additional implementation class has been added, let's call it ImplementationTwo, which needs to be used instead of ImplementationOne when the option is enabled in configuration file.
So what I need is something like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return context.getEnvironment().getProperty("optionEnabled") ? new
ImplementationOne() : new ImplementationTwo();
}
Basically a way to instantiate correct implementation at bean definition time based on the configuration value. Is this possible and can anyone please provide an example? Thanks
It is possible to implement this without using #Conditional.
Assuming you have a Interface SomeInterface and two implementations ImplOne ImplTwo:
SomeInterface.java
public interface SomeInterface {
void someMethod();
}
ImplOne.java
public class ImplOne implements SomeInterface{
#Override
public void someMethod() {
// do something
}
}
ImplTwo.java
public class ImplTwo implements SomeInterface{
#Override
public void someMethod() {
// do something else
}
}
Then you can control which implementation is used in a configuration class like this:
MyConfig.java
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext context;
#Bean
public SomeInterface someInterface() {
if (this.context.getEnvironment().getProperty("implementation") != null) {
return new ImplementationOne();
} else {
return new ImplementationTwo();
}
}
}
Make sure that the component scan of spring finds MyConfig. Then you can use #Autowired to inject the right implementation anywhere else in your code.
I think you are doing it wrong.
You should use #Conditional() on your implementation and not on your Interface.
Here is how I would do it :
The interface you will use on your code.
MyInterface.java
public interface MyInterface {
void myMethod();
}
The first implementation :
MyInterfaceImplOne.java
#Bean
#Conditional(MyInterfaceImplOneCondition.class)
public class MyInterfaceImplOne implements MyInterface {
void myMethod(){
// dosmthg
}
}
MyInterfaceImplOneCondition.java
public class MyInterfaceImplOneCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("optionEnabled")
}
}
And for the 2nd implementation :
MyInterfaceImplTwo.java
#Bean
#Conditional(MyInterfaceImplTwoCondition.class)
public class MyInterfaceImplTwo implements MyInterface {
void myMethod(){
// dosmthg 2
}
}
MyInterfaceImplTwoCondition.java
public class MyInterfaceImplTwoCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getEnvironment().getProperty("optionEnabled")
}
}
In that case, you now just have to call the interface, and Spring will inject the bean corresponding to the right condition.
Hope it is what you are looking for, and I was clear enough!
Lets say I have an Object with one boolean field.
public class AnyPojo {
private boolean b;
}
An interface DoAnything
public interface DoAnything {
void doAnything();
}
And two #Service annotated implementations of DoAnything
public class DoAnythingOneImpl implements DoAnything {
#Override
public void doAnything(){
//..
}
}
public class DoAnythingTwoImpl implements DoAnything {
#Override
public void doAnything(){
//..
}
}
In another #Service class the boolean field of AnyPojo determines which implementation of DoAnything should be called. How can I achive that? I can use ApplicationContext here and make the decision like below. But not sure if there are better ways.
#Service
public class AnotherServiceImpl implements AnotherService {
#Autowire
private ApplicationContext context;
#Override
public void anotherDoing(AnyPojo anyPojo) {
if(anyPojo.getB()){
context.getBean(DoAnythingOneImpl.class).doAnything();
} else{
context.getBean(DoAnythingTwoImpl.class).doAnything();
}
}
First things first, if your class requires particular implementations, why don't you simply inject these classes?
If you have several implementations of an interface, you have to inform Spring framework which one you would like to inject into a class. You can distinguish implementations by their unique bean names:
#Service("oneImpl")
public class DoAnythingOneImpl implements DoAnything {
#Override
public void doAnything(){
//..
}
}
#Service("twoImpl")
public class DoAnythingTwoImpl implements DoAnything {
#Override
public void doAnything(){
//..
}
}
And then inject both instances to the client service by marking which implementation should by assign to particular fields:
#Service
public class AnotherServiceImpl implements AnotherService {
#Autowire
#Qualifier("oneImpl")
private DoAnything doAnythingOneImpl;
#Autowire
#Qualifier("twoImpl")
private DoAnything doAnythingTwoImpl;
#Override
public void anotherDoing(AnyPojo anyPojo) {
if(anyPojo){
doAnythingOneImpl.doAnything();
} else{
doAnythingTwoImpl.doAnything();
}
}
Note that I would not call a service component from another service component to make sure I avoid potential redundant cycle in the future.
I would keep the following flow :
Controller ---canCall---> Services ---canCall---> Repositories
And if you need services with a more complex logic, then introduces the concept of Facade
Controller ---canCall---> Facades ---canCall---> Services ---canCall---> Repositories
However, here is a solution :
#Service("myServiceOne")
public class DoAnythingOneImpl implements DoAnything {
#Override
public void doAnything(){
//..
}
}
#Service("myServiceTwo")
public class DoAnythingTwoImpl implements DoAnything {
#Override
public void doAnything(){
//..
}
}
You can autowire both services and choose the best one based on your boolean :
#Service
public class AnotherServiceImpl implements AnotherService {
#Autowired
#Qualifier("myServiceOne")
private DoAnything serviceOne;
#Autowired
#Qualifier("myServiceTwo")
private DoAnything serviceTwo;
#Override
public void anotherDoing(AnyPojo anyPojo) {
if(anyPojo){
serviceOne.doAnything();
} else{
serviceTwo.doAnything();
}
}
}
I have an interface
public interface Abstraction {
void execute();
}
I have built a composite implementation and want to registered this object as the bean, #Named
#Named
public class Composite implements Abstraction {
private List<Abstraction> list;
#Inject
public Composite(List<Abstraction> list) {
this.list = list;
}
public void execute() {
list.forEach(Abstraction::execute);
}
}
How do I set it up so that the set of implementations to the abstraction gets injected properly into the Composite above? I will be having another object that takes the abstraction as a dependency and I want it to receive the #Named Composite above with the 2 Implementations below injected into the ctor.
public class Implementation1 implements Abstraction {
public void execute() { }
}
public class Implementation2 implements Abstraction {
public void execute() { }
}
If you create a bean for each of your implementations, your example will work out of the box. For example, annotate your implementations with #Named or #Component and mark them for scanning (component scan their package)
#Configuration
#ComponentScan
public class StackOverflow {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(StackOverflow.class);
System.out.println(ctx.getBean(Composite.class).list);
}
}
interface Abstraction {
void execute();
}
#Named
class Composite implements Abstraction {
List<Abstraction> list;
#Inject
public Composite(List<Abstraction> list) {
this.list = list;
}
public void execute() {
list.forEach(Abstraction::execute);
}
}
#Named
class Implementation1 implements Abstraction {
public void execute() {
}
}
#Named
class Implementation2 implements Abstraction {
public void execute() {
}
}
The Composite's list will contain both implementations.
Alternatively, since you only have two implementations, you could name their beans and inject them separately. For example
#Component("one")
class Implementation1 implements Abstraction {
public void execute() {
}
}
#Component("two")
class Implementation2 implements Abstraction {
public void execute() {
}
}
and inject them in the Composite
List<Abstraction> list = new ArrayList<>(2);
#Inject
public Composite(#Qualifier("one") Abstraction one, #Qualifier("two") Abstraction two) {
list.add(one);
list.add(two);
}
I suggest this solution just because the order of initialization of Abstraction beans might mess up your context initialization. For example if Implementation1 somehow depended on the initialization of Composite, the context would complain. This is rare and you can control it in other ways. Still, being explicit about the beans might be clearer in this case.
I have my AbstractBinder and I bind several classes with the same interface. Let's say I bind Fish and Cat which both implement Animal interface.
What is the easiest/proper way of injecting them into a bean which takes Collection<Animal> ?
PS: Spring has equivalent in simply #Autowire List<Animal> and the collection is created and populated by Spring.
HK2 has IterableProvider<T>, as mentioned here in the documentation. You can get the service by name, by qualifier annotation, or just iterate over them, as it's an Iterable. Just for fun, here is a test.
public class IterableProviderTest {
public static interface Service {}
public static class ServiceOne implements Service {}
#QualAnno
public static class ServiceTwo implements Service {}
#Qualifier
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public static #interface QualAnno {
public static class Instance
extends AnnotationLiteral<QualAnno> implements QualAnno {
public static QualAnno get() {
return new Instance();
}
}
}
public class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(ServiceOne.class).to(Service.class).named("one");
bind(ServiceTwo.class).to(Service.class).qualifiedBy(QualAnno.Instance.get());
}
}
#Inject
private IterableProvider<Service> services;
#Test
public void test_IterableProvider() {
ServiceLocator locator = ServiceLocatorUtilities.bind(new Binder());
locator.inject(IterableProviderTest.this);
assertEquals(2, services.getSize());
Service serviceOne = services.named("one").get();
assertTrue(serviceOne instanceof ServiceOne);
Service serviceTwo = services.qualifiedWith(QualAnno.Instance.get()).get();
assertTrue(serviceTwo instanceof ServiceTwo);
}
}
UPDATE
For a List<Service> (to avoid HK2 InterablProvider), the only think I can think of is to use a Factory and inject the IterableProvider into it, and from there return the list. For example
public class Binder extends AbstractBinder {
#Override
protected void configure() {
...
bindFactory(ListServiceFactory.class).to(new TypeLiteral<List<Service>>(){});
}
}
public static class ListServiceFactory implements Factory<List<Service>> {
#Inject
private IterableProvider<Service> services;
#Override
public List<Service> provide() {
return Lists.newArrayList(services);
}
#Override
public void dispose(List<Service> t) {}
}
Yeah it's a little bit of extra work.
In the latest release of hk2 (2.4.0) you can
#Inject Iterable<Foo> foos;
That allows you to keep your pojo's without any hk2 API in them.
For more information see: Iterable Injection
I'm looking for a way to force certain Guice bindings to be injected as providers only. For example, when there is a configuration like
interface ResultLogger {
void log(String resultAsString);
}
class ResultLoggerProvider implements Provider<ResultLogger> {
// ...
}
class ResultDisplayModule extends AbstractModule {
#Override
protected void configure() {
bind(ResultLogger.class).toProvider(ResultLoggerProvider.class);
}
}
I would like to have way to configure my module so that a class like
#Singleton
class ResultParser {
private final Provider<ResultLogger> loggerProvider;
#Inject
public ResultParser(Provider<ResultLogger> loggerProvider) {
this.loggerProvider = loggerProvider;
}
}
can be injected just fine, but an implementation like
#Singleton
class ResultParser {
private final ResultLogger resultLogger;
#Inject
public ResultParser(ResultLogger resultLogger) {
this.resultLogger = resultLogger;
}
}
should throw a RuntimeException which notifies the developer that ResultLogger is only available via a provider. The exception would ideally be thrown as soon as possible, e.g. during construction of the injector. I'm looking for an easy way to achieve this using the existing API in Guice 3.0.
Maybe you should not implement Provider at all and just have a
#Singleton
public class ResultLoggerProvider {
public ResultLogger get() {...}
// ...
}
#Singleton
class ResultParser {
private final ResultLoggerProvider loggerProvider;
#Inject
public ResultParser(ResultLoggerProvider loggerProvider) {
this.loggerProvider = loggerProvider;
}
}
and remove the other bindings.
I think that it isn't right way. I guess you need smt like
interface ResultLogger {
void log(String resultAsString);
}
class ResultLoggerWrapper implements ResultLogger {
#Inject #Named("day") ResultLogger dayLogger;
#Inject #Named("night") ResultLogger nightLogger;
public void log(String resultAsString){
if(isDay()) {
dayLogger.log(resultAsString)
} else {
nightLogger.log(resultAsString)
}
}
}
bind(ResultLogger.class).to(ResultLoggerWrapper.class);
It should work to bind Provider instead of ResultLogger. That is in your module
bind(new TypeLiteral<Provider<ResultLogger>>(){}).to(ResultLoggerProvider.class);