我有一个Bean,它创建一个对象的实例,我需要将其注入其他bean。一切正常,我可以在@PostConstruct方法中打印注入对象的属性,但是如果我尝试从ServerEndpoint的@OnOpen方法中的注入对象中调用一个方法,它会给我一个NullPointerException。
这是我的ServerEndpoint
@Named
@ApplicationScoped
@ServerEndpoint(value = "/websocket")
public class BeanThree {
private String message = "test";
@Inject private User user;
@PostConstruct
public void init() { System.out.println(user.getUserName()); } <-- displayed in the console correctly
public String getMessage() { return this.message; }
@OnOpen
public void onOpen(Session session) {
System.out.println("onOpen");
System.out.println(user.getUserName()); <-- causes NullPointerException
}
}
有可能解决这个问题吗?
EDIT1: 我使用cdi 1.2,jetty 9.1,jsf 2.2,java-ee7和来自java-ee7的websockets
答案 0 :(得分:4)
问题是BeanThree同时被声明为CDI bean和端点。 它必须分成两个不同的bean:
@ServerEndpoint("/endpoint")
public class BeanThree {
@Inject
ApplicationScopedBean bean;
@OnOpen
public String onOpen(Session s) { System.out.println(bean); }
@OnMessage
public String onMessage(String message) { System.out.println(bean); }
}
@ApplicationScoped
public class ApplicationScopedBean { ... }
但还有另一个问题
CDI / Websocket集成非常有限:开箱即用,您只能注入@ApplicationScoped
和@Dependent
个bean。
从您的代码段开始,您似乎打算使用@SessionScoped
User bean进行Websocket会话。这不会起作用,因为Websocket和HTTP会话不同
您必须自己管理Websocket会话和会话绑定数据。这是一个example。
答案 1 :(得分:1)
这样做的一种方法是允许CDI将其实例化为CDI bean。
然后对以下类进行子类化:ServerEndpointConfig.Configurator
@ServerEndpoint(..., configurator=MyCustomConfigurator.class)
@SessionScoped
@Named("myMessageHandler")
public class MyMessageHandler{
@Inject
private MyInjectable instance;
...
}
public class MyCustomConfigurator extends ServerEndpointConfig.Configurator{
public <T extends Object> getEndpointInstance(Class<T> endpointClass) throws InstantiationException{
//do cdi lookup for endpoint using the simple name.
}
要获得对cdi BeanManager的引用,请查看此线程: http://dominikdorn.com/2010/04/cdi-weld-manual-bean-lookup/
在你的情况下,你没有对FacesContext的引用,所以使用ServletContext