Skip to content

Commit

Permalink
Merge pull request #3348 from soft4rchitecture/RESTEASY-3259/fixes-er…
Browse files Browse the repository at this point in the history
…ror-when-mono-in-remote-interface

RESTEASY-3259 Proxy Framework fails to Produce Mono<T> at runtime whe…
  • Loading branch information
jamezp committed Dec 13, 2022
2 parents c03523f + 721094f commit ad0078e
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 35 deletions.
@@ -1,13 +1,12 @@
package org.jboss.resteasy.reactor;

import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.RxInvoker;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;

import org.jboss.resteasy.client.jaxrs.PublisherRxInvoker;
import reactor.core.publisher.Mono;

public interface MonoRxInvoker extends PublisherRxInvoker
public interface MonoRxInvoker extends RxInvoker<Mono<?>>
{
@Override
Mono<Response> get();
Expand Down
Expand Up @@ -3,146 +3,158 @@
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;

import org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;
import org.jboss.resteasy.client.jaxrs.internal.PublisherRxInvokerImpl;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;

import java.util.Objects;
import java.util.concurrent.CompletionStage;

public class MonoRxInvokerImpl extends PublisherRxInvokerImpl implements MonoRxInvoker {
public class MonoRxInvokerImpl implements MonoRxInvoker {

public MonoRxInvokerImpl(final ClientInvocationBuilder builder) {
super(builder);

private final MonoPublisherInvoker monoInvoker;


static class MonoPublisherInvoker extends PublisherRxInvokerImpl {
MonoPublisherInvoker(final ClientInvocationBuilder builder) {
super(builder);
}

@Override
protected <T> Publisher<T> toPublisher(CompletionStage<T> completable) {
return Mono.fromCompletionStage(completable);
}
}

@Override
protected <T> Mono<T> toPublisher(final CompletionStage<T> completable) {
return Mono.fromCompletionStage(completable);
public MonoRxInvokerImpl(final ClientInvocationBuilder builder) {
monoInvoker = new MonoPublisherInvoker(Objects.requireNonNull(builder));
}


@Override
public Mono<Response> get() {
return Mono.from(super.get());
return Mono.from(monoInvoker.get());
}

@Override
public <T> Mono<T> get(Class<T> responseType) {
return Mono.from(super.get(responseType));
return Mono.from(monoInvoker.get(responseType));
}

@Override
public <T> Mono<T> get(GenericType<T> responseType) {
return Mono.from(super.get(responseType));
return Mono.from(monoInvoker.get(responseType));
}

@Override
public Mono<Response> put(Entity<?> entity) {
return Mono.from(super.put(entity));
return Mono.from(monoInvoker.put(entity));
}

@Override
public <T> Mono<T> put(Entity<?> entity, Class<T> clazz) {
return Mono.from(super.put(entity, clazz));
return Mono.from(monoInvoker.put(entity, clazz));
}

@Override
public <T> Mono<T> put(Entity<?> entity, GenericType<T> type) {
return Mono.from(super.put(entity, type));
return Mono.from(monoInvoker.put(entity, type));
}

@Override
public Mono<Response> post(Entity<?> entity) {
return Mono.from(super.post(entity));
return Mono.from(monoInvoker.post(entity));
}

@Override
public <T> Mono<T> post(Entity<?> entity, Class<T> clazz) {
return Mono.from(super.post(entity, clazz));
return Mono.from(monoInvoker.post(entity, clazz));
}

@Override
public <T> Mono<T> post(Entity<?> entity, GenericType<T> type) {
return Mono.from(super.post(entity, type));
return Mono.from(monoInvoker.post(entity, type));
}

@Override
public Mono<Response> delete() {
return Mono.from(super.delete());
return Mono.from(monoInvoker.delete());
}

@Override
public <T> Mono<T> delete(Class<T> responseType) {
return Mono.from(super.delete(responseType));
return Mono.from(monoInvoker.delete(responseType));
}

@Override
public <T> Mono<T> delete(GenericType<T> responseType) {
return Mono.from(super.delete(responseType));
return Mono.from(monoInvoker.delete(responseType));
}

@Override
public Mono<Response> head() {
return Mono.from(super.head());
return Mono.from(monoInvoker.head());
}

@Override
public Mono<Response> options() {
return Mono.from(super.options());
return Mono.from(monoInvoker.options());
}

@Override
public <T> Mono<T> options(Class<T> responseType) {
return Mono.from(super.options(responseType));
return Mono.from(monoInvoker.options(responseType));
}

@Override
public <T> Mono<T> options(GenericType<T> responseType) {
return Mono.from(super.options(responseType));
return Mono.from(monoInvoker.options(responseType));
}

@Override
public Mono<Response> trace() {
return Mono.from(super.trace());
return Mono.from(monoInvoker.trace());
}

@Override
public <T> Mono<T> trace(Class<T> responseType) {
return Mono.from(super.trace(responseType));
return Mono.from(monoInvoker.trace(responseType));
}

@Override
public <T> Mono<T> trace(GenericType<T> responseType) {
return Mono.from(super.trace(responseType));
return Mono.from(monoInvoker.trace(responseType));
}

@Override
public Mono<Response> method(String name) {
return Mono.from(super.method(name));
return Mono.from(monoInvoker.method(name));
}

@Override
public <T> Mono<T> method(String name, Class<T> responseType) {
return Mono.from(super.method(name, responseType));
return Mono.from(monoInvoker.method(name, responseType));
}

@Override
public <T> Mono<T> method(String name, GenericType<T> responseType) {
return Mono.from(super.method(name, responseType));
return Mono.from(monoInvoker.method(name, responseType));
}

@Override
public Mono<Response> method(String name, Entity<?> entity) {
return Mono.from(super.method(name, entity));
return Mono.from(monoInvoker.method(name, entity));
}

@Override
public <T> Mono<T> method(String name, Entity<?> entity, Class<T> responseType) {
return Mono.from(super.method(name, entity, responseType));
return Mono.from(monoInvoker.method(name, entity, responseType));
}

@Override
public <T> Mono<T> method(String name, Entity<?> entity, GenericType<T> responseType) {
return Mono.from(super.method(name, entity, responseType));
return Mono.from(monoInvoker.method(name, entity, responseType));
}
}
@@ -0,0 +1,18 @@
package org.jboss.resteasy.reactor.proxyframework;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import reactor.core.publisher.Mono;


@Path("api/v1")
public class CustomResource {

public static final String THE_CUSTOM_RESOURCE = "the custom resource";

@GET
@Path("resource/custom")
public Mono<String> getCustomResource() {
return Mono.just(THE_CUSTOM_RESOURCE);
}
}
@@ -0,0 +1,92 @@
package org.jboss.resteasy.reactor.proxyframework;

import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.DefaultEventExecutor;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.client.ClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.engines.ReactorNettyClientHttpEngine;
import org.jboss.resteasy.plugins.server.netty.NettyJaxrsServer;
import org.jboss.resteasy.test.TestPortProvider;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import static org.jboss.resteasy.reactor.proxyframework.CustomResource.THE_CUSTOM_RESOURCE;
import static org.junit.Assert.assertEquals;

public class MonoWithProxyFrameworkApiTest {


private static int port;

@Path("api/v1")
public interface RemoteCustomResource {

@GET
@Path("resource/custom")
Mono<String> getCustomResource();
}


private static NettyJaxrsServer server;

@BeforeClass
public static void beforeClass() {
port = TestPortProvider.getPort();
server = new NettyJaxrsServer();
server.setPort(port);
server.setRootResourcePath("/");
Arrays.asList((Class<?>[]) new Class[]{CustomResource.class}).forEach(server.getDeployment().getActualResourceClasses()::add);
server.getDeployment().start();
server.getDeployment().registration();
server.start();
}

@AfterClass
public static void afterClass() {
server.stop();
server = null;
}

private ResteasyClient client;

@Before
public void before() {
final ReactorNettyClientHttpEngine reactorEngine =
new ReactorNettyClientHttpEngine(
HttpClient.create(),
new DefaultChannelGroup(new DefaultEventExecutor()),
ConnectionProvider.newConnection()
);
client = ((ResteasyClientBuilder) ClientBuilder.newBuilder())
.httpEngine(reactorEngine)
.readTimeout(5, TimeUnit.SECONDS)
.connectionCheckoutTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.build();
}

@After
public void after() {
client.close();
}


@Test
public void givenRemoteServiceInterfaceAndWorkingRemoteServiceWhenProxyThenGenerateProxyWithMono() {
final var proxy = client.target("http://localhost:" + port).proxy(RemoteCustomResource.class);
assertEquals(THE_CUSTOM_RESOURCE, proxy.getCustomResource().block());

}
}

0 comments on commit ad0078e

Please sign in to comment.