I am pretty new to spring. I have dynamic web application project. Inside i have a servlet which is receive request. The request comes with a request no. Based on the no i will create a new object for appropriate request class and serve the request. Now i need to integrate with spring. i applied the below configuration,
WEB.XML (To load spring context)
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/docspring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
In servlet
package com.receve;
#Controller
#WebServlet("/Recever")
public class Recever extends HttpServlet {
#Autowired
private ClassOne one;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//request parameters receved and
if(req==1){
one.print();
}
}
public ClassOne getOne() {
return One;
}
public void setOne(ClassOne one) {
this.one = one;
}
}
In ClassOne
package com.operations;
#Component
public Class ClassOne{
public void print(){
//some statement;
}
}
In spring.xml
<context:annotation-config />
<context:component-scan base-package="com" />
But while running the application i am getting NullPointerexception while calling one.print() method. what is the proper way(configuration) to obtain this?
Thanks.
Remove extends HttpServlet and Autowiring is turned off by default, so the default autowiring mode for a bean is 'no'.
Related
I've created a Servlet and added configuration in web.xml:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.foo.web.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myservlet/*</url-pattern>
</servlet-mapping>
Registered a bean for it:
<bean id="MyServlet" class="com.foo.MyServlet" autowire="byType">
<property name="MyService" ref="MyManager"/>
</bean>
I've created a bean which is injected into MyServlet
<bean id="MyManager" class="com.foo.MyService" autowire="byType">
</bean>
There s a setter method in the servlet used by spring for setting the property to the bean:
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private MyManager myService;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws
ServletException, IOException {
}
public void setMyService(MyManager myManager){
this.myService = myManager;
}
}
Autowiring is done correctly during the application startup, but when Servlet "catches" some request, this property (myService) is not instantiated (it's null). How or can I even have a Servlet with some autwired properties?
I'm working on a project which has spring mvc 2.5.* .I have integrated RESTeasy to create restful endpoints. I have defined a controller class with #Controler. I have a bean which is supposed to be injected to this controller but it seems it's not getting injected, thus it throws a null pointer exception when the bean variable is used in controller rest methods.
I have added these to the web.xml
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.package.controller.MyApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Customized class I extended from resteasy Application class to define application path:
#ApplicationPath("/rest")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
// register root resource
classes.add(EmployeeController.class);
return classes;
}
}
I have a servlet.xml which has defined mvc controller beans which works fine:
eg:
<bean name="/testDetail.html" class="com.test.package.controller.TestDetailController" parent="baseController">
<property name="testService" ref="testService"/>
</bean>
My Controller class looks like this:
#Controller
#Path("/employee")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class EmployeeController {
private static final Log LOG = LogFactory.getLog(EmployeeController.class);
private EmployeeService employeeService; // This doesn't get initiated.
#PUT
#Path("/update/{empId}")
public Response updateEmp(#PathParam("empId") Long empId, EmpRequest request) {
Response response = null;
employeeService.update(request); // NULL POINTER THROWN HERE, employeeService is null
return response;
}
public EmployeeService getEmployeeService () {
return employeeService ;
}
public void serEmployeeService (EmployeeService employeeService ) {
this.employeeService = employeeService ;
}
}
Here I added another bean to servlet.xml as,
<bean id="employeeController " class="com.test.package.controller.EmployeeController">
<property name="employeeService " ref="employeeService "/>
</bean>
In a separate xml employeeService bean is defined. It' just that it won't reflect in the employeeController bean. I'm not sure if even employeeController bean is created or not. But I'm able to call the endpoint successfully. bean initiation works fine if put employeeService bean in a MVC controller. eg:
<bean name="/testDetail.html" class="com.test.package.controller.TestDetailController" parent="baseController">
<property name="employeeService " ref="employeeService "/>
</bean>
But not in RestController. Any Idea on this behavior. Am I missing any configuration here.
firstly, you should define the employeeService bean as follows,
<bean id="employeeService" class="com.test.package.service.EmployeeService">
--------
</bean>
load the above config xml file in web.xml,
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/XML_FILE_PATH/XML_FILE_NAME.xml</param-value>
</context-param>
then, you can use employeeService bean
use #PostConstruct annotation for invoke with this method after employeeService bean is initialized
#PUT
#PostConstruct
#Path("/update/{empId}")
public Response updateEmp(#PathParam("empId") Long empId, EmpRequest request) {
Response response = null;
employeeService.update(request); // NULL POINTER THROWN HERE, employeeService is null
return response;
}
How can I make my Spring Rest HelloWorld app work without using Spring Boot?
When running this project in tomcat 8.5 within eclipse, I expect the url "localhost:8080/hello" to show "HelloWorld", but instead it shows 404
src/main/java/com.package/HelloController.java
#RestController
public class HelloController {
#RequestMapping("/hello")
public String helloWorld() {
return "Hello World";
}
}
src/main/java/com.package/HelloConfig.java
public class HelloConfig {
#Bean
public HelloController helloController() {
return new HelloController();
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(HelloConfig.class);
context.getBean(HelloController.class);
}
}
build.gradle
plugins {
id 'java'
id 'war'
id 'eclipse-wtp'
}
dependencies {
compile 'org.springframework:spring-context:5.0.3.RELEASE'
compile 'org.springframework:spring-web:5.0.3.RELEASE'
testCompile 'junit:junit:4.12'
}
repositories {
mavenCentral()
}
Answering my own question: the missing bit was the DispatcherServlet, the logic responsible for delegating http requests to Controllers, like HelloController in my example.
Based on Spring docs (https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet), there are 3 ways to configure DispatcherServlet:
in web.xml
overriding WebApplicationInitializer
extending AbstractAnnotationConfigDispatcherServletInitializer (recommended for apps with Java based configurations like mine)
src/main/java/com.package/ServletInitializer:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { HelloConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
note: why the downvotes?
You may need to WebApplicationInitializer and AnnotationConfigWebApplicationContext on start up.In onStartup Method you can mention the root context of your application and access the controller mapping thereon.
public class CustomWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfiguration.class);
ContextLoaderListener contextLoaderListener = new ContextLoaderListener(rootContext);
container.addListener(contextLoaderListener);
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(MvcConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", dispatcherServlet);
dispatcher.addMapping("/");
}
}
I am not sure if you have checked your web.xml for web application and you have correctly set the below configuration
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:pathToYourSpringBeanConfig/channel-application-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath: pathToYourSpringBeanConfig/channel-application-context.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Also you need to provide location of your context xml application where you need to tell your context like following details:
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="group.*"></context:component-scan>
PS : if you want to access URL without war name you might wanna check this
Deploy war on Tomcat without the war name in the URL
I'm trying to implement an application with several uis - vaadin, jsp and etc.
It was working with simple jsp but then I decided to use vaadin as ui.
I've created vaadin servlet(and spring servlet left too).
My web.xml looks like this
<?xml version="1.0"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/pmc-web-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>another-pmc-servlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>com.xxxx.app.pmc.vaadin.PmcUi</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>pmc-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>another-pmc-servlet</servlet-name>
<url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>pmc-servlet</servlet-name>
<url-pattern>/JSP/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/WEB-INF/jsp/*</url-pattern>
</servlet-mapping>
</web-app>
I've created vaadin table component and adjusted it for my needs. I used autowiring for service.
package com.xxxx.app.pmc.vaadin.components;
import com.xxxx.app.pmc.model.Project;
import com.xxxx.app.pmc.service.project.ProjectService;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Table;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Component("projectTable")
public class ProjectTable extends Table {
private static final String CAPTION = "Projects";
private static final String[] headers = { "Project name", "Project owner", "ID" };
#Autowired
private ProjectService projectService;
public Table createTable() {
this.setContainerDataSource(projectDatasource());
this.setVisibleColumns(headers);
this.setSelectable(true);
this.setImmediate(true);
return this;
}
public IndexedContainer projectDatasource() {
IndexedContainer indexedContainer = new IndexedContainer();
for(String header: headers) {
indexedContainer.addContainerProperty(header, String.class, "");
}
List<Project> projects = projectService.findAllProjects();
for(int i = 0; i < projects.size(); i++) {
Object id = indexedContainer.addItem();
Project item = projects.get(i);
indexedContainer.getContainerProperty(id, headers[0]).setValue(item.getProjectName());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getProjectOwner());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getProjectId());
}
return indexedContainer;
}
}
ProjectService is a spring bean too.
#Service("projectService")
public class ProjectService {
#Autowired
private ProjectRepository projectRepository;
public void insertProject(Project project) {
projectRepository.store(project);
}
public List<Project> findAllProjects() {
return projectRepository.getAllItems();
}
public Project getProject(String id) {
return projectRepository.get(id);
}
}
ProjectRepository is another spring bean. It uses SqlSessionTemplate bean from MyBatis.
#Repository("projectRepository")
public class ProjectRepository implements IRepository<Project> {
private static final String STORE_PROJECT = "Project.insertProject";
private static final String GET_PROJECT_BY_ID = "Project.getProjectById";
private static final String GET_PROJECT_LIST = "Project.getProjectList";
#Autowired
private SqlSessionTemplate sqlSessionTemplate;
#Override
public void store(Project object) {
sqlSessionTemplate.insert(STORE_PROJECT, object);
}
#Override
public Project get(String id) {
return sqlSessionTemplate.selectOne(GET_PROJECT_BY_ID, id);
}
#Override
public List<Project> getAllItems() {
return sqlSessionTemplate.selectList(GET_PROJECT_LIST);
}
}
When I wrote an application using spring controller(using JSP) - it was working fine.
But when I added vaadin - JSP stopped working and vaadin application throws NullPointerException for ProjectService, ProjectRepository... all the beans I use.
What is the problem?
All my context xml context files are simple.
<import resource="classpath:com/xxxx/app/pmc/pmc-service-context.xml"/>
<context:component-scan base-package="com.xxx.app.pmc"/>
And my pmc-web-context.xml has this lines too.
<mvc:annotation-driven/>
<context:annotation-config/>
It was working fine with JSP so I think the problem is not with spring declarations itself but with integration of spring into vaadin of mine.
How to resolve it?
When I for example created ProjectTable object manually - it throws NullPointerException for ProjectService. When I create ProjectService manually - it throws NullPointerException for ProjectRepository and so on. It seems autowiring simply doesn't work.
P.S forgot to add my UI code
package com.xxxx.app.pmc.vaadin;
import com.xxxx.app.pmc.vaadin.components.ProjectTable;
import com.vaadin.annotations.Title;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import org.springframework.stereotype.Component;
#Title("PMC")
#Component("pmcVaadin")
public class PmcUi extends UI {
#Override
protected void init(VaadinRequest request) {
VerticalLayout mainLayout = new VerticalLayout();
ProjectTable projectTable = new ProjectTable();
mainLayout.addComponent(projectTable.createTable());
mainLayout.setSizeFull();
setContent(mainLayout);
}
}
Like you suspected your Spring beans are created, but in application and Spring's servlet contexts. Your Vaadin servlet has no access to any of those.
For detailed (manual) solution with code either check Vaadin's wiki or search for a proper Vaadin's add ons that will do the job for you (personally I recommend SpringVaadinIntegration).
The typical idea is to programmatically pass Vaadin servlet to one of Spring's utility classes (eg.: WebApplicationContextUtils) and retrieve application context (loaded by ContextLoaderListener). If you need servlet context, then from code examples I have seen, you do the same as above, but additionally manually read context (eg.: using XmlWebApplicationContext) and set application context as it's parent.
Pretty easy option is to use Configurable support. It'll do some aspect magic and all java objects annotated by #Configurable will be automatically integrated into Spring. You can find more details in Spring documentation. Also please note that to represent context information in GUI you will have to use session beans. That causes the problem with session size, and in bigger applications makes it impossible to cluster.
I'm new to Guice and already stuck :)
I pretty much copied classes GuiceConfig, OfyFactory and slightly modified Ofy from Motomapia project (which you can browse) using it as s sample.
I created GuiceServletContextListener which looks like this
public class GuiceConfig extends GuiceServletContextListener
{
static class CourierServletModule extends ServletModule
{
#Override
protected void configureServlets()
{
filter("/*").through(AsyncCacheFilter.class);
}
}
public static class CourierModule extends AbstractModule
{
#Override
protected void configure()
{
// External things that don't have Guice annotations
bind(AsyncCacheFilter.class).in(Singleton.class);
}
#Provides
#RequestScoped
Ofy provideOfy(OfyFactory fact)
{
return fact.begin();
}
}
#Override
public void contextInitialized(ServletContextEvent servletContextEvent)
{
super.contextInitialized(servletContextEvent);
}
#Override
protected Injector getInjector()
{
return Guice.createInjector(new CourierServletModule(), new CourierModule());
}
}
I added this listener into my web.xml
<web-app>
<listener>
<listener-class>com.mine.courierApp.server.GuiceConfig</listener-class>
</listener>
<!-- GUICE -->
<filter>
<filter-name>GuiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>GuiceFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<!-- My test servlet -->
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.mine.courierApp.server.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>
OfyFactory looks like this
#Singleton
public class OfyFactory extends ObjectifyFactory
{
Injector injector;
#Inject
public OfyFactory(Injector injector)
{
this.injector = injector;
register(Pizza.class);
register(Ingredient.class);
}
#Override
public <T> T construct(Class<T> type)
{
return injector.getInstance(type);
}
#Override
public Ofy begin()
{
return new Ofy(super.begin());
}
}
Ofy doesn't have any Guice annotations at all...
public class Ofy extends ObjectifyWrapper<Ofy, OfyFactory>
{
// bunch of helper methods here
}
And finally test servlet where I'm trying to use injected field looks like this
public class TestServlet extends HttpServlet
{
#Inject Ofy ofy;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ofy.save(new Pizza());
}
}
Ofy ofy is always null. It's never injected. And it's not injected because OfyFactory is never instantiated, its constructor is never called.
Could you please point what I'm doing wrong? Why my singleton is never created?
Thanks a lot.
Instead of defining TestServlet in the web.xml file, try deleting its mapping from web.xml and adding this line in the configureServlets() method:
serve("/test").with(TestServlet.class);
You may also need to bind TestServlet as a Singleton either by annotating the class with #Singleton or by adding a
bind(TestServlet.class).in(Singleton.class);
line to one of the modules.
What's happening is that Guice is not actually creating your servlet so it isn't able to inject the Ofy object. Guice will only create servlets if it is instructed to do so using a serve(...).with(...) binding. Any servlets defined in the web.xml are outside of Guice's control.