From d975e46d4c406c86437d4ab297d2dba70ec4e186 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 1 Feb 2021 18:28:53 +0200 Subject: [PATCH] Ensure that ServerStringMessageBodyHandler doesn't affect build time resolution of builders By making certain writers extend AllWriteableMessageBodyWriter we can be certain that even in the presense of multiple writers, RESTEasy Reactive can optimize itself to use only the first one Fixes: #14720 (cherry picked from commit 2321d0c782a50ea368e04d29d6c6345c532e0f16) --- .../serialisers/JacksonMessageBodyWriter.java | 14 ++----------- .../serialisers/JsonbMessageBodyWriter.java | 13 +----------- .../startup/RuntimeResourceDeployment.java | 14 ++++++++++--- .../server/spi/ServerMessageBodyWriter.java | 21 +++++++++++++++++++ 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/JacksonMessageBodyWriter.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/JacksonMessageBodyWriter.java index cb07daea01df0..566e5755e3831 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/JacksonMessageBodyWriter.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/JacksonMessageBodyWriter.java @@ -1,6 +1,6 @@ package io.quarkus.resteasy.reactive.jackson.runtime.serialisers; -import static org.jboss.resteasy.reactive.server.vertx.providers.serialisers.json.JsonMessageBodyWriterUtil.*; +import static org.jboss.resteasy.reactive.server.vertx.providers.serialisers.json.JsonMessageBodyWriterUtil.setContentTypeIfNecessary; import java.io.IOException; import java.io.OutputStream; @@ -30,7 +30,7 @@ import io.quarkus.resteasy.reactive.jackson.CustomSerialization; -public class JacksonMessageBodyWriter implements ServerMessageBodyWriter { +public class JacksonMessageBodyWriter extends ServerMessageBodyWriter.AllWriteableMessageBodyWriter { private static final String JSON_VIEW_NAME = JsonView.class.getName(); private static final String CUSTOM_SERIALIZATION = CustomSerialization.class.getName(); @@ -62,11 +62,6 @@ private static void setNecessaryJsonFactoryConfig(JsonFactory jsonFactory) { jsonFactory.configure(Feature.FLUSH_PASSED_TO_STREAM, false); } - @Override - public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return true; - } - @Override public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { @@ -87,11 +82,6 @@ public void writeTo(Object o, Class type, Type genericType, Annotation[] anno } } - @Override - public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { - return true; - } - @Override public void writeResponse(Object o, Type genericType, ServerRequestContext context) throws WebApplicationException, IOException { diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/java/io/quarkus/resteasy/reactive/jsonb/runtime/serialisers/JsonbMessageBodyWriter.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/java/io/quarkus/resteasy/reactive/jsonb/runtime/serialisers/JsonbMessageBodyWriter.java index f3378c243b688..93bbbf7aaf8bb 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/java/io/quarkus/resteasy/reactive/jsonb/runtime/serialisers/JsonbMessageBodyWriter.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/runtime/src/main/java/io/quarkus/resteasy/reactive/jsonb/runtime/serialisers/JsonbMessageBodyWriter.java @@ -13,11 +13,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; -import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -public class JsonbMessageBodyWriter implements ServerMessageBodyWriter { +public class JsonbMessageBodyWriter extends ServerMessageBodyWriter.AllWriteableMessageBodyWriter { private final Jsonb json; @@ -26,11 +25,6 @@ public JsonbMessageBodyWriter(Jsonb json) { this.json = json; } - @Override - public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { - return true; - } - @Override public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { @@ -42,11 +36,6 @@ public void writeTo(Object o, Class type, Type genericType, Annotation[] anno } } - @Override - public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { - return true; - } - @Override public void writeResponse(Object o, Type genericType, ServerRequestContext context) throws WebApplicationException, IOException { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java index 9eea8378dbf83..619402e365038 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java @@ -294,9 +294,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, + "#" + method.getName() + "(" + Arrays.toString(method.getParameters()) + ")"); handlers.add(new VariableProducesHandler(serverMediaType, serialisers)); score.add(ScoreSystem.Category.Writer, ScoreSystem.Diagnostic.WriterRunTime); - } else if (buildTimeWriters.size() == 1) { - //only a single handler that can handle the response - //this is a very common case + } else if (isSingleEffectiveWriter(buildTimeWriters)) { MessageBodyWriter writer = buildTimeWriters.get(0); handlers.add(new FixedProducesHandler(mediaType, new FixedEntityWriter( writer, serialisers))); @@ -366,6 +364,16 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, return runtimeResource; } + private boolean isSingleEffectiveWriter(List> buildTimeWriters) { + if (buildTimeWriters.size() == 1) { // common case of single writer + return true; + } + + // in the case where the first Writer is an instance of AllWriteableMessageBodyWriter, + // it doesn't matter that we have multiple writers as the first one will always be used to serialize + return buildTimeWriters.get(0) instanceof ServerMessageBodyWriter.AllWriteableMessageBodyWriter; + } + private void addHandlers(List handlers, ServerResourceMethod method, DeploymentInfo info, HandlerChainCustomizer.Phase phase) { for (HandlerChainCustomizer i : info.getGlobalHandlerCustomers()) { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerMessageBodyWriter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerMessageBodyWriter.java index 92d14da3c4f61..7c794519b6b53 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerMessageBodyWriter.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ServerMessageBodyWriter.java @@ -1,6 +1,7 @@ package org.jboss.resteasy.reactive.server.spi; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; @@ -15,4 +16,24 @@ public interface ServerMessageBodyWriter extends MessageBodyWriter { void writeResponse(T o, Type genericType, ServerRequestContext context) throws WebApplicationException, IOException; + /** + * A special super-class of MessageBodyWriters that accepts all types of input. + * The main purpose of this class is to allow runtime code + * to optimize for the case when there are multiple providers determined at build time + * but the first one will always be used + */ + abstract class AllWriteableMessageBodyWriter implements ServerMessageBodyWriter { + + @Override + public final boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, + MediaType mediaType) { + return true; + } + + @Override + public final boolean isWriteable(Class type, Type genericType, + Annotation[] annotations, MediaType mediaType) { + return true; + } + } }