Skip to content

Commit

Permalink
Merge pull request #39102 from geoand/#19849
Browse files Browse the repository at this point in the history
Properly pass annotations to MessageBodyReader in REST Client
  • Loading branch information
geoand committed Mar 5, 2024
2 parents 2ee08d3 + bd77018 commit 90762d5
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -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<Person> {

@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return type.equals(Person.class);
}

@Override
public Person readFrom(Class<Person> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> 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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,15 +318,23 @@ 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);
}
start = end + separator.length;
}
} 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);
}
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -190,12 +198,14 @@ protected Throwable unwrapException(Throwable t) {

@SuppressWarnings("unchecked")
public <T> T readEntity(InputStream in,
GenericType<T> responseType, MediaType mediaType,
GenericType<T> responseType,
MediaType mediaType,
Annotation[] annotations,
MultivaluedMap<String, Object> 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);
}
Expand Down

0 comments on commit 90762d5

Please sign in to comment.