Define and inject a map in EJB 3.1 or CDI

心已入冬 提交于 2019-12-14 02:47:20

问题


After several years developing in Spring, I switched to EJB and I am not happy that I have no solution for this use-case. Let's say it is the strategy pattern implemented by a map. In Spring, it could look like this.

<bean id="myBean" class="MyBeanImpl">
    <property name="handlers">
        <map>
            <entry key="foo" value-ref="fooHandler"/>
            <entry key="bar" value-ref="barHandler"/>
    </property>
</bean>

In EJB/CDI, I have this.

@Stateless
public class MyBeanImpl implements MyBean {

    private Map<String, Class<? extends Handler>> handlers = new HashMap<>();

    @PostConstruct
    public void init() {
        handlers.put("foo", FooHandlerImpl.class);
        handlers.put("bar", BarHandlerImpl.class);
    }

    //jndi lookup handlerClass.getSimpleName()

}

Mind that jndi lookup works with implementations, not interfaces. Isn't there any better solution? And no, I do not want to have separate fields (foo, bar), inject them and create the map afterwards (It can be huge list and changed often). Ideally, in case of any configuration change, I would not touch the MyBeanImpl class at all.


回答1:


The more CDI like way would look something like:

@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Handles {
    String value();
}


public class HandlerLiteral extends AnnotationLiteral<Handles> implements Handles{
    private final String value;
    public HandlerLiteral(String value) {
        this.value = value;
    }
    @Override
    public String value() {
        return value;
    }
}

You would then annotate each of your Handler implementations with @Handles("someName"), e.g. the class name as you're using it here. The use of a qualifier here is more in line with how CDI works, and we use the internal Instance object to resolve appropriate beans. Then in your service code (or wherever) you would simply do:

@Inject @Any
private Instance<HandlerService> handlerInstance;

...
handlerInstance.select(new HandlerLiteral("whateverName")).get().handle(context);

If you're really constrained to using a map, this wouldn't work for you. But this should allow for more dynamic registration and essentially looks at every handler in your context.




回答2:


Try this:

@Inject @Any
private Instance<Handler> handlers;

private Map<String, Handler> handlerMap = new HashMap<>();


@PostConstruct
private void init() {
    for (Handler handler : handlers) {
        handlerMap.put(handler.getName(), handler);
    }
}

assuming your Handler interface has some sort of getName() method.



来源:https://stackoverflow.com/questions/25113624/define-and-inject-a-map-in-ejb-3-1-or-cdi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!