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

Deprecate @ServerRequestFilter(withBody) in favour of @WithFormRead #29825

Merged
merged 1 commit into from Dec 13, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
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
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
@@ -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", "!");
}
}
}
}
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
@@ -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);
}
}
}
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
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
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