Skip to content

Commit

Permalink
Deprecate @ServerRequestFilter(withBody) in favour of @WithFormRead
Browse files Browse the repository at this point in the history
You can also place it on endpoint methods.
Fixes #22444
  • Loading branch information
FroMage committed Dec 13, 2022
1 parent c773fd9 commit 04e20f6
Show file tree
Hide file tree
Showing 18 changed files with 310 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ protected <T, B extends AbstractInterceptorBuildItem> void registerInterceptors(
if (filterItem instanceof ContainerRequestFilterBuildItem) {
ContainerRequestFilterBuildItem crfbi = (ContainerRequestFilterBuildItem) filterItem;
interceptor.setNonBlockingRequired(crfbi.isNonBlockingRequired());
interceptor.setReadBody(crfbi.isReadBody());
interceptor.setWithFormRead(crfbi.isWithFormRead());
MethodInfo filterSourceMethod = crfbi.getFilterSourceMethod();
if (filterSourceMethod != null) {
interceptor.metadata = Map.of(FILTER_SOURCE_METHOD_METADATA_KEY, filterSourceMethod);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ public final class ContainerRequestFilterBuildItem extends AbstractInterceptorBu

private final boolean preMatching;
private final boolean nonBlockingRequired;
private final boolean readBody;
private final boolean withFormRead;

private final MethodInfo filterSourceMethod;

protected ContainerRequestFilterBuildItem(Builder builder) {
super(builder);
this.preMatching = builder.preMatching;
this.nonBlockingRequired = builder.nonBlockingRequired;
this.readBody = builder.readBody;
this.withFormRead = builder.withFormRead;
this.filterSourceMethod = builder.filterSourceMethod;
}

public ContainerRequestFilterBuildItem(String className) {
super(className);
this.preMatching = false;
this.nonBlockingRequired = false;
this.readBody = false;
this.withFormRead = false;
this.filterSourceMethod = null;
}

Expand All @@ -34,8 +34,8 @@ public boolean isNonBlockingRequired() {
return nonBlockingRequired;
}

public boolean isReadBody() {
return readBody;
public boolean isWithFormRead() {
return withFormRead;
}

public MethodInfo getFilterSourceMethod() {
Expand All @@ -45,7 +45,7 @@ public MethodInfo getFilterSourceMethod() {
public static final class Builder extends AbstractInterceptorBuildItem.Builder<ContainerRequestFilterBuildItem, Builder> {
boolean preMatching = false;
boolean nonBlockingRequired = false;
boolean readBody = false;
boolean withFormRead = false;

MethodInfo filterSourceMethod = null;

Expand All @@ -63,8 +63,8 @@ public Builder setNonBlockingRequired(boolean nonBlockingRequired) {
return this;
}

public Builder setReadBody(boolean readBody) {
this.readBody = readBody;
public Builder setWithFormRead(boolean withFormRead) {
this.withFormRead = withFormRead;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ public void handleCustomAnnotatedMethods(
.setPriority(generated.getPriority())
.setPreMatching(generated.isPreMatching())
.setNonBlockingRequired(generated.isNonBlocking())
.setReadBody(generated.isReadBody())
.setWithFormRead(generated.isWithFormRead())
.setFilterSourceMethod(generated.getFilterSourceMethod());
if (!generated.getNameBindingNames().isEmpty()) {
builder.setNameBindingNames(generated.getNameBindingNames());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package io.quarkus.resteasy.reactive.server.test.customproviders;

import java.util.function.Supplier;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.HttpHeaders;

import org.hamcrest.Matchers;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.RestQuery;
import org.jboss.resteasy.reactive.server.ServerRequestFilter;
import org.jboss.resteasy.reactive.server.WithFormRead;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext;
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.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class ImpliedReadBodyRequestFilterTest {

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

@Test
public void testMethodWithBody() {
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello")
.then().body(Matchers.equalTo("hello Quarkus!!!!!!!"));
}

@Test
public void testMethodWithUndeclaredBody() {
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello/empty")
.then().body(Matchers.equalTo("hello !!!!!!!"));
}

@Test
public void testMethodWithStringBody() {
// make sure that a form-reading filter doesn't prevent non-form request bodies from being deserialised
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello/string")
.then().body(Matchers.equalTo("hello name=Quarkus!!!!!!!"));
RestAssured.with()
.body("Quarkus")
.post("/hello/string")
.then().body(Matchers.equalTo("hello Quarkus?"));
}

@Test
public void testMethodWithoutBody() {
RestAssured.with()
.queryParam("name", "Quarkus")
.get("/hello")
.then().body(Matchers.equalTo("hello Quarkus!"));
}

@Path("hello")
public static class HelloResource {

@POST
public String helloPost(@RestForm String name, HttpHeaders headers) {
return "hello " + name + headers.getHeaderString("suffix");
}

@Path("empty")
@POST
public String helloEmptyPost(HttpHeaders headers) {
return "hello " + headers.getHeaderString("suffix");
}

@Path("string")
@POST
public String helloStringPost(String body, HttpHeaders headers) {
return "hello " + body + headers.getHeaderString("suffix");
}

@GET
public String helloGet(@RestQuery String name, HttpHeaders headers) {
return "hello " + name + headers.getHeaderString("suffix");
}
}

public static class Filters {

@WithFormRead
@ServerRequestFilter
public void addSuffix(ResteasyReactiveContainerRequestContext containerRequestContext) {
ResteasyReactiveRequestContext rrContext = (ResteasyReactiveRequestContext) containerRequestContext
.getServerRequestContext();
if (containerRequestContext.getMethod().equals("POST")) {
String nameFormParam = (String) rrContext.getFormParameter("name", true, false);
if (nameFormParam != null) {
containerRequestContext.getHeaders().putSingle("suffix", "!".repeat(nameFormParam.length()));
} else {
containerRequestContext.getHeaders().putSingle("suffix", "?");
}
} else {
containerRequestContext.getHeaders().putSingle("suffix", "!");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.RestQuery;
import org.jboss.resteasy.reactive.server.ServerRequestFilter;
import org.jboss.resteasy.reactive.server.WithFormRead;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext;
import org.jboss.shrinkwrap.api.ShrinkWrap;
Expand Down Expand Up @@ -41,6 +42,27 @@ public void testMethodWithBody() {
.then().body(Matchers.equalTo("hello Quarkus!!!!!!!"));
}

@Test
public void testMethodWithUndeclaredBody() {
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello/empty")
.then().body(Matchers.equalTo("hello !!!!!!!"));
}

@Test
public void testMethodWithStringBody() {
// make sure that a form-reading filter doesn't prevent non-form request bodies from being deserialised
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello/string")
.then().body(Matchers.equalTo("hello name=Quarkus!!!!!!!"));
RestAssured.with()
.body("Quarkus")
.post("/hello/string")
.then().body(Matchers.equalTo("hello Quarkus?"));
}

@Test
public void testMethodWithoutBody() {
RestAssured.with()
Expand All @@ -57,6 +79,18 @@ public String helloPost(@RestForm String name, HttpHeaders headers) {
return "hello " + name + headers.getHeaderString("suffix");
}

@Path("empty")
@POST
public String helloEmptyPost(HttpHeaders headers) {
return "hello " + headers.getHeaderString("suffix");
}

@Path("string")
@POST
public String helloStringPost(String body, HttpHeaders headers) {
return "hello " + body + headers.getHeaderString("suffix");
}

@GET
public String helloGet(@RestQuery String name, HttpHeaders headers) {
return "hello " + name + headers.getHeaderString("suffix");
Expand All @@ -65,13 +99,18 @@ public String helloGet(@RestQuery String name, HttpHeaders headers) {

public static class Filters {

@WithFormRead
@ServerRequestFilter(readBody = true)
public void addSuffix(ResteasyReactiveContainerRequestContext containerRequestContext) {
ResteasyReactiveRequestContext rrContext = (ResteasyReactiveRequestContext) containerRequestContext
.getServerRequestContext();
if (containerRequestContext.getMethod().equals("POST")) {
String nameFormParam = (String) rrContext.getFormParameter("name", true, false);
containerRequestContext.getHeaders().putSingle("suffix", "!".repeat(nameFormParam.length()));
if (nameFormParam != null) {
containerRequestContext.getHeaders().putSingle("suffix", "!".repeat(nameFormParam.length()));
} else {
containerRequestContext.getHeaders().putSingle("suffix", "?");
}
} else {
containerRequestContext.getHeaders().putSingle("suffix", "!");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package io.quarkus.resteasy.reactive.server.test.customproviders;

import java.util.function.Supplier;

import javax.ws.rs.POST;
import javax.ws.rs.Path;

import org.hamcrest.Matchers;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.server.WithFormRead;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.spi.ServerRequestContext;
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.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class WithFormBodyTest {

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

@Test
public void testMethodWithBody() {
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello")
.then().body(Matchers.equalTo("hello Quarkus"));
}

@Test
public void testMethodWithUndeclaredBody() {
RestAssured.with()
.formParam("name", "Quarkus")
.post("/hello/empty")
.then().body(Matchers.equalTo("hello Quarkus"));
}

@Path("hello")
public static class HelloResource {

@POST
public String helloPost(@RestForm String name) {
return "hello " + name;
}

@WithFormRead
@Path("empty")
@POST
public String helloEmptyPost(ServerRequestContext requestContext) {
return "hello " + ((ResteasyReactiveRequestContext) requestContext).getFormParameter("name", true, false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,8 @@ private ResourceMethod createResourceMethod(ClassInfo currentClassInfo, ClassInf
basicResourceClassInfo.getConsumes());
boolean suspended = false;
boolean sse = false;
boolean formParamRequired = false;
boolean formParamRequired = getAnnotationStore().getAnnotation(currentMethodInfo,
ResteasyReactiveDotNames.WITH_FORM_READ) != null;
Set<String> fileFormNames = new HashSet<>();
Type bodyParamType = null;
TypeArgMapper typeArgMapper = new TypeArgMapper(currentMethodInfo.declaringClass(), index);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ public final class ResteasyReactiveDotNames {
public static final DotName RESTEASY_REACTIVE_CONTAINER_REQUEST_CONTEXT = DotName
.createSimple("org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext");

public static final DotName WITH_FORM_READ = DotName
.createSimple("org.jboss.resteasy.reactive.server.WithFormRead");

public static final DotName OBJECT = DotName.createSimple(Object.class.getName());

public static final DotName CONTINUATION = DotName.createSimple("kotlin.coroutines.Continuation");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ResourceInterceptor<T>
private BeanFactory<T> factory;
private int priority = Priorities.USER; // default priority as defined by spec
private boolean nonBlockingRequired; // whether or not @NonBlocking was specified on the class
private boolean readBody; // whether or not 'readBody' was set true for this filter
private boolean withFormRead; // whether or not '@WithFormRead' was set on this filter

/**
* The class names of the {@code @NameBinding} annotations that the method is annotated with.
Expand Down Expand Up @@ -76,12 +76,12 @@ public void setNonBlockingRequired(boolean nonBlockingRequired) {
this.nonBlockingRequired = nonBlockingRequired;
}

public boolean isReadBody() {
return readBody;
public boolean isWithFormRead() {
return withFormRead;
}

public void setReadBody(boolean readBody) {
this.readBody = readBody;
public void setWithFormRead(boolean withFormRead) {
this.withFormRead = withFormRead;
}

// spec says that writer interceptors are sorted in ascending order
Expand Down

0 comments on commit 04e20f6

Please sign in to comment.