I have a simple service on Spring Boot with JAX-RS, JPA. It works fine on Tomcat, but when I deployed in WildFly 10, I get NPE (and Err 500 on web-page) for Services, which used Jpa query for DB. Service that doesn't use jpa-query work fine. Here is my configuration:
pom.xml:
groupId>com.github.naut92.animalswebservice</groupId>
<artifactId>animalsrestservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>AnimalsRestService</name>
<description>Restful 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>
<start-class>com.github.naut92.animalswebservice.AnimalsRestServiceApplication</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- thymeleaf used case-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- tag::security[] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- end::security[] -->
</dependencies>
<build>
<!--name project for deploying in Enterprise Servers-->
<finalName>animals-rest</finalName>
<plugins>
<!--plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin-->
<plugin>
<groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId>
<version>7.9.Final</version>
<executions>
<execution>
<id>jboss-deploy</id>
<phase>pre-integration-test</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
<execution>
<id>jboss-undeploy</id>
<phase>post-integration-test</phase>
<goals>
<goal>undeploy</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
JerseyConfig class:
@ApplicationPath("/index")
@Configuration
public class JerseyConfig extends ResourceConfig /*Application*/ {
public JerseyConfig() {
register(CustomerResource.class);
}
Service class:
@Component
@Path("/cust")
public class CustomerResource {
@Inject
private /*final*/ CustomersRepository customersRepository;
public CustomerResource(CustomersRepository customersRepository){
this.customersRepository = customersRepository;
}
public CustomerResource() {
}
//TEST--------------------------------
@GET
@Path(value = "/ajaxtest")
@Produces("application/json")
public Set<String> ajaxTest() {
Set<String> records = new HashSet<String>();
records.add("Record #1");
records.add("Record #2");
return records;
}
@GET
@Path(value = "/all")
@Produces("application/json")
public Collection<CustomersEntity> listCustomers() {
return (Collection<CustomersEntity>) customersRepository.findAll();
}
@GET
@Path("/all/{id}")
@Produces("application/json")
public CustomersEntity getCustomerById(@PathParam(value = "id") Long id) throws NotFoundException {
CustomersEntity customer;
if(customersRepository.exists(id)){
customer = customersRepository.findOne(id);
}
else
throw new NotFoundException("could not find user '" + id + "'.");
return customer;
}
}
and ajaxTest() method works fine, but the other two don't work:
java.lang.NullPointerException
at com.github.naut92.animalswebservice.resourcesService.CustomerResource.listCustomers(CustomerResource.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:295)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:249)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:236)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:402)
I try to used <exclusions>
for spring-boot-starter-tomcat like in this tutorial and spring-boot-starter-websocket, but I aways get the same error.
It's because Jersey isn't being used. You can tell be the exception that RESTEasy (Wildlfy's implementation of JAX-RS) is being used. The reason is because of the @ApplicationPath
annotation on the ResourceConfig
class. ResourceConfig
is an extension of the standard JAX-RS Application
class. And JAX-RS is designed to pick up an Application
class that is annotated with @ApplicationPath
.
So on startup, RESTEasy is creating the application, not Spring Boot. This is the reason for the NPE. RESTEasy creates the resource class, calling the default constructor, where the service is not initialized. And you are trying to call a non-initialized service during the request.
Now I don't know if this will work, as I've never tried to deploy to Wildfly, but the main things you need to fix are:
Remove the @ApplicationPath
so that RESTEasy doesn't pick it up. You can configure the path in your applicaiton.properties
file. Just use the property spring.jersey.application-path
You need to make sure your Spring Boot "application" class extends SpringBootServletInitializer
. This allows the application to be picked up by the container on startup. This is how Spring Boot will initialize the application.