3
votes

I just created a simple Spring Boot application using spring-boot-starter-webflux with version 2.0.0.BUILD-SNAPSHOT which brings spring-webflux version 5.0.0.BUILD-SNAPSHOT and same for Spring Core, Beans, Context, etc.

If I create a simple @RestController and provide a @GetMapping that simply returns a Flux<String>, then everything works as expected.

However, if I change from Flux to RxJava's Observable, I get this error:

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

Debugging a bit through the code I found that Jackson's ObjectMapper somehow registers Flux, Mono and the rest of reactive types in its typeFactory, so later the MappingJackson2HttpMessageConverter knows how to (de)-serialize them.

However, it's not the case when I use an Observable: I don't find the type Observable or Single registered in the ObjectMapper's type factory, so I get the aforementioned error.

Has anyone experienced this issue? Am I missing any dependency? Do I need to manually tell Jackson how to (de)-serialize from RxJava constructs? But why does Jackson already know about Flux and Mono?

Thanks for your help.

EDITED:

I'm using RxJava 1.2.7. Here is my pom.xml:

<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
        <version>2.0.0.BUILD-SNAPSHOT</version>
    </dependency>
    <!-- RxJava dependeencies -->
    <dependency>
        <groupId>io.reactivex</groupId>
        <artifactId>rxjava</artifactId>
        <version>1.2.7</version>
    </dependency>
</dependencies>

And here is the example of my controller code:

/**
 * Get all the available tasks.
 *
 * @return the list of tasks
 */
@GetMapping(path = "/task")
@ResponseStatus(HttpStatus.OK)
public Observable<TaskView> allTasks(@AuthenticationPrincipal LoggedUserVO principal) {
    return this.pocComponent.getAllTasks()
            .map(t -> ViewConverter.convertFromTaskDocument(t, principal));
}
2
Can you post your pom/gradle file? Which RxJava version are you using? Please also add some code like your controller. - M. Deinum
I would remove the version as spring Boot already manages that, you would also need the reactive-streams extension for rxjava to make it integration with Reactive.io as the Reactive Streams are the integration point for the different reactive implementations. - M. Deinum
If I remove the version for RxJava I get 1.1.8. The reactive-streams dependency (version 1.0.0) is transitively obtained through the dependency spring-boot-starter-webflux. In any case, still not working. - Enrique Medina
That is weird because when I look at the managed dependency that is 1.2.7... Is everything you use from Spring Boot 2.0.0??? Or have you just included this dependency into an existing older spring boot version? Or in short, can you add your full pom? You need the rxjava-reactive-streams dependency... - M. Deinum

2 Answers

3
votes

You are probably missing the following dependency to make it works:

<dependency>
    <groupId>io.reactivex</groupId>
    <artifactId>rxjava-reactive-streams</artifactId>
    <version>1.2.1</version>
</dependency>

Changes in various RxJava 1.x versions made it challenging for us to support it out of the box, that's why we prefer to rely on the official RxJava -> Reactive Streams adapter. Notice that RxJava 2.x is supported without requiring additional dependencies (it is natively built on top of Reactive Streams).

I am going to update Spring WebFlux reference documentation to specify this is required to have RxJava 1.x support.

-7
votes

So, Flux and Mono are Spring names, as Spring has the Not-Invented-Here syndrome.

You can either register a handler that does the conversion to types that Spring knows about, use the AsyncResponse facility that Jersey provides, or add toBlocking everywhere.