Details
-
Patch
-
Resolution: Unresolved
-
Major
-
None
-
3.6.2.Final
-
None
Description
I came across a need to override @Consumes annotation and though that custom httpHeaders would do the trick.
One cannot add these currently, but I had added earlier such feature to ClientInvoker and ProxyBuilder via ProxyConfig as shown below.
package org.jboss.resteasy.client.jaxrs; import java.util.Map; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; public class ProxyConfig { private final ClassLoader loader; private Map<String, Object> properties; private MultivaluedMap<String, Object> httpHeaders; private MediaType defaultConsumes; private MediaType[] defaultProduces; @Deprecated public ProxyConfig(ClassLoader loader, MediaType defaultConsumes, MediaType... defaultProduces) { this(loader, null, null, defaultConsumes, defaultProduces); } public ProxyConfig(ClassLoader loader, Map<String, Object> properties, MultivaluedMap<String, Object> httpHeaders, MediaType defaultConsumes, MediaType... defaultProduces) { this.loader = loader; this.httpHeaders = httpHeaders; this.properties = properties; this.defaultConsumes = defaultConsumes; this.defaultProduces = defaultProduces; } public ClassLoader getLoader() { return loader; } public Map<String, Object> getProperties() { return this.properties; } public MediaType getDefaultConsumes() { return defaultConsumes; } public MediaType[] getDefaultProduces() { return defaultProduces; } public MultivaluedMap<String, Object> getHttpHeaders() { return this.httpHeaders; } }
Then I noticed that for some reason the MediaType is resolved to either defaultConsumes or to the @Consumes annotation (doesn't work without either of them currently) and the one I gave as HttpHeaders.CONTENT_TYPE is neglected.
The magic happened inside ProcessorFactory where the of was course no reference to HttpHeaders that I'd just patched in.
if (this.httpHeaders != null) { clientInvocationBuilder.getHeaders().getHeaders().putAll( this.httpHeaders); }
By adding the following method I managed to change the preference so that the is a case specific MediaType declared (multipart/mixed with a custom boundary for instance) is preferred over the annotations+fallback mediatype.
@@ -7,6 +7,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.Arrays; +import java.util.Optional; import java.util.Stack; import javax.ws.rs.BeanParam; @@ -19,7 +20,9 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import org.jboss.resteasy.annotations.Form; import org.jboss.resteasy.client.ClientURI; @@ -33,6 +36,7 @@ import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.webtarget.MatrixParamProcessor; import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.webtarget.PathParamProcessor; import org.jboss.resteasy.client.jaxrs.internal.proxy.processors.webtarget.QueryParamProcessor; +import org.jboss.resteasy.core.Headers; import org.jboss.resteasy.util.FindAnnotation; import org.jboss.resteasy.util.MediaTypeHelper; @@ -46,6 +50,11 @@ public static Object[] createProcessors(Class declaringClass, Method method, ClientConfiguration configuration, MediaType defaultConsumes) { + return createProcessors(declaringClass, method, configuration, defaultConsumes, new Headers<>()); + } + + public static Object[] createProcessors(Class declaringClass, Method method, ClientConfiguration configuration, MediaType defaultConsumes, MultivaluedMap<String, Object> httpHeaders) + { Object[] params = new Object[method.getParameterTypes().length]; for (int i = 0; i < method.getParameterTypes().length; i++) { @@ -56,7 +65,7 @@ genericType = getTypeArgument((TypeVariable)genericType, declaringClass, method.getDeclaringClass()); } AccessibleObject target = method; - params[i] = ProcessorFactory.createProcessor(declaringClass, configuration, type, annotations, genericType, target, defaultConsumes, false); + params[i] = ProcessorFactory.createProcessor(declaringClass, configuration, type, annotations, genericType, target, defaultConsumes, httpHeaders, false); } return params; } @@ -70,9 +79,17 @@ } public static Object createProcessor(Class<?> declaring, + ClientConfiguration configuration, Class<?> type, + Annotation[] annotations, Type genericType, AccessibleObject target, MediaType defaultConsumes, + boolean ignoreBody) + { + return createProcessor(declaring, configuration, type, annotations, genericType, target, defaultConsumes, null, ignoreBody); + } + + public static Object createProcessor(Class<?> declaring, ClientConfiguration configuration, Class<?> type, Annotation[] annotations, Type genericType, AccessibleObject target, MediaType defaultConsumes, - boolean ignoreBody) + MultivaluedMap<String, Object> httpHeaders, boolean ignoreBody) { Object processor = null; @@ -142,7 +159,9 @@ } else if (!ignoreBody) { - MediaType mediaType = MediaTypeHelper.getConsumes(declaring, target); + MediaType mediaType = Optional.ofNullable(httpHeaders).map(headers -> headers.getFirst(HttpHeaders.CONTENT_TYPE)).map(contentType -> + contentType instanceof String ? MediaType.valueOf((String) contentType) : (MediaType) contentType + ).orElseGet(() -> MediaTypeHelper.getConsumes(declaring, target)); if(mediaType == null) mediaType = defaultConsumes; if (mediaType == null)