问题
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?
回答1:
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);
}
回答2:
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.
来源:https://stackoverflow.com/questions/31474570/java-ee-interface-conditional-inject