java - 使用 Swagger 文档的异步 Jersey REST API 中的 NullPointerException

标签 java multithreading rest asynchronous jersey-2.0

我正在使用一个 Jersey 2.10 应用程序的 REST API,它有一个异步端点(长轮询)和其他几个用于 CRUD 操作的正常同步端点。

例如,异步服务如下所示:

@GET
@Path("poll/{groupId}")
@ManagedAsync
public void poll(@Suspended final AsyncResponse asyncResponse, @NotNull @PathParam("groupId") Integer groupId) {
    asyncResponse.setTimeout(SERVICE_TIMEOUT, TimeUnit.SECONDS);

    List<User> users= Collections.emptyList();

    while (users.isEmpty() && asyncResponse.isSuspended()) {
        users= userService.findUsersByGroupId(groupId);

        if (users.isEmpty()) {
            try {
                Thread.sleep(POLL_INTERVAL);
            } catch (InterruptedException ex) {}
        }
    }

    asyncResponse.resume(users.toArray(new TestView[0]));
}   

过去一切都工作得很好,异步请求是在 Jersey 管理的线程池上自己的线程中处理的。并且同步服务按预期工作。

但是有一天,我向团队提议添加一个文档工具,Swagger 是一个非常性感的工具,因此我们安装了一些文档,并添加了一些文档到我们的同步服务中。

噩梦开始后,我们的服务返回了疯狂的响应。有时它会将响应从一个服务发送到另一个服务,例如运行 get User 服务,我希望收到一个 User 对象,但收到了其他业务对象,如地址或任何其他随机对象,甚至有时我从 Tomcat 收到一条 html 错误消息或一个空响应。

查看我发现的日志:

SEVERE: Error while closing the output stream in order to commit response.
java.lang.NullPointerException
    at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
    at org.apache.coyote.http11.InternalOutputBuffer.endRequest(InternalOutputBuffer.java:159)
    at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:758)
    at org.apache.coyote.Response.action(Response.java:174)
    at org.apache.coyote.Response.finish(Response.java:291)
    at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:320)
    at org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:108)
    at org.glassfish.jersey.message.internal.CommittingOutputStream.close(CommittingOutputStream.java:277)
    at org.glassfish.jersey.message.internal.OutboundMessageContext.close(OutboundMessageContext.java:834)
    at org.glassfish.jersey.server.ContainerResponse.close(ContainerResponse.java:411)
    at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:691)
    at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:377)
    at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:367)
    at org.glassfish.jersey.server.ServerRuntime$AsyncResponder$3.run(ServerRuntime.java:828)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297)
    at org.glassfish.jersey.server.ServerRuntime$AsyncResponder.resume(ServerRuntime.java:858)
    at org.glassfish.jersey.server.ServerRuntime$AsyncResponder.resume(ServerRuntime.java:820)
    at com.compuware.ruxit.synthetic.api.resource.test.TestDispatcherResource.poll(TestDispatcherResource.java:111)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:136)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:387)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.access$100(ResourceMethodInvoker.java:103)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker$2.call(ResourceMethodInvoker.java:320)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker$2.call(ResourceMethodInvoker.java:317)
    at org.glassfish.jersey.server.ServerRuntime$AsyncResponder$2$1.run(ServerRuntime.java:791)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297)
    at org.glassfish.jersey.server.ServerRuntime$AsyncResponder$2.run(ServerRuntime.java:787)Nul
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

我最初认为这与使 Swagger 工作的新 servlet 定义有关:

<servlet>
    <servlet-name>SwaggerConfig</servlet-name>
    <servlet-class>com.compuware.ruxit.synthetic.api.configuration.SwaggerJaxrsConfig</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

我尝试添加 <async-supported>true</async-supported> SwaggerConfig servlet 和 Jersey servlet 定义(当您使用 ManagedAsync 注释时,这不是必需的,但我尝试了一下)。但这并没有帮助。

最佳答案

发现我正在使用的swagger maven依赖:

    <dependency>
        <groupId>com.wordnik</groupId>
        <artifactId>swagger-jersey2-jaxrs_2.10</artifactId>
        <version>1.3.5</version>
    </dependency>

依赖于 jersey-container-servlet-core,但对于比我的 Jersey 依赖项中已有的版本更旧的版本,它是 2.1,而我使用的是 2.10。然后 Maven 使用它并覆盖我的 Jersey 应用程序需要的那个。

我所做的只是排除传递依赖:

    <dependency>
        <groupId>com.wordnik</groupId>
        <artifactId>swagger-jersey2-jaxrs_2.10</artifactId>
        <version>1.3.5</version>
        <exclusions>
            <exclusion>
                <artifactId>jersey-container-servlet-core</artifactId>
                <groupId>org.glassfish.jersey.containers</groupId>
            </exclusion>
        </exclusions>
    </dependency>

更新后,到目前为止,该异常尚未再出现。

关于java - 使用 Swagger 文档的异步 Jersey REST API 中的 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24833533/

相关文章:

java - 自定义类队列数据结构的并发帮助

android - Android注解中Main Thread、Ui Thread、WorkerThread、Binder Thread的区别

java - 在一个循环中批量插入到不同的表

rest - Kafka Rest API KSQL 查询永远等待并挂起

json - 使用 REST API 通过电子邮件限制获取 WooCommerce 优惠券

javascript - 使用JavaScript进行代码依赖来选择RESTful

java - 尝试将 sql 数据库中的信息显示到 html 表中

java - 从套接字的 byte[] 开头解析 int

java - GeoTools,加载 map 时出错

java - 在android中使用kso​​ap2上传的空对象