Configurating Spring Ioc with Servlets - java

I'm new in Spring and want to connect spring ioc into my small(test) web-app.
I have such Servlet ProductServlet:
public class ProductServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
private RequestHelper requestHelper;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request);
}
private void processRequest(HttpServletRequest request){
requestHelper.process(request);
}
public RequestHelper getRequestHelper() {
return requestHelper;
}
public void setRequestHelper(RequestHelper requestHelper) {
this.requestHelper = requestHelper;
}
}
and my web.xml:
<servlet>
<servlet-name>ProductServlet</servlet-name>
<servlet-class>com.epam.productshop.controller.ProductShop</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProductServlet</servlet-name>
<url-pattern>/ProductServlet</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-config.xml
</param-value>
</context-param>
and also I have such spring configuration xml:
<bean id="factory" class="com.epam.productshop.readerfactory.ReaderFactory">
<property name="file" value="/xml/products.xml" />
</bean>
<bean id="requestHelper" class="com.epam.productshop.requesthelper.RequestHelper" scope="singleton">
<property name="factory" ref="factory" />
</bean>
<bean name="ProductServlet" class="com.epam.productshop.controller.ProductServlet" scope="singleton">
<property name="requestHelper" ref="requestHelper"/>
</bean>
and I have such problem:
I want spring set requestHelper object into my servlet during servlet init(). but instead of this it's gives me nullpointer.
I'm trying to implement my servlet from HttpRequestHandler, writing SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext()); into init() method and other things that i see in the internet but all this things doesn't solve my problem.
Please help me

