users@jersey.java.net

[Jersey] Re: Client config (?) or other databinding problems in composition context

From: Michael Iles <michael.iles_at_gmail.com>
Date: Tue, 14 Jan 2014 22:38:25 -0500

FWIW I'm fine with the META-INF/services auto discovery... my problem
is that Jersey doesn't give me a way to access the Jackson provider
that it auto-discovers so that I can configure it. If Jersey allowed
me to get a handle to the provider that it discovered then I could
call `setMapper(...)` on the provider and I wouldn't have to munge the
Jackson provider jar.

Mike.

On 14 January 2014 18:46, Jack Lista <jackalista_at_gmail.com> wrote:
> OK, I *think* I sorted this out, since there seems to be much confusion
> about configuration, I'll post what I found and hopefully this will clarify
> things for the next poor sap who comes along.
>
> I tried various mvn dependencies (see my first email on this subject for the
> initial 2 jackson dep's, for data-bind and annotations) and found that if I
> just use the provider dep from the jackson github site I have *only* jackson
> json jars (6 of them), and all from the right version (2.3.0 in my case). I
> have another dep for moxy, and if I add that, then I see moxy jars in
> WEB-IN/lib, but as long as I use only the dep listed here, I get only
> jackson 2.3.0.
>
> From here:
>
> https://github.com/FasterXML/jackson-jaxrs-providers
>
> <dependency>
> <groupId>com.fasterxml.jackson.jaxrs</groupId>
> <artifactId>jackson-jaxrs-json-provider</artifactId>
>
> <version>${jackson.version}</version>
> </dependency>
>
> I have been concerned about the fact that I was not using any "Features"
> related to JSON (but it was working anyway...), and also because moxy is the
> default I was a bit worried that we might be using moxy if not providing any
> configuration at all, which I wasn't. However, I found a notice on the
> Jackson github site above that says that the Jackson (2.2 onward) provider
> performs (some sort of) auto-registration.
>
> The 6 jars produced by the above dependency are these:
>
> jackson-annotations-2.3.0.jar
> jackson-core-2.3.0.jar
> jackson-databind-2.3.0.jar
> jackson-jaxrs-base-2.3.0.jar
> jackson-jaxrs-json-provider-2.3.0.jar
> jackson-module-jaxb-annotations-2.3.0.jar
>
> It seems I'm using Jackson 2.3.0, no? With only that above json dep in my
> pom.xml none of the moxy jars appear to be present so I think I am safely
> using jackson. Please correct me if I'm wrong, you don't need to be
> polite! ;)
>
> I was wondering if the reason that Jackson auto-registers itself is related
> to the current discussion about META-INF services. Does anyone know if
> these two things are related? I've seen comments about how this META-INF
> stuff is breaking some integrations, but I'm not clear on the details. The
> gist of those conversations seems to be that the META-INF stuff should be
> removed, and that Tatu (Jackson author) will do this at some point. Should
> I then expect the auto registration I'm currently enjoying to stop working
> or are these two things not related? If anyone is clear about this stuff
> (I'm obviously far from clear) I'd love to hear from you...
>
> --j
>
>
> On Mon, Jan 13, 2014 at 5:06 PM, Jack Lista <jackalista_at_gmail.com> wrote:
>>
>> I got server side log file tracing turned on, it turns out that in
>> addition to the properties you need to set that I mentioned in my previous
>> post, you also have to register the LoggingFilter. I added this to my
>> application sublass and I now get *minor* amounts of trace info showing up:
>>
>> import import org.glassfish.jersey.filter.LoggingFilter;
>> ...
>> register(LoggingFilter.class);
>>
>>
>> I also tried regsitering like this:
>>
>> import import org.glassfish.jersey.filter.LoggingFilter;
>> import javax.ws.rs.container.ContainerRequestFilter;
>> import javax.ws.rs.container.ContainerResponseFilter;
>> ...
>> register(LoggingFilter.class, ContainerRequestFilter.class).
>> register(LoggingFilter.class, ContainerResponseFilter.class);
>>
>> The effect appears the same with both means of registering the logging
>> filter. Unfortunately, none of the tracing, even at the VERBOSE level of
>> detail, is telling me what JSON marshalling / unmarshalling is being used.
>> I have it set to verbose, but that's not very verbose in my view, it's just
>> giving me a little bit about the HTTP request/response. In fact, the
>> runtime is barely even mentioning JSON beyond what's in accept headers
>> (request) and content type (response). On the response side, this is all I
>> see:
>>
>> Jan 13, 2014 4:11:09 PM org.glassfish.jersey.filter.LoggingFilter log
>> INFO: 3 * Server responded with a response on thread http-bio-8080-exec-6
>> 3 < 201
>> 3 < Content-Type: application/json
>> 3 < Location: http://blahblahblah...
>>
>> There's also mention of the accept header in the request tracing:
>>
>> 4 > accept: application/json
>>
>> That's it, no other mention of JSON in any form. How do I get the runtime
>> to tell me what JSON infrastructure I'm using?? Is there a different means
>> of registering the LoggingFilter that will make it spit out more info?
>>
>> I am getting bi-directional databinding, I can serialize my POJOs to JSON
>> and can deserialize them back into java objects, but I want to see what JSON
>> processing I'm using, as I haven't registered any JSON provider or feature,
>> all I did was put the 2.3.1 Jackson dependencies in my pom.xml. I want to
>> do a sanity check on what I'm doing and make sure I'm not using a horked
>> configuration. How do I get more info on my JSON configuration?
>>
>> I tried registering the following in my App (ResourceConfig) subclass, but
>> I'm explicitly *not* using either of these, as they both threw exceptions
>> when I registered them (individually, I didn't register them both at once):
>>
>> ...
>> register(JacksonFeature.class);
>> register(MoxyJsonFeature.class);
>>
>> I'd like to figure out how I can validate that my JSON processing stuff is
>> properly configured, but so far I can't seem to get any visibility into it.
>> How do you get more info on this? Is there deeper tracing? Is there some
>> other means?
>>
>> You know how you can set a flag in hibernate and you get more gory detail
>> on the SQL it's using than you could ever want? *That's* what I want here,
>> some module is marshaling this stuff and unmarshaling it and I want to turn
>> on logging in that module so I can see what module it is and what's going
>> on... How do you do that?
>>
>> Thanks...
>>
>>
>> On Mon, Jan 13, 2014 at 3:24 PM, Jack Lista <jackalista_at_gmail.com> wrote:
>>>
>>> Hi Jakub, Jersey folks,
>>>
>>> I'm trying to turn on server side log file tracing to see what JSON
>>> databinding I'm using and am having trouble finding out how to successfully
>>> get actual logs to show up in a log file.
>>>
>>> I set these properties in my Application class:
>>>
>>> property("jersey.config.server.tracing", "ALL").
>>> property("jersey.config.server.tracing.threshold", "TRACE");
>>>
>>> Next I got an error related to headers buffer space, so I added the
>>> following to my tomcat's server.xml:
>>>
>>> <Connector port="8080" protocol="HTTP/1.1"
>>> connectionTimeout="20000"
>>> maxHttpHeaderSize="16384" <------------I added
>>> this, and the error stopped
>>> redirectPort="8443" />
>>>
>>> I'm pretty sure now that logging/tracing is now turned on, but I still
>>> don't see anything. Where is this logging supposed to show up? I'm not
>>> seeing it in catalina.out, is this stuff directed to a different log file?
>>>
>>> I've seen chapter 19 (Tracing and Monitoring) here:
>>>
>>>
>>> https://jersey.java.net/documentation/latest/monitoring_tracing.html#tracing
>>>
>>> It says that that there's a "dedicated logger" for java for server side
>>> log file tracing, but what do you actually have to do to make it log things?
>>> I have been scouring the web for details and there are a few pages but they
>>> all seem to be relevant to Jersey 1.x and don't seem applicable. What do
>>> you have to do to get the trace info to show up in a server side log file?
>>>
>>>
>>> On Thu, Jan 9, 2014 at 8:53 AM, Jakub Podlesak
>>> <jakub.podlesak_at_oracle.com> wrote:
>>>>
>>>> Hi Jack,
>>>>
>>>> ad 1) it is hard to tell from the information you provided.
>>>> Anyway, you should be able to determine the effective worker
>>>> used
>>>> if you set Jersey’s server side config property,
>>>> jersey.config.server.tracing,
>>>> to “ALL”. Then the actual worker used at runtime should get
>>>> logged.
>>>>
>>>> ad 2) i guess this is rather a question for Jackson mailing list, if it
>>>> turns out one of the Jackson
>>>> providers is used and the annotation is not mandated. Let’s
>>>> clarify the first thing first.
>>>>
>>>> Cheers,
>>>>
>>>> ~Jakub
>>>>
>>>>
>>>> On 08 Jan 2014, at 17:53, Jack Lista <jackalista_at_gmail.com> wrote:
>>>>
>>>> And yes, your more compact syntax works nicely, thank you very much! If
>>>> you wouldn't mind, would you please answer those two dumb questions about
>>>> 1.) which databinding I'm actually using and 2.) the question about
>>>> @JsonIgnore?
>>>>
>>>> Much thanks sir...
>>>>
>>>> -=j=-
>>>>
>>>>
>>>> On Wed, Jan 8, 2014 at 8:20 AM, Jack Lista <jackalista_at_gmail.com> wrote:
>>>>>
>>>>> Ah, yes! Sweet! So *that's* how you submit a generic type to this
>>>>> infrastructure!! I had stumbled across something very similar, although a
>>>>> bit more long winded, as the last thing I tried last night, but I just
>>>>> happened across it based on a comment of the guy I'm working with on this
>>>>> and I tried it and it actually then gave me my wrapper envelope back with my
>>>>> domain class(es) inside it. Here's the syntax I tried last night which
>>>>> worked (& I'm going to try your more compact form immediately):
>>>>>
>>>>> GenericType<ResponseEnvelope<FooBar>> fooResponseEnvType = new
>>>>> GenericType<ResponseEnvelope<FooBar>>() {};
>>>>>
>>>>> // then pass fooResponseEnvType to the get(...) method like so:
>>>>>
>>>>> ResponseEnvelope<FooBar> envelope4ReuseMkt =
>>>>> client.target("http://localhost:8080/v1.1/rs")
>>>>> .path("foobar")
>>>>> .path(fooBarId.toString())
>>>>>
>>>>> .request(MediaType.APPLICATION_JSON_TYPE)
>>>>> .get(fooResponseEnvType);
>>>>>
>>>>> Thanks so much for your comment, however, as your code is much more
>>>>> compact which I like. Where, pray tell, is this stuff documented? Almost
>>>>> *everyone* is using domain objects (or DTOs, etc.) with these services, so
>>>>> the examples with simple String data types aren't representative of the
>>>>> techniques needed to work with domain objects, generic types and other
>>>>> things commonly found in enterprise environments (like the GenericType
>>>>> utility class you pointed out). We have a pretty crazy domain model, so I
>>>>> am going to need to get much more deeply into things like this, where is
>>>>> this GenericType utility discussed, beyond a javadoc?
>>>>>
>>>>> I would also *really* love to understand what such facilities exist,
>>>>> how they're intended to be used, what kids of functionality is currently
>>>>> support and even, if you guys know, what direction things are headed in.
>>>>> I've been over (I think) most of the
>>>>> https://jersey.java.net/documentation/latest... site but I haven't found
>>>>> discussion of things like GenericType, sorry if I'm being dense but can you
>>>>> point that out? (Thanks again.)
>>>>>
>>>>> While I have your ear, can you answer two relatively simple questions?
>>>>> My services are working when I don't explicitly register any JSON Features
>>>>> at all, but I do have these mvn dependencies in my pom.xml:
>>>>>
>>>>>
>>>>> <dependency>
>>>>> <groupId>com.fasterxml.jackson.core</groupId>
>>>>> <artifactId>jackson-databind</artifactId>
>>>>> <version>${jackson.version}</version>
>>>>> </dependency>
>>>>>
>>>>> <dependency>
>>>>> <groupId>com.fasterxml.jackson.core</groupId>
>>>>> <artifactId>jackson-annotations</artifactId>
>>>>> <version>${jackson.version}</version>
>>>>> </dependency>
>>>>>
>>>>> What JSON databinding am I using? If I explicitly enable the
>>>>> JacsonFeature, I get very different behavior (stackoverflow errors).
>>>>>
>>>>> The second dumb question is, is the @JsonIgnore annotation in domain
>>>>> classes still how you are supposed to prevent recursive stackoverflow JSON
>>>>> serialization errors? I ask because if I explicitly enable the
>>>>> JacksonFeature as I described in my post, I would assume that I am
>>>>> definitely using Jackson but the @JsonIgnore annotations within my domain
>>>>> classes appear to be ignored themselves and I suffer stackoverflow errors.
>>>>> We have a very complex domain model so I want to stay on top of the best
>>>>> techniques for managing domain classes that have a lot of relationships
>>>>> among them.
>>>>>
>>>>> Thanks Jakub, appreciate your help *immensely*!
>>>>>
>>>>> -=j=-
>>>>>
>>>>>
>>>>>
>>>>> On Wed, Jan 8, 2014 at 5:30 AM, Jakub Podlesak
>>>>> <jakub.podlesak_at_oracle.com> wrote:
>>>>>>
>>>>>> Hi Jack,
>>>>>>
>>>>>> Please try to use the following type when reading the entity:
>>>>>>
>>>>>> ResponseEnvelope<FooBar> envelope = svcResponse.readEntity(new
>>>>>> javax.ws.rs.core.GenericType<ResponseEnvelope<FooBar>>(){});
>>>>>>
>>>>>> Does it help?
>>>>>>
>>>>>> ~Jakub
>>>>>>
>>>>>>
>>>>>> On 07 Jan 2014, at 22:05, Jack Lista <jackalista_at_gmail.com> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I'm trying to get a composition working in which I'm having trouble
>>>>>> getting my entity back from the Response even though the actual service
>>>>>> request seems to have succeeded. I'm using Jersey 2.5.1 and am using the
>>>>>> client API to have one service call another 2 services and then do some
>>>>>> processing based on the results of the 2 composed services.
>>>>>>
>>>>>> I'm having no trouble getting the two services being composed to work,
>>>>>> marshaling the POJO service payload as JSON. If I call either service in a
>>>>>> browser they both work and spit out the appropriate JSON content.
>>>>>> Additionally, when I call them from within the composing service, it appears
>>>>>> that the calls have succeeded. Printing the Response via a logger shows the
>>>>>> following:
>>>>>>
>>>>>> svcResponse: InboundJaxrsResponse{ClientResponse{method=GET,
>>>>>> uri=http://localhost:8080/v1.1/rs/foobar/1, status=200, reason=OK}}
>>>>>>
>>>>>> Additionally, if I call (Response) svcResponse.hasEntity() I get a
>>>>>> result of true.
>>>>>>
>>>>>> However, when I try to call readEntity(), I get a class cast
>>>>>> exception:
>>>>>>
>>>>>> java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast
>>>>>> to com.baz.domain.FooBar
>>>>>>
>>>>>>
>>>>>> A few details of my implementation that may be relevant are that we
>>>>>> are using an application class that subclasses ResourceConfig (without a
>>>>>> web.xml). This app class also uses the following package scanning call to
>>>>>> find our annotated classes:
>>>>>>
>>>>>> packages("com.baz.rest");
>>>>>>
>>>>>> The POJO domain model classes being returned are not in that package,
>>>>>> as the above snippet of stacktrace shows, but they are being marshaled to
>>>>>> JSON without issue, so I suspect that's not a problem.
>>>>>>
>>>>>> I'm not registering any JSON provider, but have the following in my
>>>>>> pom.xml which seems to have enabled Jackson:
>>>>>>
>>>>>> <dependency>
>>>>>> <groupId>com.fasterxml.jackson.core</groupId>
>>>>>> <artifactId>jackson-databind</artifactId>
>>>>>> <version>${jackson.version}</version>
>>>>>> </dependency>
>>>>>>
>>>>>> <dependency>
>>>>>> <groupId>com.fasterxml.jackson.core</groupId>
>>>>>> <artifactId>jackson-annotations</artifactId>
>>>>>> <version>${jackson.version}</version>
>>>>>> </dependency>
>>>>>>
>>>>>> I have also tried using the following in my pom.xml but it seems to
>>>>>> make no difference whether it's present or not:
>>>>>>
>>>>>> <dependency>
>>>>>> <groupId>org.glassfish.jersey.media</groupId>
>>>>>> <artifactId>jersey-media-json-jackson</artifactId>
>>>>>> </dependency>
>>>>>>
>>>>>> It is necessary for compilation if I explicitly register the
>>>>>> JacksonFeature, but seems to have no effect otherwise.
>>>>>>
>>>>>> I'm using a simple unadorned client created in the composing service
>>>>>> (the one that is calling the other two services):
>>>>>>
>>>>>> Client client = ClientBuilder.newClient();
>>>>>>
>>>>>> I'm also creating a webTarget and an invocation in the following
>>>>>> manner:
>>>>>>
>>>>>> WebTarget webTarget = client.target("http://localhost:8080/v1.1/rs");
>>>>>> Invocation.Builder invocationBuilder = webTarget
>>>>>> .path("foobar")
>>>>>> .path(foobarId.toString())
>>>>>> .request(MediaType.APPLICATION_JSON_TYPE);
>>>>>> Response svcResponse = invocationBuilder.get(Response.class);
>>>>>>
>>>>>>
>>>>>> I've tried explicitly enabling Jackson by adding the following call in
>>>>>> my application subclass:
>>>>>>
>>>>>> register(JacksonFeature.class);
>>>>>>
>>>>>> and adding a similar call in the client code like this:
>>>>>>
>>>>>> Client client =
>>>>>> ClientBuilder.newClient().register(JacksonFeature.class);
>>>>>>
>>>>>> However, when I configure the server and client that way, the Jackson
>>>>>> databinding doesn't respect the @JsonIgnore annotations in our domain model
>>>>>> and suffers a stackoverflow error. Without that explicit configuration, I
>>>>>> get nice decent sized chunks of JSON which do respect the @JsonIgnore
>>>>>> annotations in our domain model. I've also tried to switch to the Moxy JSON
>>>>>> code by adding "register(MoxyJsonFeature.class);" to the application class
>>>>>> and calling "Client client =
>>>>>> ClientBuilder.newClient().register(MoxyJsonFeature.class);" in the client
>>>>>> code but this simply results in 500 errors even when calling the 2 composed
>>>>>> services in a browser. When I do no configuration in either the application
>>>>>> subclass or in the client code in the calling service as originally shown
>>>>>> above, I get the proper JSON representation in a browser from each of the
>>>>>> two composed services.
>>>>>>
>>>>>> The problem occurs when I try to access the entity from the response.
>>>>>> This first call succeeds:
>>>>>>
>>>>>> ResponseEnvelope<FooBar> envelope =
>>>>>> svcResponse.readEntity(ResponseEnvelope.class);
>>>>>>
>>>>>> However, I get the class cast exception referencing a LinkedHashMap
>>>>>> (?!?) when I try the following call:
>>>>>>
>>>>>> FooBar fooBar = envelope.getPayload();
>>>>>>
>>>>>> Perhaps the problem is related to our envelope class that has a
>>>>>> generic domain class embedded in it? However, Jackson has no trouble
>>>>>> marshaling the ResponseEnvelope to JSON, so why would it fail in the
>>>>>> opposite direction?
>>>>>>
>>>>>> I'm utterly confused (obvious? lol), any help would be *greatly*
>>>>>> appreciated!
>>>>>>
>>>>>> --j
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>