Java 从播放2.4转换到播放2.5时异步操作中的NullPointerException
我正在将Play2.4项目移植到Play2.5(.18)。我遇到了一个虚假的Java 从播放2.4转换到播放2.5时异步操作中的NullPointerException,java,playframework,nullpointerexception,playframework-2.5,Java,Playframework,Nullpointerexception,Playframework 2.5,我正在将Play2.4项目移植到Play2.5(.18)。我遇到了一个虚假的NullPointerException我找不到原因。这是堆栈跟踪: ! @76g5ina3j - Internal server error, for (POST) [/.../tokens] -> play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[CompletionException: java.lang.NullP
NullPointerException
我找不到原因。这是堆栈跟踪:
! @76g5ina3j - Internal server error, for (POST) [/.../tokens] ->
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[CompletionException: java.lang.NullPointerException]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
Caused by: java.util.concurrent.CompletionException: java.lang.NullPointerException
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:604)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:443)
Caused by: java.lang.NullPointerException: null
at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:350)
at akka.stream.scaladsl.Source.runWith(Source.scala:81)
at akka.stream.javadsl.Source.runWith(Source.scala:528)
at akka.stream.javadsl.Source.runFold(Source.scala:539)
at play.http.HttpEntity.consumeData(HttpEntity.java:58)
正如您所看到的,堆栈跟踪没有任何对程序中代码行的引用,只提到了框架。我已经尽了最大的努力。播放操作是使用CompletableFuture
和supplyAsync
以及几个thenApply()
阶段异步实现的。助手类最终通过调用
return Controller.status(some_resultcode);
最终的NPE原因始于HttpEntity.consumerdata()
,并在游戏的Scala部分和Akka框架中深入结束。该RunnableGraph.run()方法读取
def run()(implicit materializer: Materializer): Mat = materializer.materialize(this)
虽然这肯定比我的Scala知识多出了好几个数量级,但我的结论是这里唯一的null
东西可能是神秘的materializer
,不管它是什么。它来自哪里?它有什么好处?它怎么可能是空的
我试图用一种非常简单的方法重现这个问题:
public CompletionStage<Result> version() {
return CompletableFuture
.supplyAsync(()->"2")
.thenApplyAsync(version->ok("Server v"+version));
}
public CompletionStage版本(){
返回可完成的未来
.supplyAsync(()->“2”)
.ThenApplySync(版本->确定(“服务器v”+版本));
}
不幸的是,这个操作没有问题,所以到目前为止,我还没有一个关于这个问题的简化的测试
我现在有点迷路了。有人能给我解释一下发生了什么以及如何解决这个问题吗?好的,找到了这个。经过更深入的调查,情况有所不同。事实上,行动本身并不是问题所在。控制器如下所示:
@With(OurLogger.class)
public class OurController extends Controller {
public CompletionStage<Result> ourAction() {
return CompletableFuture.supplyAsync(()->...);
}
}
问题是调用了JavaResultTextRactor.getBody()
。在Play 2.4中,它只获得两个参数。剧本2.5增加了第三个——这个神秘的物化器
,据我所知,它编纂了一些阿克卡管道的概念。在Play 2.5中使代码可编译时,一位同事刚刚添加了null
作为第三个参数,而正是null
是框架内部的Akka代码后来偶然发现的
解决方案位于的答案部分,并导致对OurLogger
进行以下更改:
public class OurLogger extends Action.Simple {
@Inject Materializer materializer;
private Result logResult(Result result) {
System.err.println("Result body: "+
JavaResultExtractor.getBody(result,1,materializer).utf8String());
}
// call() method unchanged
}
如果(a)Play migration docs提到了这个Materializer
东西和/或(b)错误堆栈跟踪中只出现了这个getBody()
调用的一点点提示,我会更快地发现问题。这是大海捞针搜索的两天…在play framework google group中,你可能会更幸运:
public class OurLogger extends Action.Simple {
@Inject Materializer materializer;
private Result logResult(Result result) {
System.err.println("Result body: "+
JavaResultExtractor.getBody(result,1,materializer).utf8String());
}
// call() method unchanged
}