From 47d782f31e222abe19061cf290a9cf2120b502b3 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 11 Apr 2024 18:42:50 +0300 Subject: [PATCH 1/2] Fix broken pre-match test --- ...nHeader.java => PreMatchAcceptInHeaderTest.java} | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) rename independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/{PreMatchAcceptInHeader.java => PreMatchAcceptInHeaderTest.java} (90%) diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java similarity index 90% rename from independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java rename to independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java index cfbd44a4795fc..eee195df3ce55 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java @@ -23,15 +23,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -public class PreMatchAcceptInHeader { +public class PreMatchAcceptInHeaderTest { @RegisterExtension static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() .setArchiveProducer(new Supplier<>() { @Override public JavaArchive get() { - return ShrinkWrap.create(JavaArchive.class) - .addClass(PathSegmentTest.Resource.class); + return ShrinkWrap.create(JavaArchive.class); } }); @@ -52,7 +51,7 @@ void text() { .get("test") .then() .statusCode(200) - .body(equalTo("test")); + .body(equalTo("text")); } @Test @@ -62,7 +61,7 @@ void html() { .get("test") .then() .statusCode(200) - .body(equalTo("test")); + .body(containsString("")); } @Test @@ -71,7 +70,7 @@ void json() { .when() .get("test") .then() - .statusCode(404); + .statusCode(406); } @Test @@ -82,7 +81,7 @@ void setAcceptToTextInFilter() { .get("test") .then() .statusCode(200) - .body(equalTo("test")); + .body(equalTo("text")); } @Path("/test") From 4f86368e4f00984558956fdd5ddac9a240c8c78c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 11 Apr 2024 18:50:49 +0300 Subject: [PATCH 2/2] Take MediaType set in pre-match filter into account during serialization Fixes: #40019 --- .../handlers/VariableProducesHandler.java | 14 ++- .../matching/PreMatchAcceptInHeaderTest.java | 107 ++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/VariableProducesHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/VariableProducesHandler.java index 6c1e712350e67..77faad733c928 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/VariableProducesHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/VariableProducesHandler.java @@ -44,8 +44,18 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti //TODO? return; } - MediaType res = mediaTypeList.negotiateProduces(requestContext.serverRequest().getRequestHeader(HttpHeaders.ACCEPT)) - .getKey(); + MediaType res = null; + List accepts = requestContext.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT); + for (String accept : accepts) { + res = mediaTypeList.negotiateProduces(accept).getKey(); + if (res != null) { + break; + } + } + if (res == null) { // fallback for some tests + res = mediaTypeList.negotiateProduces(requestContext.serverRequest().getRequestHeader(HttpHeaders.ACCEPT)) + .getKey(); + } if (res == null) { throw new WebApplicationException(Response .notAcceptable(Variant.mediaTypes(mediaTypeList.getSortedMediaTypes()).build()) diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java index eee195df3ce55..16b31cd54b127 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java @@ -4,11 +4,16 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; +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.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.container.PreMatching; @@ -17,6 +22,9 @@ import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.ext.Provider; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; +import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; @@ -84,6 +92,37 @@ void setAcceptToTextInFilter() { .body(equalTo("text")); } + @Test + void entityJsonWithoutAcceptToTextInFilter() { + given().accept("application/json") + .when() + .get("test/entity") + .then() + .statusCode(200) + .body(containsString("\"text\"")); + } + + @Test + void entityTextWithoutAcceptToTextInFilter() { + given().accept("text/plain") + .when() + .get("test/entity") + .then() + .statusCode(200) + .body(equalTo("text")); + } + + @Test + void entityTextWithAcceptToTextInFilter() { + given().accept("application/json") + .header("x-set-accept-to-text", "true") + .when() + .get("test/entity") + .then() + .statusCode(200) + .body(equalTo("text")); + } + @Path("/test") public static class Resource { @@ -106,6 +145,16 @@ public String html() { """; } + + @GET + @Path("entity") + @Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON }) + public Entity entity() { + return new Entity("text"); + } + } + + public record Entity(String value) { } @PreMatching @@ -120,4 +169,62 @@ public void filter(ContainerRequestContext requestContext) { } } } + + @Provider + @Produces(MediaType.TEXT_PLAIN) + public static class DummyTextMessageBodyWriter implements ServerMessageBodyWriter { + + @Override + public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, + MediaType mediaType) { + return Entity.class.equals(type); + } + + @Override + public void writeResponse(Object o, Type genericType, ServerRequestContext context) + throws WebApplicationException, IOException { + context.serverResponse().end(((Entity) o).value()); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return Entity.class.equals(type); + } + + @Override + public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + throw new IllegalStateException("should not be called"); + } + } + + @Provider + @Produces(MediaType.APPLICATION_JSON) + public static class DummyJsonMessageBodyWriter implements ServerMessageBodyWriter { + + @Override + public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, + MediaType mediaType) { + return Entity.class.equals(type); + } + + @Override + public void writeResponse(Object o, Type genericType, ServerRequestContext context) + throws WebApplicationException, IOException { + context.serverResponse().end("{\"value\":\"" + ((Entity) o).value() + "\"}"); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return Entity.class.equals(type); + } + + @Override + public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + throw new IllegalStateException("should not be called"); + } + } }