Discussion:
Should the JAX-RS Client pay attention to ContextResolver[s]?
exabrial12
2018-10-26 16:38:09 UTC
Permalink
I'm having trouble finding whether or not this is in the specification or
not, but lets say I want the JAX-RS client to use a custom JAXB Context that
I universally manage with CDI:
@ApplicationScopedpublic class JaxbContextResolver implements
ContextResolver { @Inject private JAXBContext jaxbContext; @Override
public JAXBContext getContext(Class<?> type) { return jaxbContext; }}
I then call an endpoint that requires XML:
***@Injectprivate JaxbContextResolver jaxbContextResolver;... Client client
= ClientBuilder.newClient(); client.register(jaxbContextResolver);
client.target("https://example.com").request("application/xml").post(Entity.entity(payload,
"application/xml"), Response.class);..
The problem I'm having is that the jax-rs client is never calling my
jaxbContextResolver.getContext() method. Are ContextResolver[s] supported on
the jax-rs client or is that not in the spec? I did notice that CXF attempts
to use a ContextResolver but it's not finding mine:
https://github.com/apache/cxf/blob/master/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java#L479




--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Romain Manni-Bucau
2018-10-26 19:48:56 UTC
Permalink
Hello

AFAIK cxf does not support it client side and spec is silent on it even if
the api is always associated with server references ("resources"). Maybe
open a feature request, no reason the clientproviderfactory cant support it.

Now for your issue you can wire it in the provider when creating your
client so no real need of the resolver ;)
Post by exabrial12
I'm having trouble finding whether or not this is in the specification or
not, but lets say I want the JAX-RS client to use a custom JAXB Context that
@ApplicationScopedpublic class JaxbContextResolver implements
public JAXBContext getContext(Class<?> type) { return jaxbContext; }}
= ClientBuilder.newClient(); client.register(jaxbContextResolver);
client.target("https://example.com
").request("application/xml").post(Entity.entity(payload,
"application/xml"), Response.class);..
The problem I'm having is that the jax-rs client is never calling my
jaxbContextResolver.getContext() method. Are ContextResolver[s] supported on
the jax-rs client or is that not in the spec? I did notice that CXF attempts
https://github.com/apache/cxf/blob/master/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java#L479
--
http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
exabrial12
2018-10-26 20:22:08 UTC
Permalink
Thanks for the information, I'll take a look at ClientProviderFactory and see
what would be involved.


I didn't understand what you mean though by "wire it in the provider"
though. Is there a way to specify a JAXB Context on the client?



--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Romain Manni-Bucau
2018-10-27 06:19:39 UTC
Permalink
The messagebody reader/writer are trivial to impl if you have the context
so yes, just dont try to reuse cxf but just jaxrs here. Cxf logic is mainly
grabbing the jaxbcontext so if you have it no nees of that cxf logic.

You register you provider(s) and cxf should let it be taken cause user
providers are higher priority for the same media type.
Post by exabrial12
Thanks for the information, I'll take a look at ClientProviderFactory and see
what would be involved.
I didn't understand what you mean though by "wire it in the provider"
though. Is there a way to specify a JAXB Context on the client?
--
http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
exabrial12
2018-10-29 14:41:48 UTC
Permalink
Post by Romain Manni-Bucau
You register you provider(s) and cxf should let it be taken cause user
providers are higher priority for the same media type.
Got it, so create our own handlers for XML.
Post by Romain Manni-Bucau
The messagebody reader/writer are trivial to impl if you have the context
so yes, just dont try to reuse cxf but just jaxrs here. Cxf logic is mainly
grabbing the jaxbcontext so if you have it no nees of that cxf logic.
Apologies, I'm not understanding what you're saying.

Given this:
https://github.com/apache/cxf/blob/master/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java#L479

I would suspect the "correct" way to fix it would be to to simply put all of
the Providers into the CXF MessageContext somehow?

Or, if you can tell me the best place to do it, I'll see if I can put a
patch together, just try to be as specific as possible. Thank you!



--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Romain Manni-Bucau
2018-10-29 15:30:26 UTC
Permalink
Here what i has in mind:


