Hi. Am 19.01.2015 um 15:20 schrieb Sergey Beryozkin: > Hi > On 19/01/15 13:57, Veit Guna wrote: >> Hi. >> >> I'm using CXF 3.0.3. >> I tried to register the provider via providers list and referencing it >> in the create() method of JAXRSClientFactory: >> >> List<Object> providers = new ArrayList<Object>(); >> // providers.add(new JacksonJaxbJsonProvider()); >> // providers.add(MultiPartWriter.class); >> // providers.add(MultiPartFeature.class); >> // providers.add(new MultiPartFeature()); >> >> I tried it the JAXRS way of specifying the class, but that didn't work. > > How do you mean ? Using JAX-RS 2.0 API ? Yes. I thought it might be the same like JAX-RS 2.0 API using the register() methods. But if that's not the same, I can live with it :).
> >> After looking at the source, I tried this one and >> this almost works for me: >> >> >> providers.add(MultiPartWriter.class.getConstructor(Providers.class)); >> >> When writing the MultiPart via client proxy the MultiPartWriter gets >> invoked and it does its job. >> BTW: is that the correct CXF-way to register a provider that needs Ctor >> injection or does this >> use an internal way? > > That is OK though is unusual. Having contexts injected into providers > via constructors is rare because people typically register custom > providers from Spring or the code, and besides, IMHO at least, it is > much simpler to inject a context via a setter or into a field. > > I think if you enable a Spring based auto-discovery on the CXF client > side then it will also work with a constructor based injection. > > I'll update the proxy client code to recognize providers registered as > Class too, which would be consistent with JAX-RS 2.0 Client API... The class comes from jersey. It seems they are using constructor injection within their providers at some places. It would be nice-to-have if the CXF client proxy could support registering via class as well. Will it also support constructor injection then as well ;)? Or is spring needed for that, too? Although I'm a big fan of spring on the server side, I'm trying to avoid it on the client side to keep it minimal. > >> >> Nevertheless I still have a problem with the rendered request. Although >> the body is correctly written, the >> Content-Type header seems "broken". It just contains "multipart/mixed" >> whereas it should contain something >> like "multipart/mixed; boundary='myboundary...". The effect is, that the >> jersey server complains about the >> missing start boundary - which is really missing. >> >> I tried the same Jersey MultiPart writer with Resteasy, and it seems to >> work fine. The correct header is sent to the jersey server >> including the boundary. So there seems something different with CXF. >> >> I debugged the MultiPartWriter and I can see, that the writeTo method >> sets the correct header to the headers map >> (MultivaluedMap<String, Object>) passed to the writeTo method. I guess >> that CXF doesn't take these headers into >> account when writing to the stream?! I don't even know, if that is the >> correct way of a MessageBodyWriter to set >> request headers. But as I mentioned before, with RestEasy the writer >> works. > > CXF uses its own mechanism to create the boundaries. In fact I'm not > sure you need to use the 3rd party provider for it, given that a > CXF-level support is very rich: > > http://cxf.apache.org/docs/jax-rs-multiparts.html > Yeah, I stumbled accross it. But the "problem" here is, that I'm using the client proxy that reflects the server API classes which contain the Jersey MultiPart in a method signature. So the client proxy expects, of course, a MultiPart object and a appropriate MessageBodyWriter (MultiPartWriter from jersey) to registered. > However, let me look into a possible issue here. > So I'm presuming the proxy has a @Consumes("multipart/mixed"), and > then a Jersey writer sets a new Content-Type with a specific boundary, > inside a writer, and it does not override the original Content-Type, > yes ? > Yes, @Consumes :). Yes. The Jersey MultiPartWriter takes the MultiPart (also Jersey's) and creates the needed boundaries for it. It sets the needed Content-Type header correctly as "multipart/mixed; boundary='.....'" on the headers map that is passed to the writeTo method (API) of the MessageBodyWriter. But it seems that this header doesn't make it into the request that is send to the server. The question here is: a) does CXF uses the headers that were passed to the MessageBodyWriter (and are probably modified by the writer) for creating the request? b) If not, is it per spec a correct way of a MessageBodyWriter to use the passed-in headers to manipulate/set the headers of the request? c) If not, what is the "correct" way for a MessageBodyWriter to set headers or the content-type of the request then? To be honest, I don't have a clue! Maybe you have :). Thanks for the quick reply! Veit > >> >> Any idea where the problem comes from? >> >> Regards, >> Veit >> >> Am 18.01.2015 um 14:09 schrieb Sergey Beryozkin: >>> Hi >>> >>> How do you register a provider ? And which CXF version is it ? I >>> expect a constructor based context injection to work, in CXF 3.0.3 at >>> least. >>> >>> Cheers, Sergey >>> On 17/01/15 10:26, Veit Guna wrote: >>>> Hi. >>>> >>>> I have a REST server API that uses Jersey for JAX-RS implementation >>>> (2.0). To upload files to the REST service, I use their MultiPart type >>>> within >>>> a server API method due to a (yet) missing JAX-RS standardization. >>>> >>>> Since Jersey doesn't offer a proxy-based client API (yet?), I want to >>>> use the nice CXF client proxy. I've added the jersey multipart jar to >>>> the client >>>> classpath as well. But when I invoke the upload method with the >>>> MultiPart parameter CXF complains about the missing MessageBodyWriter >>>> handling >>>> MultiPart. So that means, that CXF isn't picking up the provider >>>> automatically, right? So I've learned, I can register the provider per >>>> jaxrs:providers via >>>> spring xml file and also via create method. >>>> >>>> The problem is, that the Jersey MultiPart class expects a >>>> >>>> https://docs.oracle.com/javaee/6/api/javax/ws/rs/ext/Providers.html >>>> >>>> to be injected in the constructor. So registering the providers fails, >>>> because CXF can't instantiate the class correctly. >>>> So my questions is: is there a way to make CXF inject the Providers to >>>> the constructor? And if not, is there a way >>>> for me to get a reference to the Providers within the client so I can >>>> try to instantiate the MultiPart provider by myself? >>>> >>>> Thanks for your help! >>>> Veit >>>> >>>> >>> >> >
