diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/MediaTypesWithSuffixHandlingTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/MediaTypesWithSuffixHandlingTest.java new file mode 100644 index 0000000000000..4b741ca17e064 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/MediaTypesWithSuffixHandlingTest.java @@ -0,0 +1,216 @@ +package io.quarkus.resteasy.reactive.server.test.resource.basic; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; + +import org.hamcrest.Matchers; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; +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 MediaTypesWithSuffixHandlingTest { + + @RegisterExtension + static QuarkusUnitTest testExtension = new QuarkusUnitTest() + .setArchiveProducer(() -> { + JavaArchive archive = ShrinkWrap.create(JavaArchive.class); + archive.addClasses(TestResource.class, NoSuffixMessageBodyWriter.class, SuffixMessageBodyWriter.class); + return archive; + }); + + @Test + public void testWriterWithoutSuffix() { + RestAssured.get("/test/writer/with-no-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("result - no suffix writer")); + } + + @Test + public void testReaderWithoutSuffix() { + RestAssured.get("/test/reader/with-no-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("from reader - result")); + } + + @Test + public void testWriterWithSuffix() { + RestAssured.get("/test/writer/with-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("result - suffix writer")); + } + + @Test + public void testReaderWithSuffix() { + RestAssured.get("/test/reader/with-suffix") + .then() + .statusCode(200) + .body(Matchers.equalTo("from reader suffix - result")); + } + + @Path("/test") + public static class TestResource { + + @GET + @Path("/writer/with-no-suffix") + @Produces("text/test") + public String writerSimple() { + return "result"; + } + + @GET + @Path("/writer/with-suffix") + @Produces("text/test+suffix") + public String writerSuffix() { + return "result"; + } + + @GET + @Path("/reader/with-no-suffix") + @Consumes("text/test") + public String readerSimple(Object fromReader) { + return fromReader + " - result"; + } + + @GET + @Path("/reader/with-suffix") + @Consumes("text/test+suffix") + public String readerSuffix(Object fromReader) { + return fromReader + " - result"; + } + } + + @Provider + @Consumes("text/test") + @Produces("text/test") + public static class NoSuffixMessageBodyWriter implements ServerMessageBodyWriter, ServerMessageBodyReader { + + @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 { + String response = (String) o; + response += " - no suffix writer"; + context.getOrCreateOutputStream().write(response.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return true; + } + + @Override + public Object readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException { + return "from reader"; + } + + @Override + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public Object readFrom(Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap multivaluedMap, InputStream inputStream) + throws WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + } + + @Provider + @Consumes("text/test+suffix") + @Produces("text/test+suffix") + public static class SuffixMessageBodyWriter implements ServerMessageBodyWriter, ServerMessageBodyReader { + + @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 { + String response = (String) o; + response += " - suffix writer"; + context.getOrCreateOutputStream().write(response.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return true; + } + + @Override + public Object readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException { + return "from reader suffix"; + } + + @Override + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + throw new IllegalStateException("should never have been called"); + } + + @Override + public Object readFrom(Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap multivaluedMap, InputStream inputStream) + throws WebApplicationException { + throw new IllegalStateException("should never have been called"); + } + } + +} diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java index c73f288f0c87a..55815186fa959 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientReaderInterceptorContextImpl.java @@ -17,7 +17,6 @@ import org.jboss.resteasy.reactive.common.core.Serialisers; import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl; import org.jboss.resteasy.reactive.common.util.CaseInsensitiveMap; -import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; public class ClientReaderInterceptorContextImpl extends AbstractClientInterceptorContextImpl implements ReaderInterceptorContext { @@ -35,7 +34,7 @@ public ClientReaderInterceptorContextImpl(Annotation[] annotations, Class ent Map properties, MultivaluedMap headers, ConfigurationImpl configuration, Serialisers serialisers, InputStream inputStream, ReaderInterceptor[] interceptors) { - super(annotations, entityClass, entityType, MediaTypeHelper.withSuffixAsSubtype(mediaType), properties); + super(annotations, entityClass, entityType, mediaType, properties); this.configuration = configuration; this.serialisers = serialisers; this.inputStream = inputStream; diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java index 9a1c82d1795ba..e543e7cf976cb 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java @@ -43,7 +43,7 @@ public List> findReaders(ConfigurationImpl configuration, C public List> findReaders(ConfigurationImpl configuration, Class entityType, MediaType mediaType, RuntimeType runtimeType) { - List mt = Collections.singletonList(mediaType); + List desired = MediaTypeHelper.getUngroupedMediaTypes(mediaType); List> ret = new ArrayList<>(); Deque> toProcess = new LinkedList<>(); Class klass = entityType; @@ -66,7 +66,7 @@ public List> findReaders(ConfigurationImpl configuration, C while (!toProcess.isEmpty()) { Class iface = toProcess.poll(); List goodTypeReaders = readers.get(iface); - readerLookup(mediaType, runtimeType, mt, ret, goodTypeReaders); + readerLookup(mediaType, runtimeType, desired, ret, goodTypeReaders); for (Class i : iface.getInterfaces()) { if (!seen.contains(i)) { seen.add(i); @@ -76,7 +76,7 @@ public List> findReaders(ConfigurationImpl configuration, C } } List goodTypeReaders = readers.get(klass); - readerLookup(mediaType, runtimeType, mt, ret, goodTypeReaders); + readerLookup(mediaType, runtimeType, desired, ret, goodTypeReaders); if (klass.isInterface()) { klass = Object.class; } else { @@ -87,7 +87,8 @@ public List> findReaders(ConfigurationImpl configuration, C return ret; } - private void readerLookup(MediaType mediaType, RuntimeType runtimeType, List mt, List> ret, + private void readerLookup(MediaType mediaType, RuntimeType runtimeType, List desired, + List> ret, List goodTypeReaders) { if (goodTypeReaders != null && !goodTypeReaders.isEmpty()) { List mediaTypeMatchingReaders = new ArrayList<>(goodTypeReaders.size()); @@ -96,13 +97,15 @@ private void readerLookup(MediaType mediaType, RuntimeType runtimeType, List> findBuildTimeWriters(Class entityType, Runt protected List findResourceWriters(QuarkusMultivaluedMap, ResourceWriter> writers, Class klass, List produces, RuntimeType runtimeType) { + Class currentClass = klass; + List desired = MediaTypeHelper.getUngroupedMediaTypes(produces); List ret = new ArrayList<>(); Deque> toProcess = new LinkedList<>(); do { - if (klass == Object.class) { + if (currentClass == Object.class) { //spec extension, look for interfaces as well //we match interfaces before Object Set> seen = new HashSet<>(toProcess); while (!toProcess.isEmpty()) { Class iface = toProcess.poll(); List goodTypeWriters = writers.get(iface); - writerLookup(runtimeType, produces, ret, goodTypeWriters); + writerLookup(runtimeType, produces, desired, ret, goodTypeWriters); for (Class i : iface.getInterfaces()) { if (!seen.contains(i)) { seen.add(i); @@ -170,15 +175,16 @@ protected List findResourceWriters(QuarkusMultivaluedMap goodTypeWriters = writers.get(klass); - writerLookup(runtimeType, produces, ret, goodTypeWriters); - toProcess.addAll(Arrays.asList(klass.getInterfaces())); + List goodTypeWriters = writers.get(currentClass); + writerLookup(runtimeType, produces, desired, ret, goodTypeWriters); + toProcess.addAll(Arrays.asList(currentClass.getInterfaces())); // if we're an interface, pretend our superclass is Object to get us through the same logic as a class - if (klass.isInterface()) - klass = Object.class; - else - klass = klass.getSuperclass(); - } while (klass != null); + if (currentClass.isInterface()) { + currentClass = Object.class; + } else { + currentClass = currentClass.getSuperclass(); + } + } while (currentClass != null); return ret; } @@ -200,22 +206,25 @@ protected List> toMessageBodyWriters(List r return ret; } - private void writerLookup(RuntimeType runtimeType, List mt, List ret, - List goodTypeWriters) { + private void writerLookup(RuntimeType runtimeType, List produces, List desired, + List ret, List goodTypeWriters) { if (goodTypeWriters != null && !goodTypeWriters.isEmpty()) { List mediaTypeMatchingWriters = new ArrayList<>(goodTypeWriters.size()); + for (int i = 0; i < goodTypeWriters.size(); i++) { ResourceWriter goodTypeWriter = goodTypeWriters.get(i); if (!goodTypeWriter.matchesRuntimeType(runtimeType)) { continue; } - MediaType match = MediaTypeHelper.getFirstMatch(mt, goodTypeWriter.mediaTypes()); + MediaType match = MediaTypeHelper.getFirstMatch(desired, goodTypeWriter.mediaTypes()); if (match != null) { mediaTypeMatchingWriters.add(goodTypeWriter); } } + // we sort here because the spec mentions that the writers closer to the requested java type are tried first - mediaTypeMatchingWriters.sort(ResourceWriter.ResourceWriterComparator.INSTANCE); + mediaTypeMatchingWriters.sort(new ResourceWriter.ResourceWriterComparator(produces)); + ret.addAll(mediaTypeMatchingWriters); } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java index 69ad09b953e4a..ca73e22378d91 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java @@ -114,7 +114,11 @@ public boolean matchesRuntimeType(RuntimeType runtimeType) { */ public static class ResourceReaderComparator implements Comparator { - public static final ResourceReaderComparator INSTANCE = new ResourceReaderComparator(); + private final List produces; + + public ResourceReaderComparator(List produces) { + this.produces = produces; + } @Override public int compare(ResourceReader o1, ResourceReader o2) { @@ -144,6 +148,14 @@ public int compare(ResourceReader o1, ResourceReader o2) { return mediaTypeCompare; } + // try to compare using the number of matching produces media types + if (!produces.isEmpty()) { + mediaTypeCompare = MediaTypeHelper.compareMatchingMediaTypes(produces, mediaTypes1, mediaTypes2); + if (mediaTypeCompare != 0) { + return mediaTypeCompare; + } + } + // done to make the sorting result deterministic return Integer.compare(mediaTypes1.size(), mediaTypes2.size()); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java index d04c4420c801d..381c363b60667 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java @@ -99,7 +99,7 @@ public ServerMediaType serverMediaType() { if (serverMediaType == null) { synchronized (this) { // a MessageBodyWriter should always return its configured media type when negotiating, hence the 'false' for 'useSuffix' - serverMediaType = new ServerMediaType(mediaTypes(), StandardCharsets.UTF_8.name(), false, false); + serverMediaType = new ServerMediaType(mediaTypes(), StandardCharsets.UTF_8.name(), false); } } return serverMediaType; @@ -129,7 +129,15 @@ public String toString() { */ public static class ResourceWriterComparator implements Comparator { - public static final ResourceWriterComparator INSTANCE = new ResourceWriterComparator(); + private final List produces; + + public ResourceWriterComparator() { + this(Collections.emptyList()); + } + + public ResourceWriterComparator(List produces) { + this.produces = produces; + } @Override public int compare(ResourceWriter o1, ResourceWriter o2) { @@ -159,6 +167,14 @@ public int compare(ResourceWriter o1, ResourceWriter o2) { return mediaTypeCompare; } + // try to compare using the number of matching produces media types + if (!produces.isEmpty()) { + mediaTypeCompare = MediaTypeHelper.compareMatchingMediaTypes(produces, mediaTypes1, mediaTypes2); + if (mediaTypeCompare != 0) { + return mediaTypeCompare; + } + } + // done to make the sorting result deterministic return Integer.compare(mediaTypes1.size(), mediaTypes2.size()); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java index 41b72877f9808..f7e5e84006736 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java @@ -2,9 +2,11 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -16,6 +18,7 @@ public class MediaTypeHelper { public static final MediaTypeComparator Q_COMPARATOR = new MediaTypeComparator("q"); public static final MediaTypeComparator QS_COMPARATOR = new MediaTypeComparator("qs"); + private static final String MEDIA_TYPE_SUFFIX_DELIM = "+"; private static float getQTypeWithParamInfo(MediaType type, String parameterName) { if (type.getParameters() != null) { @@ -138,6 +141,13 @@ public static int compareWeight(MediaType one, MediaType two) { return Q_COMPARATOR.compare(one, two); } + public static int compareMatchingMediaTypes(List produces, List mediaTypes1, + List mediaTypes2) { + int countMediaTypes1 = countMatchingMediaTypes(produces, mediaTypes1); + int countMediaTypes2 = countMatchingMediaTypes(produces, mediaTypes2); + return (countMediaTypes1 < countMediaTypes2) ? 1 : ((countMediaTypes1 == countMediaTypes2) ? 0 : -1); + } + public static void sortByWeight(List types) { if (hasAtMostOneItem(types)) { return; @@ -267,20 +277,77 @@ public static boolean isUnsupportedWildcardSubtype(MediaType mediaType) { return false; } + public static List toListOfMediaType(String[] mediaTypes) { + if (mediaTypes == null || mediaTypes.length == 0) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(mediaTypes.length); + for (String mediaType : mediaTypes) { + list.add(MediaType.valueOf(mediaType)); + } + + return Collections.unmodifiableList(list); + } + + /** + * This method ungroups the media types with suffix in separated media types. For example, having the media type + * "application/one+two" will return a list containing ["application/one+two", "application/one", "application/two"]. + * The Media Types without suffix remain as one media type. + * + * @param mediaTypes the list of media types to separate. + * @return the list of ungrouped media types. + */ + public static List getUngroupedMediaTypes(List mediaTypes) { + List effectiveMediaTypes = new ArrayList<>(); + for (MediaType mediaType : mediaTypes) { + effectiveMediaTypes.addAll(getUngroupedMediaTypes(mediaType)); + } + + return Collections.unmodifiableList(effectiveMediaTypes); + } + /** - * If the supplied media type contains a suffix in the subtype, then this returns a new media type - * that uses the suffix as the subtype + * This method ungroups the media type with suffix in separated media types. For example, having the media type + * "application/one+two" will return a list containing ["application/one+two", "application/one", "application/two"]. + * If the Media Type does not have a suffix, then it's not modified. + * + * @param mediaType the media type to separate. + * @return the list of ungrouped media types. */ - public static MediaType withSuffixAsSubtype(MediaType mediaType) { + public static List getUngroupedMediaTypes(MediaType mediaType) { if (mediaType == null) { - return null; + return Collections.emptyList(); + } + + if (mediaType.getSubtype() == null || !mediaType.getSubtype().contains(MEDIA_TYPE_SUFFIX_DELIM)) { + return Collections.singletonList(mediaType); + } + + String[] subTypes = mediaType.getSubtype().split(Pattern.quote(MEDIA_TYPE_SUFFIX_DELIM)); + + List effectiveMediaTypes = new ArrayList<>(1 + subTypes.length); + effectiveMediaTypes.add(mediaType); + for (String subType : subTypes) { + effectiveMediaTypes.add(new MediaType(mediaType.getType(), subType, mediaType.getParameters())); } - int plusIndex = mediaType.getSubtype().indexOf('+'); - if ((plusIndex > -1) && (plusIndex < mediaType.getSubtype().length() - 1)) { - mediaType = new MediaType(mediaType.getType(), - mediaType.getSubtype().substring(plusIndex + 1), - mediaType.getParameters()); + + return Collections.unmodifiableList(effectiveMediaTypes); + } + + private static int countMatchingMediaTypes(List produces, List mediaTypes) { + int count = 0; + for (int i = 0; i < mediaTypes.size(); i++) { + MediaType mediaType = mediaTypes.get(i); + for (int j = 0; j < produces.size(); j++) { + MediaType produce = produces.get(j); + if (mediaType.isCompatible(produce)) { + count++; + break; + } + } } - return mediaType; + + return count; } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java index cff31dd2a3200..97ba2d2f174be 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java @@ -30,14 +30,11 @@ public static List mediaTypesFromArray(String[] mediaTypesStrs) { } /** - * * @param mediaTypes The original media types * @param charset charset to use * @param deprioritizeWildcards whether or not wildcard types should be carry less weight when sorting is performed - * @param useSuffix whether or not a media type whose subtype contains a suffix should swap the entire subtype with the - * suffix */ - public ServerMediaType(List mediaTypes, String charset, boolean deprioritizeWildcards, boolean useSuffix) { + public ServerMediaType(List mediaTypes, String charset, boolean deprioritizeWildcards) { if (mediaTypes.isEmpty()) { this.sortedOriginalMediaTypes = new MediaType[] { MediaType.WILDCARD_TYPE }; } else { @@ -87,12 +84,6 @@ public int compare(MediaType m1, MediaType m2) { MediaType m = new MediaType(existing.getType(), existing.getSubtype(), charset); sortedMediaTypes[i] = m; } - // use the suffix type if it exists when negotiating the type - if (useSuffix) { - for (int i = 0; i < sortedMediaTypes.length; i++) { - sortedMediaTypes[i] = MediaTypeHelper.withSuffixAsSubtype(sortedMediaTypes[i]); - } - } // if there is only one media type, use it if (sortedMediaTypes.length == 1 && !(sortedMediaTypes[0].isWildcardType() || sortedMediaTypes[0].isWildcardSubtype())) { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java index 4109b8e1182a7..929017cdc6bd7 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java @@ -97,8 +97,7 @@ public void write(ResteasyReactiveRequestContext context, Object entity) throws } } else { writers = serialisers - .findWriters(null, entity.getClass(), MediaTypeHelper.withSuffixAsSubtype(producesMediaType.getMediaType()), - RuntimeType.SERVER) + .findWriters(null, entity.getClass(), producesMediaType.getMediaType(), RuntimeType.SERVER) .toArray(ServerSerialisers.NO_WRITER); } for (MessageBodyWriter w : writers) { 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 d8b8aa906779a..f8aedea78f0de 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 @@ -367,7 +367,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, // when negotiating a media type, we want to use the proper subtype to locate a ResourceWriter, // hence the 'true' for 'useSuffix' serverMediaType = new ServerMediaType(ServerMediaType.mediaTypesFromArray(method.getProduces()), - StandardCharsets.UTF_8.name(), false, true); + StandardCharsets.UTF_8.name(), false); } if (method.getHttpMethod() == null) { //this is a resource locator method @@ -387,8 +387,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, } else if (rawEffectiveReturnType != Void.class && rawEffectiveReturnType != void.class) { List> buildTimeWriters = serialisers.findBuildTimeWriters(rawEffectiveReturnType, - RuntimeType.SERVER, Collections.singletonList( - MediaTypeHelper.withSuffixAsSubtype(MediaType.valueOf(method.getProduces()[0])))); + RuntimeType.SERVER, MediaTypeHelper.toListOfMediaType(method.getProduces())); if (buildTimeWriters == null) { //if this is null this means that the type cannot be resolved at build time //this happens when the method returns a generic type (e.g. Object), so there diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java index 1d2bea0c74983..a77db34a0d847 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java @@ -131,8 +131,9 @@ public void setResource(RuntimeResource runtimeResource, MediaType mediaType) { } public void setupServerMediaType() { - MediaTypeHelper.sortByQSWeight(mtsWithParams); // TODO: this isn't completely correct as we are supposed to take q and then qs into account... - serverMediaType = new ServerMediaType(mtsWithParams, StandardCharsets.UTF_8.name(), true, false); + // TODO: this isn't completely correct as we are supposed to take q and then qs into account... + MediaTypeHelper.sortByQSWeight(mtsWithParams); + serverMediaType = new ServerMediaType(mtsWithParams, StandardCharsets.UTF_8.name(), true); } } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java index 2a89c7b1f4c1d..d668916b5851d 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java @@ -15,7 +15,6 @@ import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.ReaderInterceptor; import org.jboss.logging.Logger; -import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; import org.jboss.resteasy.reactive.server.core.ServerSerialisers; import org.jboss.resteasy.reactive.server.jaxrs.ReaderInterceptorContextImpl; @@ -47,7 +46,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti String requestTypeString = requestContext.serverRequest().getRequestHeader(HttpHeaders.CONTENT_TYPE); if (requestTypeString != null) { try { - effectiveRequestType = MediaTypeHelper.withSuffixAsSubtype(MediaType.valueOf(requestTypeString)); + effectiveRequestType = MediaType.valueOf(requestTypeString); } catch (Exception e) { throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build()); }