On 19/01/15 17:11, Sergey Beryozkin wrote:
Hi
On 19/01/15 14:54, Veit Guna wrote:
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 :).

Well, proxy API is not a standard API, though I guess it would not be ok

Meant to say it would be OK...

if it accepted the provider registrations via JAX-RS 2.0 Configurable
API, perhaps sometime in the future it can be synced


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.


As I said I'll update the proxy API so that registering providers as
Classes will work; no Spring will be needed...




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 :).


Typically Content-Type would not be set from MBW but either from a filer
or WriterInterceptor. However setting it from MBW must also work; I
vaguely recall it was working fine on the server side but looks like
there's a sync issue on the client side - will have a look into it asap

Thanks, Sergey

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










--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Reply via email to