I'm running GWT app on Jetty 6.1 with Weld 2.0.
Got the next code:
#SessionScoped
public class SessionContext implements Serializable {
#Inject
private HttpSession httpSession;
public SessionContext() {
super();
//at this point httpSession is null
}
}
What am I missing, why HttpSession is not injected? Reference says that Injecting the HttpSession will force the session to be created.
Change the definition of
public SessionContext() {
super();
//at this point httpSession is null
}
to
public SessionContext(HttpSession httpSession) {
super();
this.httpSession = httpSession;
//check session here
}
Also use constructor injection
Otherwise provide a setter method for httpSession
It's better to use #PostConstruct to annotate some other method, here you have :
Initializing a managed bean specifies the lifecycle callback method
that the CDI framework should call after dependency injection but
before the class is put into service.
This is exactly the place where your injections are done but no code has been invoked.
like this :
#PostConstruct
public void doMyStuff() {
//feel free to access your injections here they are not null!
}
Related
Lately, I've come to know that RequestScoped beans are not usable outside a web transaction.
The problem is that outside the web transaction I do not want to use that bean, instead of having an error.
How could I achieve this ?
The component using the request scoped bean :
#Component
public class JavaComponent {
#Autowired
private RequestScopedBean requestScopedBean;
#Override
public void doStuff() {
// TODO if in web transaction, use RequestScopedBean , otherwhise don't
}
}
The bean:
#Component
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
public String getInfo() {
return "information about the web transaction";
}
}
EDIT: the error I get when trying to use the JavaComponent outside the web request is :
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'JavaComponent.requestScopedBean': Scope
'request' is not active for the current thread; consider defining a
scoped proxy for this bean if you intend to refer to it from a
singleton; nested exception is java.lang.IllegalStateException: No
thread-bound request found: Are you referring to request attributes
outside of an actual web request, or processing a request outside of
the originally receiving thread? If you are actually operating within
a web request and still receive this message, your code is probably
running outside of DispatcherServlet/DispatcherPortlet: In this case,
use RequestContextListener or RequestContextFilter to expose the
current request.
The way I use the bean while outside the web request thread is by having #Async methods running in separated threads.
Autowire ApplicationContext only and lookup your request scoped bean, then perform a null check.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
#Service
public class TestService {
#Autowired
private ApplicationContext applicationContext;
public void myMethod() {
RequestScopedBean bean = applicationContext.getBean(RequestScopedBean.class);
if (bean != null) {
// do stuff
}
}
}
I've come up with a better solution because applicationContext.getBean() throws an exception when called, instead, it's better to check if the current thread is executed in a web request context and then get the bean.
I've also tested the performances and the get bean is very fast ( 0ms ) probably because the request scoped bean pretty light
/**
* The Class AuditConfig.
*/
#Component
public class AuditConfig implements AuditorAware<String> {
/**
* The Constant SYSTEM_ACCOUNT.
*/
public static final String SYSTEM_ACCOUNT = "system";
#Autowired
private ApplicationContext context;
/**
* Gets the current auditor.
*
* #return the current auditor
*/
#Override
public Optional<String> getCurrentAuditor() {
return Optional.ofNullable(getAlternativeUser());
}
private String getAlternativeUser() {
try {
// thread scoped context has this != null
if (RequestContextHolder.getRequestAttributes() != null) {
Object userBean = context.getBean(AuditRequestScopedBean.BEAN_NAME);
if (StringUtils.isNotBlank(((AuditRequestScopedBean) userBean).getUser()))
{
return ((AuditRequestScopedBean) userBean).getUser();
}
}
} catch (Exception e) {
return SYSTEM_ACCOUNT;
}
return SYSTEM_ACCOUNT;
}
}
I want to inject request scoped bean into singleton scoped. I can do it using Provider. The problem occurs when no scope request is not active for a thread. In such case I would like to inject bean in e.g. prototype scope. Is that possible?
E.g. code:
public class Tenant {
private String name;
...
}
#Configuration
public class AppConfig {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_REQUEST)
public Tenant prototypeBean() {
return new Tenant();
}
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Tenant prototypeBean() {
return new Tenant();
}
#Bean
public MySingletonBean singletonBean() {
return new MySingletonBean();
}
public class MySingletonBean {
#Autowired
private Provider<Tenant> beanProvider;
//inject conditionally on request or prototype scope
public void showMessage() {
Tenant bean = beanProvider.get();
}
}
I want to avoid error with this message:
Error creating bean with name 'tenantDetails':
Scope 'request' is not active for the current thread;
consider defining a scoped proxy for this bean if you intend to
refer to it from a singleton;
nested exception is java.lang.IllegalStateException: No thread-bound
request found: Are you referring to request attributes outside of an
actual web request, or processing a request outside of the originally
receiving thread? If you are actually operating within a web request
and still receive this message, your code is probably running outside
of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current
request.
If something like this is required, then the design of an application should be reconsidered.
Is it possible? Yes.
#Component
#RequestScope
public class RequestScopeTenant implements Tenant {
private String name;
...
}
This way we have request scoped bean.
#Component
#PrototypeScope
public class DefaultTenant implements Tenant {
private String name;
...
}
here we have our default Tenant.
#Configuration
public class AppConfig {
#Primary
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Tenant prototypeBean(RequestScopeTenant requestScopeTenant, DefaultTenant defaultTenant) {
return RequestContextHolder.getRequestAttributes() != null ? requestScopeTenant : defaultTenant;
}
#Bean
public MySingletonBean singletonBean() {
return new MySingletonBean();
}
This way when no request scope is available default tenant is returned.
And again, if you would have to implement something like this - change the design or create custom scope.
I have an application in which we have a bean as
#RequestScoped
public class UserSession extends SessionMessage {
}
Then we have a WebFilter in which the above bean in injected. The filter populates all the properties on this userSession object.
public class SessionFilter implements Filter {
#Inject
private UserSession userSession;
.....
public void doFilter(....){
.....
someService.populateSession(userSession);
chain.doFilter(req, res)
}
}
and then on the
#Path("/token")
public class TokenService {
#Inject
private UserSession userSession;
.....
}
I am expecting the same object that is injected in the SessionFilter is injected in the TokenService. However, I am getting different object in TokenService than one injected in SessionFilter.
I am not able to figure out why same object is not injected when I have defined it to be RequestScope. Is there something I am missing?
What do you mean with the same object?
If you call the getter-methods, are the things set in the filter still there in TokenService?
The Beans injected in SessionFilter and TokenService are cdi-proxy-objects hiding the actual instance per request.
For further details see this question
I had the exact same Problem. I am Using Java EE 7 with wildfly 8.1.
My current solution is to use
HttpServletRequest context = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest");
this could be used inside your UserSession to populate the Session via Http-Header
#RequestScoped
public class UserSession extends SessionMessage {
public Session getSession() {
HttpServletRequest context = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest");
Session session = someService.populateSession(context);
return session;
}
}
I have a Bean, which creates an instance of an object, which i need to inject into other beans. Everything works fine, i can print a property of the injected object in the #PostConstruct method, but if i try to call a method from that injected object inside the #OnOpen method of a ServerEndpoint it gives me a NullPointerException.
Here is my 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
}
}
Is it possible to fix this?
Edit1:
Im using cdi 1.2, jetty 9.1, jsf 2.2, java-ee7 and websockets from java-ee7
The problem is that BeanThree is declared both a CDI bean and an endpoint at the same time.
It has to be split into two different beans:
#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 { ... }
But there's another issue.
CDI / Websocket integration is very limited: out of the box you can inject #ApplicationScoped and probably #Dependent beans only.
From your snippet it seems you intend to use #SessionScoped User bean withing a Websocket session. That's not going to work because Websocket and HTTP sessions differ.
You'll have to manage Websocket sessions and session-bound data by yourself. Here's an example.
One way to do this is to allow CDI to instantiate it as a CDI bean.
Then subclasses the following classes: 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.
}
To have a reference to the cdi BeanManager, have a look at this thread:
http://dominikdorn.com/2010/04/cdi-weld-manual-bean-lookup/
In your case, you dont have a reference to FacesContext, so use the ServletContext
I want to create a timer EJB3 when a stateless bean is created in the pool.
But if I use #PostConstruct I get the exception:
java.lang.IllegalStateException: [EJB:010193]Illegal call to EJBContext method. The bean is in "null" state. It cannot perform 'getting the Timer Service' action(s). Refer to the EJB specification for more details.
If container calls #PostConstruct, the bean ins't null. So, why I get this exception?
CLASS
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Override
public void test() {
}
}
INTERFACE
#Local
public interface TesteLocal {
void test();
}
SERVLET
public class TestServlet extends HttpServlet {
#EJB
private TestLocal test;
protected void doGet(....) throws .... {
test.test();
}
}
DETAILS
I'm using weblogic server 11g.
You can NOT use a #PostConstruct to create a timer in a stateless bean EJB 3. See this blog How to use EJB 3 timer in a weblogic 10 cluster environment for the explanation. Even the blog was talking about weblogic, but the explanation should apply to other app servers also.
Container will not allow for timerService in method annotated with #PostConstruct of Stateless Session Bean. If you want to use timerService in method annotated with #PostConstruct the go for Singleton session bean(#Singleton).
I'm not 100% sure but I think that the bean class must implement javax.ejb.TimedObject or have a method annotated with #Timeout to use EJB timers. Example:
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Timeout
#TransactionAttribute(value=REQUIRES_NEW)
public void timeoutCallback(Timer timer) {
...
}
}
Does WebLogic still complain with the above code?
PS: In any case, the error you currently get is very poorly reported, you should probably open a case.