From bd77018404ed7151c9b58fa88fa1dbb5d014630e Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 1 Mar 2024 11:44:27 +0200 Subject: [PATCH] Properly pass annotations to MessageBodyReader in REST Client Fixes: #19849 --- ...mMessageBodyReaderUsesAnnotationsTest.java | 114 ++++++++++++++++++ .../ClientResponseCompleteRestHandler.java | 2 + .../reactive/client/impl/MultiInvoker.java | 17 ++- .../client/impl/RestClientRequestContext.java | 14 ++- 4 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomMessageBodyReaderUsesAnnotationsTest.java diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomMessageBodyReaderUsesAnnotationsTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomMessageBodyReaderUsesAnnotationsTest.java new file mode 100644 index 0000000000000..eab0b5aced44b --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomMessageBodyReaderUsesAnnotationsTest.java @@ -0,0 +1,114 @@ +package io.quarkus.rest.client.reactive; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Type; +import java.net.URI; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; + +public class CustomMessageBodyReaderUsesAnnotationsTest { + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest(); + + @TestHTTPResource + URI baseUri; + + private Client client; + + @BeforeEach + public void before() { + client = QuarkusRestClientBuilder.newBuilder() + .baseUri(baseUri) + .register(PersonMessageBodyReader.class) + .build(Client.class); + } + + @Test + public void fromAnnotation() { + Person person = client.fromAnnotation(); + assertEquals("from-annotation", person.name()); + } + + @Test + public void unset() { + Person person = client.unset(); + assertEquals("unset", person.name()); + } + + @Path("test") + public interface Client { + + @GET + @PersonName("from-annotation") + Person fromAnnotation(); + + @GET + Person unset(); + } + + @Path("test") + public static class Endpoint { + + @GET + public Person get() { + return new Person("dummy"); + } + } + + public record Person(String name) { + + } + + @Documented + @Target({ ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + public @interface PersonName { + String value(); + } + + public static class PersonMessageBodyReader implements MessageBodyReader { + + @Override + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.equals(Person.class); + } + + @Override + public Person readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, InputStream entityStream) { + PersonName personName = null; + if (annotations != null) { + for (Annotation annotation : annotations) { + if (annotation instanceof PersonName pn) { + personName = pn; + break; + } + } + } + if (personName == null) { + return new Person("unset"); + } + return new Person(personName.value()); + } + } +} diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseCompleteRestHandler.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseCompleteRestHandler.java index 873bb8fd62d19..36d165192f98b 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseCompleteRestHandler.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseCompleteRestHandler.java @@ -76,6 +76,7 @@ public static ResponseImpl mapToResponse(RestClientRequestContext context, Object fieldValue = context.readEntity(in, fieldFiller.getFieldType(), MediaType.valueOf(fieldFiller.getMediaType()), + context.getMethodDeclaredAnnotationsSafe(), // FIXME: we have strings, it wants objects, perhaps there's // an Object->String conversion too many (MultivaluedMap) responseContext.getHeaders()); @@ -104,6 +105,7 @@ public static ResponseImpl mapToResponse(RestClientRequestContext context, Object entity = context.readEntity(entityStream, context.getResponseType(), responseContext.getMediaType(), + context.getMethodDeclaredAnnotationsSafe(), // FIXME: we have strings, it wants objects, perhaps there's // an Object->String conversion too many (MultivaluedMap) responseContext.getHeaders()); diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java index 4459e66000227..235a3937d0605 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/MultiInvoker.java @@ -318,7 +318,11 @@ public void handle(Buffer buffer) { if (start < end) { ByteArrayInputStream in = new ByteArrayInputStream(bytes, start, end); - R item = restClientRequestContext.readEntity(in, responseType, mediaType, + R item = restClientRequestContext.readEntity( + in, + responseType, + mediaType, + restClientRequestContext.getMethodDeclaredAnnotationsSafe(), response.getMetadata()); multiRequest.emitter.emit(item); } @@ -326,7 +330,11 @@ public void handle(Buffer buffer) { } } else { ByteArrayInputStream in = new ByteArrayInputStream(bytes); - R item = restClientRequestContext.readEntity(in, responseType, mediaType, + R item = restClientRequestContext.readEntity( + in, + responseType, + mediaType, + restClientRequestContext.getMethodDeclaredAnnotationsSafe(), response.getMetadata()); multiRequest.emitter.emit(item); } @@ -360,7 +368,10 @@ public void handle(Buffer chunk) { ByteArrayInputStream in = new ByteArrayInputStream(chunk.getBytes()); try { - R item = restClientRequestContext.readEntity(in, responseType, response.getMediaType(), + R item = restClientRequestContext.readEntity(in, + responseType, + response.getMediaType(), + restClientRequestContext.getMethodDeclaredAnnotationsSafe(), response.getMetadata()); multiRequest.emit(item); } catch (IOException e) { diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java index a2f7e9fba9102..dca9e4fe33bf7 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java @@ -167,6 +167,14 @@ public Method getInvokedMethod() { return null; } + public Annotation[] getMethodDeclaredAnnotationsSafe() { + Method invokedMethod = getInvokedMethod(); + if (invokedMethod != null) { + return invokedMethod.getDeclaredAnnotations(); + } + return null; + } + @Override protected Throwable unwrapException(Throwable t) { var res = super.unwrapException(t); @@ -190,12 +198,14 @@ protected Throwable unwrapException(Throwable t) { @SuppressWarnings("unchecked") public T readEntity(InputStream in, - GenericType responseType, MediaType mediaType, + GenericType responseType, + MediaType mediaType, + Annotation[] annotations, MultivaluedMap metadata) throws IOException { if (in == null) return null; - return (T) ClientSerialisers.invokeClientReader(null, responseType.getRawType(), responseType.getType(), + return (T) ClientSerialisers.invokeClientReader(annotations, responseType.getRawType(), responseType.getType(), mediaType, properties, this, metadata, restClient.getClientContext().getSerialisers(), in, getReaderInterceptors(), configuration); }