Retrofit-Vertx在Kotlin中使用RxJava2 IllegalStateException消息== null

我用Vertex和RxJava 2(RxKotlin)在Kotlin上构建了一个非常简单的应用程序,使用Kovert REST框架和Retrofit。 我有retrofit-vertx适配器和RxJava2 Retrofit适配器。 我可以从我的listUndergroundStations()方法返回一个任意列表,但每当我尝试从远程API加载时,我得到以下错误:

 Jun 23, 2017 2:16:29 PM uk.amb85.rxweb.api.UndergroundRestController SEVERE: HTTP CODE 500 - /api/underground/stations - java.io.IOException: java.lang.IllegalStateException: message == null java.lang.RuntimeException: java.io.IOException: java.lang.IllegalStateException: message == null at io.reactivex.internal.util.ExceptionHelper.wrapOrThrow(ExceptionHelper.java:45) at io.reactivex.internal.observers.BlockingMultiObserver.blockingGet(BlockingMultiObserver.java:91) at io.reactivex.Single.blockingGet(Single.java:2148) at uk.amb85.rxweb.api.UndergroundRestController$listUndergroundStations$1.invoke(UndergroundRestController.kt:35) at uk.amb85.rxweb.api.UndergroundRestController$listUndergroundStations$1.invoke(UndergroundRestController.kt:13) at nl.komponents.kovenant.TaskPromise$wrapper$1.invoke(promises-jvm.kt:138) at nl.komponents.kovenant.TaskPromise$wrapper$1.invoke(promises-jvm.kt:130) at nl.komponents.kovenant.NonBlockingDispatcher$ThreadContext.run(dispatcher-jvm.kt:327) at java.lang.Thread.run(Thread.java:748) Caused by: java.io.IOException: java.lang.IllegalStateException: message == null at com.julienviet.retrofit.vertx.VertxCallFactory$VertxCall.lambda$enqueue$0(VertxCallFactory.java:90) at io.vertx.core.impl.FutureImpl.tryFail(FutureImpl.java:170) at io.vertx.core.http.impl.HttpClientResponseImpl.handleException(HttpClientResponseImpl.java:270) at io.vertx.core.http.impl.HttpClientResponseImpl.handleEnd(HttpClientResponseImpl.java:259) at io.vertx.core.http.impl.ClientConnection.handleResponseEnd(ClientConnection.java:361) at io.vertx.core.http.impl.ClientHandler.doMessageReceived(ClientHandler.java:80) at io.vertx.core.http.impl.ClientHandler.doMessageReceived(ClientHandler.java:38) at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$0(VertxHttpHandler.java:71) at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:335) at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:193) at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:71) at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341) at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267) at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341) at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1228) at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1039) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) ... 1 more Caused by: java.lang.IllegalStateException: message == null at okhttp3.Response$Builder.build(Response.java:431) at com.julienviet.retrofit.vertx.VertxCallFactory$VertxCall.lambda$null$1(VertxCallFactory.java:109) at io.vertx.core.http.impl.HttpClientResponseImpl$BodyHandler.notifyHandler(HttpClientResponseImpl.java:301) at io.vertx.core.http.impl.HttpClientResponseImpl.lambda$bodyHandler$0(HttpClientResponseImpl.java:193) at io.vertx.core.http.impl.HttpClientResponseImpl.handleEnd(HttpClientResponseImpl.java:257) ... 36 more 

我不能为我的生活找出是什么导致了IllegalStateException并已经把它死了。 我不认为它是Rx相关的,因为如果我使方法返回Observable<List<UndergroundLine>> ,甚至完全摆脱Rx,并返回Call<List<UndergroundLine>> (调整控制器相应),则得到相同的错误。 但是,除此之外,我正在撞墙! 有人能够指出我的方式的错误(除了在我的头下垫)?

