Problem description

For historical reason in our project we have services like:

interface Service<I, O> {
    String name();
    Mono<O> execute(I input);
}

And when we started using reactive Spring transactions, we couldn't always avoid applying @Transactional on a interface/class level, so we needed a solution that tolerates such mix of reactive and non-reactive public methods in classes with @Transactional annotation.

Registering reactive type adapters in shared instance of ReactiveAdapterRegistry looked as a standard way to go, so we used it, and it worked well for a while. But now we are trying to start using Spring Data JPA framework in our project, and having reactive adapters for non-reactive types in the shared repository causes issues in the framework, because it makes an assumption that every reactive type is a type with a type parameter, and fails to figure out the type parameters of non-reactive types with reactive adapters. For instance, if we have an adapter for String, when Spring Data will try to create a repository with a method like this:

public Collection<String> findSometing(...);

it will fail with Can't resolve required component type for java.lang.String.

So this PR addresses the problem described above by providing a mechanism that allows to customize reactive type adapters only for Reactive Spring Transactions without affecting the shared ReactiveAdapterRegistry.

Comment From: rstoyanchev

Registering reactive type adapters in shared instance of ReactiveAdapterRegistry looked as a standard way to go

Registering a ReactiveAdapter for non-reactive types is not the intended way of using the registry, so that's not a standard way to go. I think we should take a step back and consider how to address the original problem.

Could you elaborate on the original issue with a l little more detail on what you did and how that helped to solve the problem?

Comment From: snicoll

@prishedko I am going to close this now as we're not going to go forward with this approach. If you want to share the details Rossen requested, feel free to do so and we'll figure out what to do next based on that.

Comment From: prishedko

@rstoyanchev thank you very much for your reply and sorry for so long delay with the response.

Could you elaborate on the original issue with a l little more detail on what you did and how that helped to solve the problem?

We have a set of APIs where some interfaces have methods that return reactive types and methods that return non-reactive types. When we started using Spring reactive transactions, we figure out that we cannot annotate such interfaces or their implementations as @Transactional, because of the methods that return non-reactive types. The correct way was just refactor reactive methods, but we couldn't do that due to huge splash effect on projects that use the API and our obligation to provide backward compatible changes. So as a workaround we created an adapter like class NonReactiveTypeAdapter<T> implements Publisher<T>, Subscription {...} and registered it by:

         ReactiveAdapterRegistry.getSharedInstance()
                .registerReactiveType(ReactiveTypeDescriptor.nonDeferredAsyncValue(Object.class, () -> null),
                        NonReactiveTypeAdapter::new, pub -> Flowable.fromPublisher(pub)
                                .blockingFirst());

It provided ability to annotate classes with a mix of both reactive and non-reactive methods as @Transactional, but when we started using Spring Data, the approach started breaking Spring Data data type analyzing process, because it makes totally reasonable assumption that reactive types are containers, but with the workaround it gets non-reactive types as String as reactive and it cannot figure out type of their parameters.