users@jersey.java.net

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

From: Jack Lista <jackalista_at_gmail.com>
Date: Fri, 17 Jan 2014 16:37:55 -0800

I see... that's frustrating. It seems odd that you can't do that
considering how much effort has been put into configuration facilities. So
it is the META-INF/services autodiscovery that is how Jackson is getting
registered? I have been wondering about that, it sounds like you think
that's what's happening in my case. I'm curious about your opinion because
I am honestly clueless, when it comes right down to it, but the moxy jars
aren't in my war so it couldn't be moxy. It's touchy, configuration-wise,
it seems but we've found a configuration that handles our domain model and
various uses of generics and whatnot, but damn, we spent a *long* time
getting there.

If the META-INF/services thing goes away I may have to revisit this, but
for now, we seem to be good. I wish I could get it to work by registering
the JacksonFeature but it completely ignores all the @JsonIgnore tags in
our domain model, and I haven't figured out how to change that so I guess
letting it auto-register itself is going to have to suffice. Any idea why
Jackson would ignore the @JsonIgnore tags when registered via the
JacksonFeature and would honor them when auto-registered? I would love to
know that as well...

In other news, I just tried using Links embedded in Responses and that's
really easy to use and works nicely from what I've seen so far, and that's
pretty cool, but I am still a bit in the dark WRT Jackson registration.
Thanks for your response...

--j


On Tue, Jan 14, 2014 at 7:38 PM, Michael Iles <michael.iles_at_gmail.com>wrote:

> 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
> >>>>>>
> >>>>>>
> >>>>>
> >>>>
> >>>>
> >>>
> >>
> >
>