主垂直:

 class ApiVerticle : AbstractVerticle() { override fun start(startFuture: Future<Void>?) { // Initialise injection. configureKodein() val apiRouter = configureRouter(vertx) vertx.createHttpServer() .requestHandler { apiRouter.accept(it) } .listen(8080) } private fun configureKodein() { Kodein.global.addImport(Kodein.Module { import(TflUndergroundService.module) }) } private fun configureRouter(vertx: Vertx): Router { val apiMountPoint = "api" val routerInit = fun Router.() { bindController(UndergroundRestController(), apiMountPoint) } val router = Router.router(vertx) initializedBy { router -> router.routerInit() } return router } } 

TflService:

 interface TflService { @GET("/Line/Mode/tube") fun getAllUndergroundLines(): Observable<UndergroundLine> @GET("/Line/{lineName}/StopPoints") fun getStationsForUndergroundLine( @Path("lineName") lineName: String ): Observable<UndergroundStation> @GET("/Line/{lineName}/Arrivals?stopPointId={stationNaptanId") fun getArrivalsFor( @Path("lineName") lineName: String, @Path("stationNaptanId") stationNaptanId: String ) : Observable<Arrival> } data class UndergroundLine(val id: String, val name: String) data class UndergroundStation(val naptanId: String, val commonName: String) data class Arrival( val platformName: String, val towards: String, val currentLocation: String, val expectedArrival: LocalDateTime) object TflUndergroundService { val module = Kodein.Module { val vertx: Vertx = Vertx.currentContext().owner() val client: HttpClient = vertx.createHttpClient() val jacksonMapper: ObjectMapper = ObjectMapper() jacksonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) val retrofit: Retrofit = Retrofit.Builder() .baseUrl("https://api.tfl.gov.uk/") .callFactory(VertxCallFactory(client)) .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) .addConverterFactory(JacksonConverterFactory.create(jacksonMapper)) .build() val tflService: TflService = retrofit.create(TflService::class.java) bind<TflService>() with instance(tflService) } } 

ApiKeySecured(只需要“appid”作为参数):

 class ApiKeySecured(private val routingContext: RoutingContext) : KodeinGlobalAware { val user: String = routingContext.request().getParam("appid") ?: throw HttpErrorUnauthorized() } 

有问题的REST控制器(在Kovert中, Promise的是在Vertx工作线程上执行的):

 class UndergroundRestController(val undergroundService: TflService = Kodein.global.instance()) { fun ApiKeySecured.listUndergroundStations(): Promise<List<UndergroundLine>, Exception> { //TODO: This is blocking, fix it!?? return task { undergroundService .getAllUndergroundLines() .doOnError { println(it) } .toList() .blockingGet() } } } 

的build.gradle:

 mainClassName = "io.vertx.core.Launcher" def mainVerticleName = "uk.amb85.rxweb.verticles.ApiVerticle" def configurationFile = "conf/development.json" run { args = ["run", mainVerticleName, "--launcher-class=$mainClassName", "-conf $configurationFile" ] } 

你正在使用的retrofit-vertx有一个问题。 OkHttp3ResponseBuilder要求message不为null,但是VertxCallFactory不会设置它。

它在最新版本中已经修复,但由于它仍在开发中,所以您必须使用快照:

 repositories { mavenCentral() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } dependencies { compile 'com.julienviet:retrofit-vertx:1.0.2-SNAPSHOT' } 

切换到快照依赖关系可以解决您在问题中提到的问题,但是json映射存在一个问题,可以通过切换代码轻松修复这个问题:

 @GET("/Line/Mode/tube") fun getAllUndergroundLines(): Observable<UndergroundLine> 

至:

 @GET("/Line/Mode/tube") fun getAllUndergroundLines(): Observable<List<UndergroundLine>> 

并更新你的数据类有默认的空构造函数让Jackson实例化使用反射:

 data class UndergroundLine(var id: String = "", var name: String = "") 

更多关于数据类的默认构造函数 。

但是另外一个问题涉及到如何解析来自您使用Observable API的响应,并且应该询问您是否找不到解决方法。