public class MyClient {
private MyClient() {
// no-op
}

public static void main(final String[] args) throws JAXBException {
Client client = ClientBuilder.newClient();
try {
client.register(new
MyJaxbProvider<>(JAXBContext.newInstance(MyRoot.class)))
.target("http://foo.bar")
.request()
.get();
} finally {
client.close();
}
}

@XmlRootElement
public static class MyRoot {
// ...
}

// note: base impl, error handling + stream security to enhance etc
public static class MyJaxbProvider<T> implements
MessageBodyReader<T>, MessageBodyWriter<T> {
private final JAXBContext context;

public MyJaxbProvider(final JAXBContext context) {
this.context = context;
}

private boolean isJaxb(final Class<?> type) {
return type.isAnnotationPresent(XmlRootElement.class) ||
type.isAnnotationPresent(XmlType.class);
}

@Override
public boolean isReadable(final Class<?> type, final Type genericType,
final Annotation[] annotations,
final MediaType mediaType) {
return isJaxb(type);
}

@Override
public T readFrom(final Class<T> type, final Type genericType,
Annotation[] annotations,
final MediaType mediaType, final
MultivaluedMap<String, String> httpHeaders,
final InputStream entityStream)
throws WebApplicationException {
// customize the xml size etc if no other protection in
front - see AbsrtactJAXBProvider configureReader
try {
return
context.createUnmarshaller().unmarshal(StaxUtils.createXMLStreamReader(entityStream),
type).getValue();
} catch (final JAXBException e) {
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
}

@Override
public boolean isWriteable(final Class<?> type, final Type genericType,
final Annotation[] annotations,
final MediaType mediaType) {
return isJaxb(type);
}

@Override
public void writeTo(final T t, final Class<?> type, final Type
genericType,
final Annotation[] annotations, final
MediaType mediaType,
final MultivaluedMap<String, Object>
httpHeaders, final OutputStream entityStream)
throws WebApplicationException {
try {
context.createMarshaller().marshal(t,
StaxUtils.createXMLStreamWriter(entityStream));
} catch (final JAXBException e) {
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
}
}
}


Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> | Blog
<https://rmannibucau.metawerx.net/> | Old Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book
<https://www.packtpub.com/application-development/java-ee-8-high-performance>
Post by exabrial12
Post by Romain Manni-Bucau
You register you provider(s) and cxf should let it be taken cause user
providers are higher priority for the same media type.
Got it, so create our own handlers for XML.
Post by Romain Manni-Bucau
The messagebody reader/writer are trivial to impl if you have the
context
Post by Romain Manni-Bucau
so yes, just dont try to reuse cxf but just jaxrs here. Cxf logic is mainly
grabbing the jaxbcontext so if you have it no nees of that cxf logic.
Apologies, I'm not understanding what you're saying.
https://github.com/apache/cxf/blob/master/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java#L479
I would suspect the "correct" way to fix it would be to to simply put all of
the Providers into the CXF MessageContext somehow?
Or, if you can tell me the best place to do it, I'll see if I can put a
patch together, just try to be as specific as possible. Thank you!
--
http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
exabrial12
2018-10-29 15:32:28 UTC
Permalink
Actually, I just wrote my own MessageBodyReader/writer, annotated it with
@Provider, and it is _definitely not_ being invoked while using the JAXRS
client. Is that the expected behavior?

It *does* work if you call client.register(), but I thought anything
annotated @Provider was supposed to be picked up automatically.



--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Romain Manni-Bucau
2018-10-29 15:35:17 UTC
Permalink
Yep, except you instantiate yourself the client outside any container so
you are the one to pick it up ;)

Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> | Blog
<https://rmannibucau.metawerx.net/> | Old Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book
<https://www.packtpub.com/application-development/java-ee-8-high-performance>
Post by exabrial12
Actually, I just wrote my own MessageBodyReader/writer, annotated it with
@Provider, and it is _definitely not_ being invoked while using the JAXRS
client. Is that the expected behavior?
It *does* work if you call client.register(), but I thought anything
--
http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
exabrial12
2018-10-29 15:41:18 UTC
Permalink
So, currently I'm not instantiating it. I tried both managing it with CDI
(@ApplicationScoped AND @Provider), no management (Just annotating
@Provider) and it didn't get picked up automatically. The only thing that
worked was @ApplicationScoped it and calling client.register on the CDI
managed instance. Is that expected behavior?



--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Romain Manni-Bucau
2018-10-29 15:46:59 UTC
Permalink
yes

Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> | Blog
<https://rmannibucau.metawerx.net/> | Old Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book
<https://www.packtpub.com/application-development/java-ee-8-high-performance>
Post by exabrial12
So, currently I'm not instantiating it. I tried both managing it with CDI
@Provider) and it didn't get picked up automatically. The only thing that
managed instance. Is that expected behavior?
--
http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
exabrial12
2018-10-29 15:53:21 UTC
Permalink
So the @Provider annotation does nothing for the jaxrs client essentially. Is
this correct?



--
Sent from: http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Romain Manni-Bucau
2018-10-29 16:29:20 UTC
Permalink
yes

Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> | Blog
<https://rmannibucau.metawerx.net/> | Old Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book
<https://www.packtpub.com/application-development/java-ee-8-high-performance>
Post by exabrial12
this correct?
--
http://tomee-openejb.979440.n4.nabble.com/TomEE-Users-f979441.html
Loading...