I'm fresh new in Google Guice framework and i have a question regarding injecting in guice servlet and using RequestScope. Ok let me give some example from my code just to make the things clearly.
I have a bean class for example Bean ..
#RequestScope
public class Bean {
private String user;
private String pass;
// constructor which is #inject
// getters and setters
}
Here i've got a servlet
#Singleton
public class MainServlet extends HttpServlet {
doGet(HttpServletRequest request, HttpServletResponse response) {
.... some code
Injector injector = Guice.createInjector();
ValidUser validUser = injector.getInstance(ValidUser.class)
// Here i got the below exception
}
}
com.google.inject.ConfigurationException: Guice configuration errors:
1) No scope is bound to com.google.inject.servlet.RequestScoped.
at Bean.class while locating Bean
It's interesting here that servlet scope is singleton as we know.
And also how can i get from the http request - Bean instance?? because as far as i understand after a instance of a Bean class is injected it goes in the http request, right?
Any help or example is welcome.
Thanks
Br
You're creating and using an Injector inside the doGet method on your servlet... it has no chance to be aware of scope or of the current request or anything!
Guice Servlet requires that you set up all requests to go through the GuiceFilter and that you create a subclass of GuiceServletContextListener that creates the Injector that your whole application will use. This is all described in Guice user guide in the Servlets section.
Once you've done that, you can #Inject things in to your MainServlet (even using an #Inject annotated constructor). To get a request scoped instance of Bean inside the servlet, you'd need to inject a Provider<Bean> (since Bean has a smaller scope than the singleton servlet). Within a request, you can call beanProvider.get() to get the Bean for the current request.
Note that servlets are singletons because that's how they work in the normal Java servlet world as well... they're each only created once per application and that single instance is used for all requests to that servlet.
Related
when I tried to inject request scoped bean in application scope bean I got the following error.
Method threw 'org.jboss.weld.contexts.ContextNotActiveException' exception. Cannot evaluate com.example.flow.txn.TxnMessageProcessor$Proxy$_$$_WeldClientProxy.toString()
Code Reference:
#ApplicationScoped
public class TxnMessageObserver {
private static final Logger logger = LoggerFactory.getLogger(TxnMessageObserver.class);
#Inject
private TxnMessageProcessor processor;
//message is observed here
public void postConstruct(#Observes #Initialized(ApplicationScoped.class) Object o) {
logger.info("Subscribing to queue [{}] for msg.", queue);
consumer.subscribe(queue);
}
}
#RequestScoped
public class TxnMessageProcessor {
private static final Logger logger = LoggerFactory.getLogger(TxnMessageProcessor.class);
//all processing happens here
}
I need to process every message in request scope.
If the applicationscoped bean is constructed eagerly when the servlet context is initialized (like is the case here), there is no request context and hence no requestscoped bean.
Since it is completely unclear what you try to achieve (your code is not a minimal reproducible example, let me point you to
JEE6 #ApplicationScoped bean and concurrency
Why #Singleton over #ApplicationScoped in Producers?
(All found via this search)
Injecting a requestscoped bean is therefor dangerous and I strongly suggest to retrieve the required requestscoped bean in the specific methods or do it the other way around, inject the applicationscoped bean in the requestscoped one and call a method on it, passing in itself.
I do not know what exactly the problem cause is. But I can confirm that you can inject #ReqeustScoped beant into #ApplicationScoped. I do that in many applications with hundreds of classes and it worked out of the box.
I've got a Java EE app running in wildfly acting as a REST API. Before an endpoint logic is run, a filter grabs a JWT out of the headers and sets the user on a request scoped variable like the CDI solution proposed here: https://stackoverflow.com/a/26778123/4236181
If I then inject that bean in a class annotated with #Singleton and run multiple requests at once I can see that Wildfly is using a single instance of my singleton class as expected, but it seems it's doing proxy magic for my request scope variable. My request scoped variable is different in each request, even though they are using the same instance of the singleton. I was under the impression you could not use request scoped variables in a singleton, does Wildfly allow you to do that now? What is happening here?
A contextual reference to a bean with a normal scope(such as RequestScope), is not a direct reference to a contextual instance of the bean. Instead, the contextual reference is a client proxy object. when a method is called the proxy looks up the current instance. so you could use RequestScope in a singleton
https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies this would look sort of like this:(shows a client proxy).
public class PaymentProcessor_$$Proxy extends PaymentProcessor
{
public void processPayment(int amount)
{
PaymentProcessor instance = lookupBean();
instance.processPayment(amount);
}
private PaymentProcessor lookupBean()
{
//get the correct instance from the BeanManager and return it
}
}
As you can see, client proxy gets the correct instance from the BeanManager(lookupBean method)
I'm trying to understand CDI using Weld. Got the next structure:
#ApplicationScoped
public class MainFacade {
#Inject
private FooFacade fooFacade;
private static int ins=0;
public MainFacade() {
super();
ins++;
System.out.println("MainFacade instance = "+ins);
}
public FooFacade getFooFacade() {
return fooFacade;
}
}
Where FooFacade is also #ApplicationScope.
When app is starting I've get a MainFacade instance = 1. When I inject it in other class (GWT RPC servlet) and call mainFacade.getFooFacade() then new instance of MainFacade are created along with a new instance of fooFacade.
Thought that Weld would return me the same instance of application scope bean anywhere I inject it. What I'm doing wrong?
I don't think this test will work well to verify that an application scoped bean is really a "singleton".
If you inject this bean into other beans, Weld will create a proxy which will handle the delegation of all invocations to the correct instance. This is important especially if you inject request scoped bean into session scoped beans for example.
The proxy will basically extend MainFacade which is required because otherwise the proxy cannot be injected into the fields where the injection is happening. When creating an instance of the proxy, the default constructor of you bean will be executed. As Weld will create many proxies, you are seeing multiple logs to the console. You could verify this by adding something like this to your constructor:
System.out.println("Type: "+this.getClass().getName());
When you use #ApplicationScoped Weld creates a proxy that calls constructor too, specification here.
In my SpringMVC project I need a certain tactic to call a class which does parse a xml file which does own my RMI server ip & port & the url must be relative to servletContext url :
HttpServletRequest request;
request.getServletContext().getRealPath("/WEB-INF/LABLAB/RMI-Config.xml")
I want to load these classes when I start my application in tomcat not when I call a Controller Class because my application depend to my RMI so before anything else I have to parse my file & using the IP & PORT fields to start connecting to my RMI & then call the rmi method to do some stuffs later on ...
now
how I'm gonna do it ? please tell me how I can initialize an instance of HttpServletRequest & give an intial value when I'm not on the Controller classes as well .
Thank you
You are using Spring, then you can create a class and implement IntializingBean. If you want to get hold of ServletContext you can simple use #Autowired annotation in your initializing bean. For e.g.:
#Component
public class SomeBean implements InitializingBean {
#Autowired
private ServletContext context;
public void afterPropertiesSet() throws Exception {
String path = context.getRealPath("/WEB-INF/LABLAB/RMI-Config.xml");
//do something.
}
}
As per docs:
IntializingBean - Interface to be implemented by beans that need to
react once all their properties have been set by a BeanFactory.
Or take a look here how to do this using ServletContextListener.
You need to implement the ServletContextListener interface and refer to it from your web.xml:
<listener>
<listener-class>InitializingListener</listener-class>
</listener>
The interface has a contextInitialized(ServletContextEvent sce) method, in which you can call sce.getServletContext(), so you don't need a HttpServletRequest.
If this doesn't work out, because you also need to access some of your Spring beans from the initializing class, then forget about implementing the ServletContextListener interface, and do the following instead:
Instantiate your initialization class via Spring (make a bean of that type).
Make the class implement ServletContextAware. This will cause Spring to inject the ServletContext into your class.
Define an init method on that bean (use the init-method bean attribute, or define a #PostConstruct annotated method)
Make all your Controller beans depend on the initializing bean by using the depends-on bean attribute. As a result, the initialaizing bean will be created before any Controller bean.
Without the last step, it cannot be guaranteed that your controllers won't start processing requests before the initialization bean finishes its work. However, specifying the depends-on attribute on each and every controller bean is also problematic, especially that they are usually created by applying the #Controller annotation instead of xml configuration. A nice workaround is described in this post.
I have a Session scoped bean
import javax.faces.bean.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class SessionBean implements Serializable{
I inyect the object in one Filter...
public class FiltroSeguridad implements Filter{
#Inject
private SessionBean sessionBean;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
sessionBean.setRutaRedirect(httpRequest.getRequestURI());
}
}
But, I inyect SessionBean in the next interaction...
#Model
public class CuentaUsuarioWebBean implements Serializable{
#Inject
private SessionBean sessionBean;
public void loginUsuario() throws IOException{
sessionBean.getRutaRedirect();
}
}
But the property getRutaRedirect() returns null
I change the import by CDI annotations it still doesn't work (javax.enterprise.context.SessionScoped), same with JSF annotation (javax.faces.bean.ManagedBean and #ManagedProperty).
Thanks.
PD: Sorry for my English!
You can't mix annotations from those two packages you're using javax.faces.bean.SessionScoped for JSF, and import javax.inject.Named for CDI. Both reflect different injection mechanisms and cannot be mixed on the same bean. You have to pick both annotations(for Injection and Bean Scoping) from the same package. Use the following sets from their corresponding packages
For CDI-based bean definitions
javax.enterprise.context.SessionScoped //for bean scoping
javax.inject.Named //for bean declaration
javax.inject.Inject //for injection
For JSF-based bean definitions
javax.faces.bean.SessionScoped //for bean scoping
javax.faces.bean.ManagedBean //for bean declaration
javax.faces.bean.ManagedProperty //for bean injection
EDIT: Now I understand your requirements better, use the following construct to inject a JSF managed bean
#ManagedProperty(value="#{yourBeanName}")
SessionBean yourSessionBean;
Also note that within JSF, you can inject only beans of a wider scope than their targets e.g. you can inject a #SessionScoped bean into a #RequestScoped bean and not the other way around
But since JSF managed beans are deprecated, better to use the CDI managed ones. In that case you can inject shorter scoped beans in wider scoped ones
Forget about managed beans. It won't work with a Filter that way. If you insist on using it then do it properly by follow the answer provided here:
How implement a login filter in JSF?
Now regarding CDI, if you problem is that a specific value is null and you have verified this by actually getting a NPE or so (Since for example Eclipse debugger sometimes get's it wrong). Then double check that you used correct SessionScoped like described by kolossus and also check what BalusC said (beans.xml).
A good way to see if CDI is working is to ask the manager for the bean. Put this debug code somewhere and try it:
#Inject
BeanManager manager;
#PostConstruct
private void test() {
Bean<?> bean = (Bean) manager.resolve(manager.getBeans("ANY_NAMED_BEAN_EL_NAME"));
System.out.println(bean);
}