Skip to content

Commit

Permalink
Ensure that ServerStringMessageBodyHandler doesn't affect build time …
Browse files Browse the repository at this point in the history
…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: quarkusio#14720
(cherry picked from commit 2321d0c)
  • Loading branch information
geoand authored and gsmet committed Feb 2, 2021
1 parent 3b00c6b commit d975e46
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -30,7 +30,7 @@

import io.quarkus.resteasy.reactive.jackson.CustomSerialization;

public class JacksonMessageBodyWriter implements ServerMessageBodyWriter<Object> {
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();
Expand Down Expand Up @@ -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<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Object> {
public class JsonbMessageBodyWriter extends ServerMessageBodyWriter.AllWriteableMessageBodyWriter {

private final Jsonb json;

Expand All @@ -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<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down Expand Up @@ -366,6 +364,16 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz,
return runtimeResource;
}

private boolean isSingleEffectiveWriter(List<MessageBodyWriter<?>> 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<ServerRestHandler> handlers, ServerResourceMethod method, DeploymentInfo info,
HandlerChainCustomizer.Phase phase) {
for (HandlerChainCustomizer i : info.getGlobalHandlerCustomers()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -15,4 +16,24 @@ public interface ServerMessageBodyWriter<T> extends MessageBodyWriter<T> {

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<Object> {

@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;
}
}
}

0 comments on commit d975e46

Please sign in to comment.