Menu

Null Pointer Exception in RestEasy Asynchronous Request

2015-04-14
2015-06-11
  • Naveen Kumar

    Naveen Kumar - 2015-04-14

    I was working in Resteasy where I've to make a asynchronous request to server. The real purpose is, I'll be submitting a form which will be converted into a .xlsx file which will take atleast 10 seconds to complete. So Asynchronous request is the best way here. I followed the procedures from the following link.

    https://docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/#Asynchronous_HTTP_Request_Processing

    I'm making the ajax request like this.

    $.ajax({
      url : 'rest/parentPath/childPath',
      type : 'GET',
      success : function(data, status, xhr) {
          console.log(xhr.getResponseHeader('Location'));
      },
      failure : function(data) {
          console.log(data);
      },
      error : function(error,status) {
    
      }
    });
    

    ParentClass.java

    import javax.ws.rs.container.AsyncResponse;
    import javax.ws.rs.container.Suspended;
    
    @Component
    @Path("/parentPath")
    public class ParentClass {
       @GET
       @Path("childPath")
       @Produces("text/plain")
       public void asyncFunction(@Suspended final AsyncResponse response) {
           Thread t = new Thread() {
               @Override
               public void run() {
                   try {
                       Response jaxrs = Response.ok("basic").type(MediaType.TEXT_PLAIN).build();   
                       System.out.println("entered======================= =================================================");
                       response.resume(jaxrs);
                   }
                   catch (Exception e){
                       e.printStackTrace();
                   }
               }
           };
           t.start();
       }
    }
    

    If I simply make a ajax request, it gives me 503 Service unavailable error but I do get my Asynchronous task executed, I can confirm by seeing my sysout present in wildfly log. But this is not a way how a asynchronous should be done. I've to be able to see the response of my asynchronous task in the second request. I followed the procedures in this link.

    https://docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/#async_job

    If I put ?asynch=true in the request url, immediately i get a response of 202 Accepted with a location of asynchronous job in response. But it didn't even entered into the try statement. An error is thrown in the wildfly terminal like this.

    19:11:41,733 WARN  [org.jboss.resteasy.core.ExceptionHandler] (pool-4-thread-1) Failed executing GET /parentPath/childPath: org.jboss.resteasy.spi.BadRequestExcept
    ion: Failed processing arguments of org.jboss.resteasy.spi.metadata.ResourceMethod@44d4407c
      at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:104) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:112) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:296) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:250) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:237) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.AsynchronousDispatcher.invokeSuper(AsynchronousDispatcher.java:237) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.AsynchronousDispatcher$1.call(AsynchronousDispatcher.java:278) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.AsynchronousDispatcher$1.call(AsynchronousDispatcher.java:269) [resteasy-jaxrs-3.0.10.Final.jar:]
      at java.util.concurrent.FutureTask.run(FutureTask.java:266) [rt.jar:1.8.0_25]
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_25]
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_25]
      at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_25]
    Caused by: java.lang.NullPointerException
      at org.jboss.resteasy.core.ResourceMethodInvoker.initializeAsync(ResourceMethodInvoker.java:374) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.AsynchronousResponseInjector.inject(AsynchronousResponseInjector.java:43) [resteasy-jaxrs-3.0.10.Final.jar:]
      at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:89) [resteasy-jaxrs-3.0.10.Final.jar:]
       ... 12 more
    

    If I made the same request again with asynch=true, it shows the same error but with (pool-4-thread-2) instead of (pool-4-thread-1)

    This means exception is not occured at the server side but at the runtime layer. Coz any exception occured inside my code will be present in log file but not in wildfly terminal. I'll post the web.xml, WebConfig.java, build.gradle files. I'm just replicating the same thing which is done in jboss docs, but I cant figure out why is this exception occuring at the wildfly layer.

    Web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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_3_0.xsd" version="3.0">
    
       <display-name>Web Application</display-name>
    
       <distributable />
    
       <listener>
           <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
       </listener>
    
       <listener>
           <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
       </listener>
    
       <!-- Context Configuration locations for Spring XML files -->
       <context-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>
               classpath:/applicationContext-resources.xml
               classpath:/applicationContext-dao.xml
               classpath:/applicationContext-service.xml
               classpath*:/applicationContext.xml
              /WEB-INF/applicationContext*.xml
           </param-value>
       </context-param>
    
       <context-param>
           <param-name>resteasy.servlet.mapping.prefix</param-name>
           <param-value>/rest</param-value>
       </context-param>
    
       <context-param>
           <param-name>resteasy.async.job.service.enabled</param-name>
           <param-value>true</param-value>
       </context-param>
    
       <context-param>
           <param-name>resteasy.async.job.service.max.job.results</param-name>
           <param-value>100</param-value>
       </context-param>
    
       <!-- Maximum wait time on a job when a client is querying for it -->
       <context-param>
           <param-name>resteasy.async.job.service.max.wait</param-name>
           <param-value>300000</param-value>
       </context-param>
    
       <!-- Thread pool size of background threads that run the job -->
       <context-param>
           <param-name>resteasy.async.job.service.thread.pool.size</param-name>
           <param-value>100</param-value>
       </context-param>
    
       <!-- Set the base path for the Job uris -->
       <context-param>
           <param-name>resteasy.async.job.service.base.path</param-name>
           <param-value>/asynch/jobs</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.mypackage.service.WebConfig</param-value>
       </init-param>
           <load-on-startup>1</load-on-startup>
       </servlet>
    
       <servlet-mapping>
           <servlet-name>resteasy-servlet</servlet-name>
           <url-pattern>/rest/*</url-pattern>
      </servlet-mapping>
    
      <welcome-file-list>
          <welcome-file>login.html</welcome-file>
      </welcome-file-list>
    
    </web-app>
    

    WebConfig.java

    import java.util.HashSet;
    import java.util.Set;
    
    import javax.ws.rs.core.Application;
    
    public class WebConfig extends Application {
    
       private Set<Object> singletons = new HashSet<Object>();
       private Set<Class<?>> empty = new HashSet<Class<?>>();
    
       public WebConfig() {
           // ADD YOUR RESTFUL RESOURCES HERE
           this.singletons.add(new SignupService());
           this.singletons.add(new UserService());
           this.singletons.add(new ParentClass());
       }
    
       public Set<Class<?>> getClasses()
       {
           return this.empty;
       }
    
       public Set<Object> getSingletons()
       {
           return this.singletons;
       }
    
    }
    

    Build.gradle

    apply plugin: 'java'
    apply plugin: 'war'
    apply plugin: 'eclipse-wtp'
    apply plugin: 'eclipse'
    
    // Uses JDK 8
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
    
    // 1. Get dependencies from Maven local repository
    // 2. Get dependencies from Maven central repository
    repositories {
      mavenLocal()
      mavenCentral()
      maven  {
      url "http://repo1.maven.org/maven2"
       }
    }
    
    configurations {
      provided
    }
      sourceSets {
      main { compileClasspath += configurations.provided }
    }
    
    //Project dependencies
    dependencies {
    
       //Spring framework core
      compile 'org.springframework:spring-web:4.1.4.RELEASE'
      compile 'org.springframework:spring-core:4.1.4.RELEASE'
      compile 'org.springframework:spring-context:4.1.4.RELEASE'
      compile 'org.springframework:spring-context-support:4.1.4.RELEASE'
      compile 'org.springframework:spring-orm:4.1.4.RELEASE'
    
      compile 'org.springframework.security:spring-security-core:4.0.0.RELEASE'
    
       //MySQL database driver
       //compile 'mysql:mysql-connector-java:5.1.34'
      compile 'com.oracle:ojdbc6:11.2.0.1.0'
    
       //Hibernate framework 
      compile 'org.hibernate:hibernate-core:4.3.8.Final'
      compile 'commons-dbcp:commons-dbcp:1.2.2'
    
       //Servlet API
      compile 'javax.servlet:servlet-api:2.5'
    
       //Base-64 Apache commons
      compile 'commons-codec:commons-codec:1.10'
    
       //log4j
      compile 'log4j:log4j:1.2.17'
      compile 'org.slf4j:slf4j-simple:1.7.10'
    
       //XmlBeans Equity Valuation
      compile 'org.apache.xmlbeans:xmlbeans:2.6.0'
    
       //Poi Equity Valuation
      compile 'org.apache.poi:poi:3.10.1'
    
       //Poi ooxml Equity Valuation
      compile 'org.apache.poi:poi-ooxml:3.10.1'
    
       //Poi ooxml Schemas Equity Valuation
      compile 'org.apache.poi:poi-ooxml-schemas:3.10.1'
    
       //Jacob Equity Valuation
      compile 'jacob:jacob:1.18-M2'
    
       //Google gson
      compile 'com.google.code.gson:gson:2.3.1'
    
      provided 'org.jboss.resteasy:resteasy-jaxrs:3.0.11.Final'
    
      provided 'org.jboss.resteasy:resteasy-spring:3.0.11.Final'
    
    }
    
     
  • Ron Sigal

    Ron Sigal - 2015-06-11

    Hi Naveen,

    According to the JAX-RS 2.0 spec, "JAX-RS implementations are REQUIRED to generate a ServiceUnavailableException , a subclass of WebApplicationException with its status set to 503, if the timeout value is reached and no timeout handler is registered." I don't see anything that would cause a timeout in your case - the default behavior is to allow the response to suspend indefinitely.

    There is an asynchronous example here:

    https://github.com/resteasy/Resteasy/tree/master/jaxrs/async-http-servlet-3.0/async-http-servlet-3.0-test

    In particular, see org.jboss.resteasy.test.async.JaxrsAsyncTest. You can run it with

    mvn install -Dtest=JaxrsAsyncTest

    Or, you can start jetty with

    mvn jetty:run

    and then run the test in an IDE.

    One thing I can tell you is that I'm not sure what happens when you mix "Asynchronous HTTP Request Processing" from Chapter 34 of the Resteasy guide and "Asynchronous Job Service" from Chapter 35. That might be why you're getting a NullPointerException.

    Note that the JAX-RS 2.0 spec defines an asynchronous client side facility, which you can use if you want to poll the server. See

    http://java.dzone.com/articles/whats-new-jax-rs-20

    for example.

    -Ron

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.