From e398099c156171492514184a091803a77bd0c8a1 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Thu, 7 Apr 2022 23:35:56 -0400 Subject: [PATCH] fixed multipart support in both jersey/cxf --- pom.xml | 5 ++++ src/main/java/com/inteligr8/rs/Client.java | 9 ++++-- .../java/com/inteligr8/rs/ClientCxfImpl.java | 9 ++++-- .../com/inteligr8/rs/ClientJerseyImpl.java | 16 ++++------ .../inteligr8/rs/CxfMultipartProvider.java | 29 +++++++++++++++++++ 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/inteligr8/rs/CxfMultipartProvider.java diff --git a/pom.xml b/pom.xml index 97a590d..6395b00 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,11 @@ jackson-datatype-jsr310 2.12.2 + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey.version} + org.slf4j slf4j-api diff --git a/src/main/java/com/inteligr8/rs/Client.java b/src/main/java/com/inteligr8/rs/Client.java index a607652..06a6128 100644 --- a/src/main/java/com/inteligr8/rs/Client.java +++ b/src/main/java/com/inteligr8/rs/Client.java @@ -26,7 +26,7 @@ public abstract class Client { public final javax.ws.rs.client.Client getClient() { synchronized (this.sync) { if (this.client == null) - this.client = this.buildClient(null); + this.client = this.buildClient((AuthorizationFilter)null); } return this.client; @@ -48,7 +48,7 @@ public abstract class Client { * @param authFilter A dynamic authorization filter. * @return A pre-configured JAX-RS client (no URL) with the specified authorization. */ - public javax.ws.rs.client.Client buildClient(AuthorizationFilter authFilter) { + public final javax.ws.rs.client.Client buildClient(AuthorizationFilter authFilter) { JacksonJsonProvider provider = new JacksonJaxbJsonProvider(); if (this.getConfig().isWrapRootValueEnabled()) @@ -64,9 +64,14 @@ public abstract class Client { authFilter = this.getConfig().createAuthorizationFilter(); if (authFilter != null) clientBuilder.register(authFilter); + this.buildClient(clientBuilder); return clientBuilder.build(); } + + public void buildClient(ClientBuilder clientBuilder) { + // for extension purposes + } /** * @return A pre-configured JAX-RS target (client w/ base URL) with configured authorization. diff --git a/src/main/java/com/inteligr8/rs/ClientCxfImpl.java b/src/main/java/com/inteligr8/rs/ClientCxfImpl.java index 9e4f8f0..c28bbd7 100644 --- a/src/main/java/com/inteligr8/rs/ClientCxfImpl.java +++ b/src/main/java/com/inteligr8/rs/ClientCxfImpl.java @@ -9,7 +9,6 @@ import org.apache.cxf.BusFactory; import org.apache.cxf.jaxrs.client.JAXRSClientFactory; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl; -import org.apache.cxf.jaxrs.provider.MultipartProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -68,12 +67,14 @@ public abstract class ClientCxfImpl extends Client implements InitializingBean { List providersAndFilters = new LinkedList(); providersAndFilters.add(new JacksonJaxbJsonProvider()); providersAndFilters.add(new CxfLoggingFilter()); - providersAndFilters.add(new MultipartProvider()); + providersAndFilters.add(new CxfMultipartProvider()); if (authFilter == null) authFilter = this.getConfig().createAuthorizationFilter(); if (authFilter != null) providersAndFilters.add(authFilter); + + this.addProvidersAndFilters(providersAndFilters); // we can't use JAXRSClientFactory with a JAXRS client (duh!) // so we need to create a CXF client @@ -89,6 +90,10 @@ public abstract class ClientCxfImpl extends Client implements InitializingBean { return client; } + + public void addProvidersAndFilters(List providersAndFilters) { + // for extension purposes + } /** * This method retrieves a JAX-RS implementation of the specified API with diff --git a/src/main/java/com/inteligr8/rs/ClientJerseyImpl.java b/src/main/java/com/inteligr8/rs/ClientJerseyImpl.java index c35f646..d3735cf 100644 --- a/src/main/java/com/inteligr8/rs/ClientJerseyImpl.java +++ b/src/main/java/com/inteligr8/rs/ClientJerseyImpl.java @@ -1,10 +1,12 @@ package com.inteligr8.rs; +import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.ext.RuntimeDelegate; import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.proxy.WebResourceFactory; import org.glassfish.jersey.internal.RuntimeDelegateImpl; +import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -46,20 +48,14 @@ public abstract class ClientJerseyImpl extends Client implements InitializingBea this.logger.info("API Base URL: " + this.getConfig().getBaseUrl()); } - /** - * @param authFilter A post-configuration authorization filter. - * @return A JAX-RS client. - */ @Override - public javax.ws.rs.client.Client getClient(AuthorizationFilter authFilter) { - javax.ws.rs.client.Client client = super.getClient(authFilter); - + public void buildClient(ClientBuilder clientBuilder) { + clientBuilder.register(MultiPartFeature.class); + if (!this.getConfig().isPutBodyRequired()) { // allow PUT operations without body data - client.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); + clientBuilder.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); } - - return client; } /** diff --git a/src/main/java/com/inteligr8/rs/CxfMultipartProvider.java b/src/main/java/com/inteligr8/rs/CxfMultipartProvider.java new file mode 100644 index 0000000..dfedcfc --- /dev/null +++ b/src/main/java/com/inteligr8/rs/CxfMultipartProvider.java @@ -0,0 +1,29 @@ +package com.inteligr8.rs; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.ext.Provider; + +import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; +import org.apache.cxf.jaxrs.provider.MultipartProvider; + +@Consumes(MediaType.MULTIPART_FORM_DATA) +@Produces(MediaType.MULTIPART_FORM_DATA) +@Provider +public class CxfMultipartProvider extends MultipartProvider { + + @Override + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return MultipartBody.class.isAssignableFrom(type) || this.isReadable(type, genericType, annotations, mediaType); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return MultipartBody.class.isAssignableFrom(type) || this.isWriteable(type, genericType, annotations, mediaType); + } + +}