Reputation: 21
I have created a application in GWT + Spring Boot and when I try to use @Autowired
- I get NullPointerException
. Apparently @Autowired
does not work and does not insert the bean in the right place. How can I fix this situation?
Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.util.List com.myGWT.springbootapp.client.UserService.list()' threw an unexpected exception: java.lang.NullPointerException
File web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>userService</servlet-name>
<servlet-class>com.myGWT.springbootapp.server.UserServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>userService</servlet-name>
<url-pattern>/gwtApp/service</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>GWTApp.html</welcome-file>
</welcome-file-list>
</web-app>
pom.xml
<name>spring-boot-app</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<gwt.version>2.7.0</gwt.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<!-- GWT -->
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>${gwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-codeserver</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>apache-jsp</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwt.version}</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>target</directory>
</fileset>
<fileset>
<directory>builds</directory>
<includes>
<include>**/*.*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>deploy</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<id>deploy</id>
<phase>deploy</phase>
<goals><goal>deploy</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
File UserServiceImpl.java
package com.myGWT.springbootapp.server;
import com.myGWT.springbootapp.client.UserService;
import com.myGWT.springbootapp.entities.User;
import com.myGWT.springbootapp.repositories.UserRepository;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends RemoteServiceServlet implements UserService {
AnnotationConfigWebApplicationContext();
@Autowired
private UserRepository repository ;
@Override
public List<User> list() {
return repository.findAll();
}
}
File UserRepository.java
package com.myGWT.springbootapp.repositories;
import com.myGWT.springbootapp.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
File UserService.java
package com.myGWT.springbootapp.client;
import com.myGWT.springbootapp.entities.User;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import java.util.List;
@RemoteServiceRelativePath("service")
public interface UserService extends RemoteService {
List<User> list();
}
File GWTApp.java
package com.myGWT.springbootapp.client;
import com.myGWT.springbootapp.entities.User;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.view.client.ListDataProvider;
import java.util.List;
public class GWTApp implements EntryPoint {
private UserServiceAsync userService = GWT.create(UserService.class);
private ListDataProvider<User> createTable (CellTable<User> table){
TextColumn<User> idColumn =new TextColumn<User>() {
@Override
public String getValue(User object) {
return object.getId().toString();
}
};
TextColumn<User> loginColumn =new TextColumn<User>() {
@Override
public String getValue(User object) {
return object.getLogin();
}
};
table.addColumn(idColumn, "Id");
table.addColumn(loginColumn, "Login");
final ListDataProvider<User> dataProvider = new ListDataProvider<>();
dataProvider.addDataDisplay(table);
this.userService.list(new AsyncCallback<List<User>>() {
@Override
public void onFailure(Throwable caught) {
Window.alert("Error: " + caught.getMessage());
}
@Override
public void onSuccess(List<User> result) {
dataProvider.getList().addAll(result);
}
});
return dataProvider;
}
public void onModuleLoad() {
CellTable<User> table = new CellTable<>();
ListDataProvider<User> dataProvider = createTable(table);
RootPanel.get().add(table);
}
}
Directory structure of the project
Upvotes: 2
Views: 861
Reputation: 1551
The short answer is: Spring didn't instantiate your GWT service; therefore it can't autowire anything into it.
The Jetty container is actually responsible for creating and mapping an instance of UserServiceImpl
. That's what your web.xml
is describing.
Your @Service
annotation is indeed creating a Servlet instance within the Spring context as you would expect, but it's not known to Jetty. Historically, I have removed the @Service annotation from my RemoteServiceServlet
-based services and added the following method to provide @Autowire
support:
public class UserServiceImpl extends RemoteServiceServlet implements UserService {
...
@Override
public void init() throws ServletException {
super.init();
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
}
...
}
From the SpringBeanAutowiringSupport
javadoc:
Process @Autowired injection for the given target object, based on the current root web application context as stored in the ServletContext.
Jetty will call init()
during Servlet creation and boom, you're beans come together. This is on the hacky side of things because it bridges two unrelated processes, but it is working for me in production currently.
Using a Servlet 3.0+ compliant container you can probably find a way to use WebApplicationInitializer
(javadoc) to fire up your Spring context via AnnotationConfigWebApplicationContext
(javadoc) prior to mapping your servlets which would allow you to use the instances from there (this replaces your web.xml
).
Edit:
And since you're using Spring Boot you can take a peek at this thread which shows how to map servlets via ServletRegistrationBean
: How can I register a secondary servlet with Spring Boot? (see checketts's answer)
Upvotes: 2