In your question you have
<bean name="ProductServlet" class="com.epam.productshop.controller.ProductServlet" scope="singleton">
<property name="requestHelper" ref="requestHelper"/>
</bean>
You cannot instantiate servlets with Spring container, they are instantiated by servlet container. You're merely declaring another instance of ProductServlet.
So, when the Servlet init() method is called you should call
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());`
To inject the requestHelper declare an #Autowired annotated field or property in your servlet:
private RequestHelper requestHelper;
#Autowired
public void setRequestHelper(RequestHelper requestHelper){
this.requestHelper = requestHelper;
}
from processInjectionBasedOnServletContext javadoc:
Process #Autowired injection for the given target object, based on the
current root web application context as stored in the ServletContext.

Here is a solution, which might help you:
public class ProductServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private RequestHelper requestHelper = null;
private requestHelperInit(HttpServletRequest request)
{
if(requestHelper == null)
{
ApplicationContext ap = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
requestHelper = ap.getBean(RequestHelper.class);
}
}
}
Then call requestHelperInit(request) method in either your doGet() or doPost() method as the first statement.
If you are still looking for a solution, then I hope this will help you out.

You have a couple of choices. If you really want to inject a servlet, the problem is that the servlet container is already in charge of creating the servlet. Since injections are a creation time occurence, and it's a bit hard to get at this servlet creation, you have to use less elegant solutions. However, this question explains how to inject servlets.
On the other hand, you might consider aborting this approach. If you are really creating a web application, it's fairly uncommon to code directly to the servlet api. Why not choose one of the many web application frameworks that sit on top of the servlet api and provide higher level functionality, aka bells and whistles. One of the bells and whistles is that these frameworks provide convenient integration with Spring so you can easily inject your code. For instance, Struts 2 has a spring plugin that allows you to use spring to inject all of the objects created by the framework, including framework infrastructural components.

Related

Create bean in spring context

<bean id="configuration" class="com.mypackage.util.Configuration" factory-method="getInstance">
<property name="path" value="${path.props.app.dev}"></property>
</bean>
Then I have the following in my class
Configuration.getInstance();
Whereas the spring application context is loaded in another class Factory like this
private Factory() {
context = new ClassPathXmlApplicationContext("META-INF/spring.xml");
}
The problem is that before Factory class is accessed the context does not load and the configuration object gives null for path whereas when Factory is accessed and after that path property is accessed it gives the correct path.
Please tell me how to do it correctly? That is how can i get my member variable path with correct data without accessing Factory class.
Assuming that you are using Spring WebMVC. There are 2 ways:
Putting you bean configurations to dispatcher config XML (mvc-dispatcher-servlet.xml)
Remain your spring.xml and specify it in web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>spring.xml</param-value>
</context-param>
In both cases, you will no longer need a class like Factory. Besides, because of that Spring creates beans in singleton scope by default, you do not need to implement a getInstance() method for your com.mypackage.util.Configuration class.

Bean Validation does't work

I'm currently learning spring but I'm stuck with the validation annotation that don't works with my bean. I really don't understand what missing and I would need a Hand :)
I have a controller :
#Controller
public class CirclesController {
#RequestMapping(value = "/createCircle", method = RequestMethod.POST)
public ModelAndView createCircle(#Valid Circle circle, BindingResult res) {
if (res.hasErrors()) {
System.out.println("Can't validate this form..");
else
System.out.println("Created new circle : " + circle);
}
}
And a bean :
public class Circle {
#Size(min = 5) // This is what I try to validate
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I configured the web.xml
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:conf/dao-context.xml
classpath:conf/services-context.xml
classpath:conf/beans-context.xml
</param-value>
</context-param>
my prject looks like that :
the *-context.xml have the component-scan and anotation-config tags :
<context:component-scan base-package="com.test.app.[package-name]">
</context:component-scan>
<context:annotation-config></context:annotation-config>
<tx:annotation-driven></tx:annotation-driven>
I have all the external libraries (hibernate, hibernate-api, javax.validation) and no error on the run time...
but when I fill the field "name" wit less than 5 characters, I always get "Created new circle : Circle{name=txt}" instead of "Can't validate this form..".
EDIT :
Here is my classpath :
and the servlet-context.xml :
<context:component-scan base-package="com.test.app.controllers"></context:component-scan>
<mvc:annotation-driven></mvc:annotation-driven>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsps/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
Providing the list of your dependencies and the circles-servlet.xml would give a full context to your question.
Nevertheless, for what I see there could be only two things missing. First make sure that you have the validation provider such as hibernate-validator on your classpath, second make sure that you have
<mvc:annotation-driven />
element in your circles-servlet.xml it provides support for enabling validation against parameter objects of your controller annotated with #Valid
UPDATE after comment
the bean validation has an updated specification, so you should align your dependencies in the following manner
hibernate-validator-5.x.x
validation-api-1.1.x
which will implement a JSR-349
OR
hibernate-validator-4.x.x
validation-api-1.0.x.
which implements JSR-303
Your issue from the comment means that you've most likely mixed the dependency, so used hibernate-validator-5.x.x with validation-api-1.0.x or missed it the other way around
See the very bottom of this page:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
Add the following to you spring config:
<!-- JSR-303/JSR-349 support will be detected on classpath and enabled automatically -->
<mvc:annotation-driven/>
Use #RequestBody annotation with #Valid annotation
public ModelAndView createCircle(#Valid #RequestBody Circle circle, BindingResult res) {

ServletConfig with out xml configuration in jsp?

How to set ServeltConfig param name and value in index.jsp page with out xml configuration like initParams in Servlet ? is Possible ?
<servlet>
<servlet-name>welcome</servlet-name>
<jsp-file>/index.jsp</jsp-file>
<init-param>
<param-name>website</param-name>
<param-value>www.google.com</param-value>
</init-param>
</servlet>
In JSP, we have implicit objects, in which we have config (This is the ServletConfig object associated with the page) object. But I guess we can't add parameters manually as their is not method for adding init parameter in ServletConfig interface.
If you want to save any parameters you can save in 4 scopes of JSP (page,request,session and application) and use it wherever you needed.
<c:set var="user" value="TestUser" scope="session"> //can set any value
You can do this with ServletContextListener. When the container starts up, it will call the ServletContextListener class. There you can set your params:
#WebListener
public class ContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext ctx = servletContextEvent.getServletContext();
ctx.setAttribute("website", "www.google.com");
}
}

RESTEasy will not map my Spring bean with custom Spring ContextLoader

RESTEasy 2.0.1GA
Java 1.6
Spring 3.0.3
I have tried everything I can, and cannot make head or tail of what's going on. I have a Spring MVC application, however I'd like to have some RESTEasy endpoints available outside the Spring MVC app, but in the same container, ultimately being able to wire in the same beans.
As a first step, I'm simply trying to stand-up RESTEasy inside the container, serving requests from a Spring-configured bean. I have tried the boilerplate from the instructions and have also tried manual setup, to no avail.
Bean
#Resource
#Path("/")
public class NeighborComparison {
private String foo;
#GET #Path(value="customer") #Produces("text/plain")
public String getNeighborComparison() {
return "foo";
}
}
web.xml
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/api</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<!-- NOT configuring SpringContextLoaderListener because I declare my own, so if I do, everything
blows up, plus all it actually does is sanity check configuration -->
<listener>
<listener-class>com.example.MyCustomContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
applicationContext.xml
<bean id="resteasy.providerFactory" class="org.jboss.resteasy.spi.ResteasyProviderFactory"
factory-method="getInstance">
</bean>
<bean id="resteasy.dispatcher" class="org.jboss.resteasy.core.SynchronousDispatcher">
<constructor-arg ref="resteasy.providerFactory"/>
</bean>
<bean id="resteasy.spring.bean.processor" class="org.jboss.resteasy.plugins.spring.SpringBeanProcessor">
<description>
Add Resources and #Providers to the appropriate places
in Resteasy's infrastructure
</description>
<constructor-arg ref="resteasy.dispatcher"/>
</bean>
<bean id="neighborComparison" class="opower.api.customer.neighbor_comparison.NeighborComparison">
</bean>
According to the documentation, all I have to do is “manually register the RESTeasy BeanFactoryPostProcessor by allocating an instance of org.jboss.resteasy.plugins.spring.SpringBeanProcessor”. I believe this spring configuration does that.
Jetty starts and the app context spins up with no issues. Application works normally, however when I
> curl -H"Accept: text/plain" localhost:8080/ei/api/customer
("ei" is the application context). The log shows (this and only this):
2011-03-29 16:44:24,153 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] PathInfo: /customer
2011-03-29 16:44:24,156 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] Failed executing GET /customer
org.jboss.resteasy.spi.NotFoundException: Could not find resource for relative : /customer of full path: http://localhost:8080/ei/api/customer
Even if I could convince RESTEasy to show me the mappings, it seems that it's just not discovering my bean.
If I map it explicitly via the resteasy.resources context param, it works, though obviously doesn't have access to auto-wired Spring beans.
Anything else I can try? I have debug log on the entire RESTEasy codebase and I don't get any messages. I've also confirmed that Spring is, in fact, creating my bean, so it's just that RESTEasy isn't finding it.
Your resource class needs to be annotated with #Path annotation for RESTeasy to pick up on it during bootstrap:
#Path("/customer")
#Resource
public class NeighborComparison {
#GET #Path("/{customerId}") #Produces("text/plain")
public String getNeighborComparison(#PathParam("customerId") long customerId) {
return "foo";
}
}
Note the #Path("/{customerId}} annotation without which your #PathParam parameter would not have been mapped correctly, resulting in a pretty detailed exception (and an accompanying 500 response on the client side). Assuming the service is picked up by RESTeasy of course.
In addition if you don't use RESTeasy's SpringContextLoader, you have to make sure your SpringBeanProcessor instance is registered with the ApplicationContext. RESTeasy delegates to it by registering an ApplicationListener in SpringContextLoader:
ApplicationListener listener = new ApplicationListener() {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ContextRefreshedEvent cre = (ContextRefreshedEvent) event;
ConfigurableListableBeanFactory autowireCapableBeanFactory = (ConfigurableListableBeanFactory) cre
.getApplicationContext().getAutowireCapableBeanFactory();
new SpringBeanProcessor(dispatcher, registry, providerFactory)
.postProcessBeanFactory(autowireCapableBeanFactory);
}
}
};
configurableWebApplicationContext.addApplicationListener(listener);
If using a custom context loader and not the RESTEasy-provided one, this code has to appear somewhere in your context loader so that everything gets wired up. A bit convoluted, yeah. It is SpringBeanProcessor that goes through all Spring beans and registers with RESTeasy those that have a #Path annotation somewhere in their hierarchy (type and their corresponding interfaces).

Access Spring beans from a servlet in JBoss

I want to write a simple servlet in JBoss which will call a method on a Spring bean. The purpose is to allow a user to kick off an internal job by hitting a URL.
What is the easiest way to get hold of a reference to my Spring bean in the servlet?
JBoss web services allow you to inject a WebServiceContext into your service class using an #Resource annotation. Is there anything comparable that works in plain servlets? A web service to solve this particular problem would be using a sledgehammer to crush a nut.
There is a much more sophisticated way to do that. There is SpringBeanAutowiringSupportinside org.springframework.web.context.support that allows you building something like this:
public class MyServlet extends HttpServlet {
#Autowired
private MyService myService;
public void init(ServletConfig config) {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
}
This will cause Spring to lookup the ApplicationContext tied to that ServletContext (e.g. created via ContextLoaderListener) and inject the Spring beans available in that ApplicationContext.
Your servlet can use WebApplicationContextUtils to get the application context, but then your servlet code will have a direct dependency on the Spring Framework.
Another solution is configure the application context to export the Spring bean to the servlet context as an attribute:
<bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="jobbie" value-ref="springifiedJobbie"/>
</map>
</property>
</bean>
Your servlet can retrieve the bean from the servlet context using
SpringifiedJobbie jobbie = (SpringifiedJobbie) getServletContext().getAttribute("jobbie");
I've found one way to do it:
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
SpringifiedJobbie jobbie = (SpringifiedJobbie)context.getBean("springifiedJobbie");

Categories