Reactor - 在flatMap的输出上调用块会导致ClassCastException

时间:2017-12-27 15:00:01

标签: spring-data project-reactor

我正在使用Spring Boot 2.0.0.M7和Project Reactor。我的问题与编写单元测试时遇到的一些奇怪行为有关。在尝试将flatMap的输出提供给存储库时,我也遇到了这个问题。

Mono<Foo> create(Mono<FooResource> resourceMono) {
    resourceMono.flatMap({
        // convert resource into Foo domain Entity
        return new Foo()
    })
}

由于Mono<Foo>的返回值,此闭包应发出flatMap。但是,在致电block()订阅并获得结果Foo时,ClassCastException

中有FluxFlatMap.trySubscribeScalarMap

测试代码:

   def createdFoo = Foo.create(Mono.just(fooResource)).block() 

堆栈追踪:

java.lang.ClassCastException: com.example.Foo cannot be cast to org.reactivestreams.Publisher

at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:141)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:53)
at reactor.core.publisher.Mono.block(Mono.java:1161)

这似乎是因为MonoJust实现了Callable,所以trySubscribeScalarMap尝试解开它失败。

在非测试案例场景中,会发生类似的错误。

Mono<ServerResponse> createFoo(ServerRequest request) {
    def body = request.body(BodyExtractors.toMono(FooResource))
    ok().body(fromPublisher(Foo.create(body)
        .flatMap({fooRepository.save(it)}), Foo))
}

堆栈追踪:

java.lang.ClassCastException: com.example.Foo cannot be cast to reactor.core.publisher.Mono
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:118) [reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1092) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.MonoSingle$SingleSubscriber.onComplete(MonoSingle.java:171) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
<...>
Assembly trace from producer [reactor.core.publisher.MonoFlatMap] :
reactor.core.publisher.Mono.flatMap(Mono.java:2059)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrap.invoke(PojoMetaMethodSite.java:213)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
com.example.Foo.create(Foo.groovy:28)
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
com.example.FooHandlerFunctions.createFoo(FooHandlerFunctions.groovy:48)

flatMap闭包的输出包装在另一个Mono.just(foo)中解决了这两个问题。但是,似乎不应该这样做。我做错了什么或只是误解了flatMap在这里是如何运作的?

1 个答案:

答案 0 :(得分:1)

flatmap需要Function才能返回Mono(我认为groovy会让您返回错误的类型,因为Foo似乎无法实现Publisher?)