Supporting the registration of providers as Class types is now supported
on all the paths, not only via JAX-RS 2.0 Configurable.
The CR update directly in MBW does work on the server side, but is
broken on the client side, needs to be fixed next
Sergey
On 19/01/15 19:15, Veit Guna wrote:
Sounds great. I appreciate your help!
Cheers
Veit
On 19. Januar 2015 18:15:47 MEZ, Sergey Beryozkin <[email protected]> wrote:
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