Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customizing JSON marhsalling with GlassFish v4

We've got a JAX-RS application that runs on Apache TomEE. We slightly customize the default Jettison provider to better adhere to JSON conventions used by JavaScript frontend. TomEE allows to do it via its resources.xml file:

<resources>
    <Service id="jettison" class-name="org.apache.cxf.jaxrs.provider.json.JSONProvider">
        serializeAsArray = true
        dropRootElement = false
        arrayKeys = members,roles
        supportUnwrapped = true
        writeXsiType = false
    </Service>
</resources>

Now we are migrating to GlassFish v4.1, and we notice that JSON output differs from what we had in TomEE - thus completely breaking frontend. I'm looking for similar mechanism to customize JSON marshaller in GlassFish. In fact, I'm already a little bit stuck with Jersey, MOXy, Jackson, Jettison. How do we know which JSON provider is actually used? How do we select one? How do we customize the behavior?

The application is pure JAX-RS and does not use any JSON processor directly, instead relying on marshalling of JAXB-annotated classes. Introduction of any non-JavaEE dependencies is highly undesirable, since the application is intended to be portable across containers (TomEE, GlassFish, some day WildFly). Config-file method, similar to TomEE, is preferable; programmatic way is acceptable, too - but only if portability is maintained.

like image 562
Martin Schmidt Avatar asked Nov 01 '22 11:11

Martin Schmidt


1 Answers

Glassfish uses MOXy as the default provider. Internally it has the libraries to handle Jackson, Jettison, and MOXy, but the default is MOXy. There are two ways to disable MOXy

  1. Set the Jersey property jersey.config.server.disableMoxyJson to true.
  2. Register a different XxxJsonFeature that disables MOXy. For instance the JacksonFeature that comes with jersey-media-json-jackson

Note that Glassfish comes with a Jackson provider, but it is Jackson 1.x. If you want to use 2.x, instead of the using the jersey-media-json-jackson dependency listed above, it would be better to use the underlying Jackson provider dependency, which is

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.6.0</version>
</dependency>

You can register the JacksonJsonProvider or the JacksonJaxbJsonProvider for JAXB annotation support.

To configure Jackson, the easiest way to implement a ContextResolver, as seen in this answer. The JacksonJsonProvider will lookup this ContextResolver to retrieve the ObjectMapper used for (de)serialization.

You will also need to remember to disable MOXy, as mentioned above.

Also one thing to note is that this solution is portable. With JAX-RS, the only portable application configuration is through an Application subclass

@ApplicationPath("/api")
public class MyApplication extends Application {}

That being said, the disabling of MOXy in the case of Glassfish, is nothing more than setting a property. In the Application class, you can override getProperties() which returns a Map<String, Object>. This is where you can set the property. And because it s nothing more than a String (no outside dependencies), it remains portable

@ApplicationPath("/api")
public class MyApplication extends Application {
    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("jersey.config.server.disableMoxyJson", true);
        return props;
    }
}

As far as the above Jackson dependency, it is also a portable solution. It it nothing (JAX-RS) implementation specific. It implements and uses standard JAX-RS APIs

like image 113
Paul Samsotha Avatar answered Nov 09 '22 05:11

Paul Samsotha