From a6edf30c44f9d6564b2e71fc7dcdb5071e32669a Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 31 Oct 2024 17:31:35 +0200 Subject: [PATCH] Properly implement priority of ContainerResponseFilter Closes: #44229 --- .../reactive/common/model/HasPriority.java | 7 + .../common/model/ResourceInterceptor.java | 9 +- .../startup/RuntimeInterceptorDeployment.java | 3 +- ...ipleResponseFiltersWithPrioritiesTest.java | 122 ++++++++++++++++++ 4 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/MultipleResponseFiltersWithPrioritiesTest.java diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/HasPriority.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/HasPriority.java index 4d4d4d2c4b2a8..932892a4d83aa 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/HasPriority.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/HasPriority.java @@ -14,6 +14,13 @@ class TreeMapComparator implements Comparator { public static final TreeMapComparator INSTANCE = new TreeMapComparator(); + public static final TreeMapComparator REVERSED = new TreeMapComparator() { + @Override + public int compare(HasPriority o1, HasPriority o2) { + return super.compare(o2, o1); + } + }; + @Override public int compare(HasPriority o1, HasPriority o2) { int res = o1.priority().compareTo(o2.priority()); diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceInterceptor.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceInterceptor.java index b4bdd4e8f09f0..d31dbe4a1caab 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceInterceptor.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceInterceptor.java @@ -95,7 +95,6 @@ public void setRuntimeType(RuntimeType runtimeType) { this.runtimeType = runtimeType; } - // spec says that writer interceptors are sorted in ascending order @Override public int compareTo(ResourceInterceptor o) { return this.priority().compareTo(o.priority()); @@ -105,12 +104,8 @@ public int compareTo(ResourceInterceptor o) { public static class Reversed extends ResourceInterceptor { @Override - public Integer priority() { - Integer p = super.priority(); - if (p == null) { - return null; - } - return -p; + public int compareTo(ResourceInterceptor o) { + return o.priority().compareTo(this.priority()); } } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeInterceptorDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeInterceptorDeployment.java index 7679f9e2d0c44..9511aca57fbcd 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeInterceptorDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeInterceptorDeployment.java @@ -173,7 +173,8 @@ TreeMap, T> buildInterceptorMap( Map, T> globalInterceptorsMap, Map, T> nameInterceptorsMap, Map, T> methodSpecificInterceptorsMap, ResourceMethod method, boolean reversed) { - TreeMap, T> interceptorsToUse = new TreeMap<>(HasPriority.TreeMapComparator.INSTANCE); + TreeMap, T> interceptorsToUse = new TreeMap<>( + reversed ? HasPriority.TreeMapComparator.REVERSED : HasPriority.TreeMapComparator.INSTANCE); interceptorsToUse.putAll(globalInterceptorsMap); interceptorsToUse.putAll(methodSpecificInterceptorsMap); for (ResourceInterceptor nameInterceptor : nameInterceptorsMap.keySet()) { diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/MultipleResponseFiltersWithPrioritiesTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/MultipleResponseFiltersWithPrioritiesTest.java new file mode 100644 index 0000000000000..74586aa63371c --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/MultipleResponseFiltersWithPrioritiesTest.java @@ -0,0 +1,122 @@ +package org.jboss.resteasy.reactive.server.vertx.test.simple; + +import static io.restassured.RestAssured.*; +import static io.restassured.RestAssured.when; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; +import jakarta.ws.rs.ext.Provider; + +import org.jboss.resteasy.reactive.server.vertx.test.CookiesSetInFilterTest; +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.Headers; + +public class MultipleResponseFiltersWithPrioritiesTest { + + @RegisterExtension + static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(CookiesSetInFilterTest.TestResource.class, CookiesSetInFilterTest.Filters.class)); + + @Test + void requestDoesNotContainCookie() { + when().get("/test") + .then() + .statusCode(200) + .body(is("foo")); + } + + @Test + void test() { + Headers headers = get("/hello") + .then() + .statusCode(200) + .extract().headers(); + assertThat(headers.getValues("filter-response")).containsOnly("max-default-0-minPlus1-min"); + } + + @Path("hello") + public static class TestResource { + + @GET + public String get() { + return "hello"; + } + } + + @Provider + @Priority(Integer.MAX_VALUE) + public static class FilterMax implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + responseContext.getHeaders().putSingle("filter-response", "max"); + } + + } + + @Provider + public static class FilterDefault implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + String previousFilterHeaderValue = (String) responseContext.getHeaders().getFirst("filter-response"); + responseContext.getHeaders().putSingle("filter-response", previousFilterHeaderValue + "-default"); + } + + } + + @Provider + @Priority(0) + public static class Filter0 implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + String previousFilterHeaderValue = (String) responseContext.getHeaders().getFirst("filter-response"); + responseContext.getHeaders().putSingle("filter-response", previousFilterHeaderValue + "-0"); + } + + } + + @Provider + @Priority(Integer.MIN_VALUE + 1) + public static class FilterMinPlus1 implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + String previousFilterHeaderValue = (String) responseContext.getHeaders().getFirst("filter-response"); + responseContext.getHeaders().putSingle("filter-response", previousFilterHeaderValue + "-minPlus1"); + } + + } + + @Provider + @Priority(Integer.MIN_VALUE) + public static class FilterMin implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + String previousFilterHeaderValue = (String) responseContext.getHeaders().getFirst("filter-response"); + responseContext.getHeaders().putSingle("filter-response", previousFilterHeaderValue + "-min"); + } + + } +}