2

What is a ContextResolver in Jersey and what is a Provider? What is the difference between the two? I am using Genson with Jersey. Genson is auto-registered when Jersey finds the Genson JAR on the classpath. The Genson JAR's WEB-INF/services directory contains a file called "org.glassfish.jersey.internal.spi.AutoDiscoverable".

Following that AutoDiscoverable path, by default Genson/Jersey auto-registers a the following class:

@Provider
@Consumes({MediaType.APPLICATION_JSON, "text/json", "application/*+json"})
@Produces({MediaType.APPLICATION_JSON, "text/json", "application/*+json"})
public class GensonJsonConverter implements MessageBodyReader<Object>, MessageBodyWriter<Object> {

     private final ContextResolver<GensonJaxRSFeature> _gensonResolver;

Here's where more confusion comes into play: looking at the Genson documentation it recommends to create a custom provider like so:

    @Provider
    public class GensonProvider implements ContextResolver<Genson> {
    private final Genson genson = new GensonBuilder().setSkipNull(true).create();
    }

However that provider implements a ContextResolver not a MessageBodyReader/Writer like the internal Genson one does. What's the difference? Also, that provider does not do the same thing as the default auto-registered one does! In particular, it ignores JAXB tags like @XmlTransient! Digging into the Genson source code for GensonJaxRSFeature, I see that the Genson object is created like so:

private static final Genson _defaultGenson = new GensonBuilder()
      .withBundle(new JAXBBundle())
      .useConstructorWithArguments(true)
      .create();

From that and from the Genson documentation I can see that the "JAXBBundle" is probably what causes Genson to pay attention to the JAXB annotations.

The main issue:

I want to use the default Genson JSON provider that is auto-registered with Jersey, but I want to set a few custom properties on it. As I said, when I register my custom provider, it doesn't use the default Genson one!


Update:

This is what I'm doing right now and it works. However, the solution below by @eugen is the Genson recommended solution.

@Provider
public class GensonProvider implements ContextResolver<GensonJaxRSFeature> {
    private final GensonJaxRSFeature _gensonResolver = new GensonJaxRSFeature();

    private static final Genson _defaultGenson = new GensonBuilder()
              .withBundle(new JAXBBundle())
              .useConstructorWithArguments(true)
              .setSkipNull(true)
              .create();

   @Override
   public GensonJaxRSFeature getContext(Class<?> type) {
        return _gensonResolver.use(_defaultGenson);
   }
}
KyleM
  • 4,445
  • 9
  • 46
  • 78
  • what makes you say Genson recommends to define a custom provider? At least the current documentation recommends to use a ResourceConfig configured with a GensonJaxRSFeature that uses you custom Genson instance. You are not supposed to alter the default genson instance. If you want another config just create another instance with the config you want. – eugen Jun 29 '16 at 21:17
  • @eugen Look at my edit to see what I did. The code recommended in the Genson docs is "new ResourceConfig().register(new GensonJaxRSFeature().use(myCustomGenson).disableSerializationFor(String.class));". It does the same as what I'm now doing except I'm using a Provider instead of wherever you'd normally put the "new ResourceConfig" code. Where does that "new ResourceConfig" usually go? Can you post an example or link? – KyleM Jun 29 '16 at 22:46
  • Check [the official docs](https://jersey.java.net/documentation/latest/deployment.html#environmenmt.appmodel) on how to use a ResourceConfig. There is no way to take the default genson instance and modify it. Just provide your own with whatever config you want. And yes if you want Genson to use the JAXB annotations you need to configure it to use this bundle. – eugen Jun 29 '16 at 23:11
  • @eugen That doesn't make sense to me, I've already read it 3 times now. I've seen other examples that say to put an with your package.ClassName in the web xml and make your class extend Application. If that's what you're advocating I still don't see where you'd put the code "new ResourceConfig().register(new GensonJaxRSFeature().use(myCustomGenson).disableSerializationFor(String.class))" since those example typically just call register(...). If you don't want to give me an example then whatever, but the explanation isn't getting through. – KyleM Jun 29 '16 at 23:23
  • @eugen One more question. You keep implying the way I did it is wrong, and yet, I tested it and it works. Why do you think the Provider with the ContextResolver like I put above should not work? Anyway, thanks for your assistance thus far. – KyleM Jun 29 '16 at 23:51
  • I don't say the way you do is wrong...I am just pointing out that if you want the default config + custom, you will need to redefine that default config. The link I gave you above, shows you that you can extend ResourceConfig and then in it's constructor for example you can call register with your custom config. You can also use you custom Provider if you prefer. – eugen Jun 29 '16 at 23:58

1 Answers1

2

Like always in our world for the same problem there are multiple solutions. Jersey seems to encourage the use ResourceConfig instead of defining custom providers. So this is how you can achieve it using a resource config (from jersey docs here and Genson documentation here).

public class MyApplication extends ResourceConfig {
    public MyApplication() {
      Genson genson = new GensonBuilder()
              .withBundle(new JAXBBundle())
              .useConstructorWithArguments(true)
              .setSkipNull(true)
              .create();

      register(new GensonJaxRSFeature().use(genson));
    }
}

But of course the way you do it with a provider is fine too.

eugen
  • 5,856
  • 2
  • 29
  • 26
  • Thanks, I think I was just getting confused b/c in the Genson docs it says to create a "new ResourceConfig()" which is not the case in this solution. You're creating a new GensonBuilder but never a new ResourceConfig(). Anyway, I get it now.. I was mostly making sure that I wasn't missing something important with the "new ResourceConfig" piece... – KyleM Jun 30 '16 at 00:19
  • No you don't miss anything. The resource config seems to be the place where jersey wants us to put the configuration part - but your current solution is fine too. Yeah, here we don't create a resource config but extend it. In some other usages of Jersey people would instantiate it (I think it is the case with jetty + jersey). – eugen Jun 30 '16 at 00:24