From f3ced2d329710ef2f61c02b4c97c483524ff68ae Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 6 Jul 2020 09:40:16 +0200 Subject: [PATCH] Reactive routes - set content-type from Route#produces() - if no content-type header is set try to use RoutingContext#getAcceptableContentType() - resolves #10465 --- .../quarkus/vertx/web/deployment/Methods.java | 4 ++++ .../web/deployment/VertxWebProcessor.java | 7 +++++-- .../main/java/io/quarkus/vertx/web/Route.java | 4 ++++ .../vertx/web/runtime/RouteHandlers.java | 19 ++++++++++++++++++- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/Methods.java b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/Methods.java index 554c8137af547..22102021b2bd8 100644 --- a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/Methods.java +++ b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/Methods.java @@ -19,6 +19,7 @@ import io.quarkus.vertx.web.runtime.MultiJsonArraySupport; import io.quarkus.vertx.web.runtime.MultiSseSupport; import io.quarkus.vertx.web.runtime.MultiSupport; +import io.quarkus.vertx.web.runtime.RouteHandlers; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.groups.UniSubscribe; @@ -136,6 +137,9 @@ class Methods { CreationalContext.class); static final MethodDescriptor OBJECT_CONSTRUCTOR = MethodDescriptor.ofConstructor(Object.class); + static final MethodDescriptor ROUTE_HANDLERS_SET_CONTENT_TYPE = MethodDescriptor + .ofMethod(RouteHandlers.class, "setContentType", void.class, RoutingContext.class); + private Methods() { // Avoid direct instantiation } diff --git a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java index a8b9289ee1afb..7b56b67208bfa 100644 --- a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java +++ b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java @@ -530,10 +530,13 @@ void implementInvoke(HandlerDescriptor descriptor, BeanInfo bean, MethodInfo met // Invoke the business method handler ResultHandle res = invoke.invokeVirtualMethod(methodDescriptor, beanInstanceHandle, paramHandles); + // If no content-type header is set then try to use the most acceptable content type + invoke.invokeStaticMethod(Methods.ROUTE_HANDLERS_SET_CONTENT_TYPE, routingContext); + // Get the response: HttpServerResponse response = rc.response() - ResultHandle response = invoke.invokeInterfaceMethod(Methods.RESPONSE, routingContext); MethodDescriptor end = Methods.getEndMethodForContentType(descriptor); if (descriptor.isReturningUni()) { + ResultHandle response = invoke.invokeInterfaceMethod(Methods.RESPONSE, routingContext); // The method returns a Uni. // We subscribe to this Uni and write the provided item in the HTTP response // If the method returned null, we fail @@ -568,7 +571,7 @@ void implementInvoke(HandlerDescriptor descriptor, BeanInfo bean, MethodInfo met } else if (descriptor.getContentType() != null) { // The method returns "something" in a synchronous manner, write it into the response - + ResultHandle response = invoke.invokeInterfaceMethod(Methods.RESPONSE, routingContext); // If the method returned null, we fail // If the method returns string or buffer, the response.end method is used to write the response // If the method returns an object, the result is mapped to JSON and written into the response diff --git a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/Route.java b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/Route.java index a8b0ef5eae591..d4221b7252e7f 100644 --- a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/Route.java +++ b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/Route.java @@ -10,6 +10,7 @@ import io.vertx.core.Handler; import io.vertx.core.http.HttpMethod; import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; /** * This annotation can be used to configure a reactive route in a declarative way. @@ -74,8 +75,11 @@ /** * Used for content-based routing. + *

+ * If no {@code Content-Type} header is set then try to use the most acceptable content type. * * @see io.vertx.ext.web.Route#produces(String) + * @see RoutingContext#getAcceptableContentType() * @return the produced content types */ String[] produces() default {}; diff --git a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouteHandlers.java b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouteHandlers.java index 4e1978f80b5e6..a2f37cac5b35d 100644 --- a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouteHandlers.java +++ b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouteHandlers.java @@ -5,12 +5,29 @@ import io.quarkus.arc.Arc; import io.quarkus.arc.impl.LazyValue; import io.quarkus.security.identity.SecurityIdentity; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; -final class RouteHandlers { +public final class RouteHandlers { + + private RouteHandlers() { + } + + static final String CONTENT_TYPE = "content-type"; private static final LazyValue> SECURITY_IDENTITY_EVENT = new LazyValue<>( RouteHandlers::createEvent); + public static void setContentType(RoutingContext context) { + HttpServerResponse response = context.response(); + if (response.headers().get(CONTENT_TYPE) == null) { + String acceptableContentType = context.getAcceptableContentType(); + if (acceptableContentType != null) { + response.putHeader(CONTENT_TYPE, acceptableContentType); + } + } + } + static void fireSecurityIdentity(SecurityIdentity identity) { SECURITY_IDENTITY_EVENT.get().fire(identity); }