FasterXML / jackson-jaxrs-providers

Multi-module project that contains Jackson-based "old" JAX-RS (ones under `javax.ws.rs`) providers for JSON, XML, YAML, Smile, CBOR formats
Apache License 2.0
111 stars 78 forks source link

JEE RestApplication - Weblogic - Unpredicatable behavior on which provider gets used #107

Open 99sono opened 6 years ago

99sono commented 6 years ago

We see the fowllowing.

In Weblogic, that uses Jersey to orchestrate rest web services, we can enable jackson to be used by.

  1. javax.ws.rs.core.Application extend this class and set the property proprties.put("jersey.config.server.disableMoxyJson", true);

  2. Include the jackson-jaxrs-providers

The problem now is the following. We have unpredicatable behavior in terms of which of the Jackson providers get used. In system tests, sometimes we see that the provider being used to render rest responses is:

com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider Sometimes it is: com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider

And this is very clear, when your rest web service uses as a response object a class that has JaxB annotations. Sometimes the fields are rendered in the JSON as they are declared in the class. Some times the jaxb annotation metadata is being used some times ignored.

So if you image you a field called: @XmlElement(name = "Field1") String field1;

The json is sometimes rendered as field1 and other times as Filed1.

To me this looks like this boils down to however jersey decides to configure itself. It goes hunting for classes that are providers or implemneting specific interfaces such as body writer and body readers, and then it is most likely chaos ruling your runtime echosystem.

I currently have no idea of what rest configuration is being activated, I just know it looks to be relatively random.

Are you aware of any approach by which it would be possible to say:

I have seen that most of the time the configuration that is active for me is the one with the JacksonJaxbJsonProvider .

Therefore, I have tried as an experiment to froce my rest services to be handled by the JacksonJsonProvider. To do this I tried

@Provider
@Consumes(MediaType.WILDCARD) // NOTE: required to support "non-standard" JSON variants
@Produces(MediaType.WILDCARD)
@Specializes
public class acksonRestProviderSpecialization extends JacksonJaxbJsonProvider{
 public Wm6JacksonRestProviderSpecialization() {
        super(JacksonJsonProvider.BASIC_ANNOTATIONS);
        LOGGER.info("{} is being created,", this.getClass().getCanonicalName());
    }

}

to see if I could knock out from CDI the JacksonJaxbJsonProvider.

But apparently Jersey still finds ount JacksonJaxbJsonProvider and still manages to use it.

Does anyone know how to ensure that the rest service provider used is the JacksonJaxbJsonProvider rather than the JacksonJsonProvider?

99sono commented 6 years ago

If I make the experiment making the JacksonJaxbJsonProvider do nothing except extend the JacksonJsonProvider. And in the JacksonJsonProvider sometimes we support both annotations sometimes only the JACKSON annotations - we get deterministic results.

It would appear.

So this really appears to be an issue of configuration. The Jackson proviers package is providing two solutions of configuration that get automatically detected by jersey.

But we lack some sort of means of taking control of which of the providers should be active.

Is there an answer to this?

When automatica configuration is in place, doe we have any means of taking control of which provider should take the leading role?

I am not sure how the configuration is working in jersey:

I just see if I debug that the class: org.glassfish.jersey.message.internal.MessageBodyFactory

has a massive pool of resources to play with and some of them look like they offer redundant services. Our configuration is as a result ambiguous and does not provide determinism.

I would really appreciate if someone is aware of how to properly configure JEE applicaton servers to use automatic configuration in terms of the resources deployed. But then in terms of th bodry writers and readers to make the hole process detemrinistic if omre than one contender exist for the roe.

99sono commented 6 years ago

The only solution I could find thus was was taking form the JAR one of the providers - or likewise rewriting one of the providers to be logically equivalent to the other.

This in short prooves that puting in a JAR library two candidate provides that can picked up automatically is not the most ideal thing to do, as it causes "auto-configuration" chaos.

It would have been better, if the JAX-RS provider was written in such a way that both providers are disabled / not discoverable by the REST server and a third package to activate either one or the other configuration.

As it stands right now, the jackson-providers package by default makes rest service behavior unstable for applications that serialize classes hold JAXB annotations.

I would welcome some feedback on these conclusions and any tip on how to overcome this problem in jersey without needing to work-around the library implementation wuld be useful.

Kindest regards.

cowtowncoder commented 6 years ago

Isn't this more a question for Weblogic maintainers? I can't think of much Jackson providers can do to the general problem of classpath containing multiple implementations (which is somewhat common problem with SPI approach for all kinds of pluggable components). Usually JAX-RS implementations have a mechanism for registering specific implementation; and it is a good idea not to rely on existence of just one implementation in classpath since it is easy to get unexpected additions that way (transitive dependencies tend to pull additional jars, and sometimes version upgrade of a dependency can lead to such changes).

If you can not get help from Weblogic forums, Jackson user list:

https://groups.google.com/forum/#!forum/jackson-user

is probably a good resource: not many developers follow issue trackers and it is easier to get help for usage questions there.

99sono commented 6 years ago

Perfect. Thanks a lot for the feedback.

But just to be clear. The @Provider annotation which is part of the JAX-RS spec is only about allowing an implemnetaton RestEasy or Jersey to automatically find JAX-RS releated resources of interest:

QUOTE documentation: "

The @Provider annotation is used for anything that is of interest to the JAX-RS runtime, such as MessageBodyReader and MessageBodyWriter. For HTTP requests, the MessageBodyReader is used to map an HTTP request entity body to method parameters. On the response side, a return value is mapped to an HTTP response entity body by using a MessageBodyWriter. If the application needs to supply additional metadata, such as HTTP headers or a different status code, a method can return a Response that wraps the entity and that can be built using Response.ResponseBuilder.

"

From your respective, every rest orchestration engine, must provide you doors to decide which Provider component to use, one two or more components are found in the classpath and virtually offer the exact same service. In scnearios where things are ambiguous a proper implementation (e.g. Jersey) should be giving a door to make the story anmbiguous.

Correct?

So Jackson could be offering several possible configurations - and if I am using Weblogic/Jersey - i should be able to tweak the system to solve the "ambiguity".

This is your point. Correct?

Many thanks.

99sono commented 5 years ago

I would be helpful to get a reply on what the concept is behind this configuration. The JEE should support developers in terms of tackling such issues. Or at minimum it should state that rest orchestration providers like Jersey and RestEasy need to offer flexibile enough configuration to address such ambiguity.

Many thanks for your help on this.