Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure that MessageBodyWriter is passed the proper media type #41411

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import jakarta.ws.rs.ext.MessageBodyWriter;

import org.jboss.resteasy.reactive.common.util.MediaTypeHelper;
import org.jboss.resteasy.reactive.common.util.ServerMediaType;
import org.jboss.resteasy.reactive.server.core.EncodedMediaType;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.core.ServerSerialisers;
Expand Down Expand Up @@ -41,22 +42,27 @@ public void write(ResteasyReactiveRequestContext context, Object entity) throws
ServerHttpRequest vertxRequest = context.serverRequest();
// first check and see if the resource method defined a media type and try to use it
if ((context.getTarget() != null) && (context.getTarget().getProduces() != null)) {
ServerMediaType producesServerMediaType = context.getTarget().getProduces();
MediaType negotiatedMediaType = null;
List<String> accepts = context.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT);
for (String accept : accepts) {
negotiatedMediaType = context.getTarget().getProduces().negotiateProduces(accept).getKey();
negotiatedMediaType = producesServerMediaType.negotiateProduces(accept).getKey();
if (negotiatedMediaType != null) {
break;
}
}
if (negotiatedMediaType == null) { // fallback to ensure that MessageBodyWriter is passed the proper media type
negotiatedMediaType = producesServerMediaType
gastaldi marked this conversation as resolved.
Show resolved Hide resolved
.negotiateProduces(vertxRequest.getRequestHeader(HttpHeaders.ACCEPT)).getKey();
}

List<MessageBodyWriter<?>> writersList = serialisers.findWriters(null, entity.getClass(), negotiatedMediaType,
RuntimeType.SERVER);
if (!writersList.isEmpty()) {
writers = writersList.toArray(EMPTY_ARRAY);
// use the actual type the method declares as this is what the spec expects despite the fact that we might
// have used the suffix of the subtype to determine a MessageBodyWriter
MediaType[] sortedOriginalMediaTypes = context.getTarget().getProduces().getSortedOriginalMediaTypes();
MediaType[] sortedOriginalMediaTypes = producesServerMediaType.getSortedOriginalMediaTypes();
for (MediaType methodMediaType : sortedOriginalMediaTypes) {
if (methodMediaType.isCompatible(negotiatedMediaType)) {
selectedMediaType = methodMediaType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti
break;
}
}
if (res == null) { // fallback for some tests
if (res == null) { // fallback to ensure that MessageBodyWriter is passed the proper media type
res = mediaTypeList.negotiateProduces(requestContext.serverRequest().getRequestHeader(HttpHeaders.ACCEPT))
.getKey();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.jboss.resteasy.reactive.server.vertx.test.matching;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.function.Supplier;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.MessageBodyWriter;
import jakarta.ws.rs.ext.Provider;

import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.restassured.http.Header;

public class StringMessageBodyWriterTest {

@RegisterExtension
static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest()
.setArchiveProducer(new Supplier<>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class);
}
});

@Test
void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Greeting response: Hello from Quarkus REST"));
}

@Test
void testWithNoAcceptHeader() {
// Prevent RestAssured from setting any Accept header
final var header = new Header("Accept", null);

given()
.when()
.header(header)
.get("/hello")
.then()
.statusCode(200)
.body(is("Greeting response: Hello from Quarkus REST"));
}

@Path("/hello")
public static class GreetingResource {

@GET
@Produces(MediaType.TEXT_PLAIN)
public Response hello() {
return Response.ok("Hello from Quarkus REST").build();
}
}

@Provider
public static class GreetingMessageBodyWriter implements MessageBodyWriter<String> {

@Override
public boolean isWriteable(final Class<?> aClass, final Type type, final Annotation[] annotations,
final MediaType mediaType) {
return String.class.isAssignableFrom(aClass) && MediaType.TEXT_PLAIN_TYPE.isCompatible(mediaType);
}

@Override
public void writeTo(final String s, final Class<?> aClass, final Type type, final Annotation[] annotations,
final MediaType mediaType,
final MultivaluedMap<String, Object> multivaluedMap, final OutputStream outputStream)
throws IOException, WebApplicationException {

final var content = "Greeting response: " + s;
outputStream.write(content.getBytes());
}
}
}
Loading