The marshalling service allows you to create JSON-to-Java and Java-to-JSON marshallers. To create a marshaller, you have to write a Java class that manages the marshalling and registers it using a contribution.
Let's suppose we'd like to create marshallers for the following Java object:
public class Product {
private String reference;
public int getReference() { return reference; }
public void setReference(int reference) { this.reference = reference; }
private String description;
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}
Creating a Java-to-JSON Marshaller
A Java-to-JSON marshaller must implement the org.nuxeo.ecm.core.io.registry.Writer<EntityType>
class. It must have a @Setup
annotation to register it as a marshaller and a @Supports
annotation to specify the supported mimetype (JSON in our example). The Product
class is a POJO, we can either use Jackson POJO marshalling capabilities or create a custom JSON marshalling.
@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE)
public class ProductJsonWriter extends AbstractJsonWriter<Product> {
public void write(Product product, JsonGenerator jg) throws IOException {
jg.writeObject(product);
}
}
@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE)
public class ProductJsonWriter extends AbstractJsonWriter<Product> {
public void write(Product product, JsonGenerator jg) throws IOException {
jg.writeStartObject();
jg.writeNumberField("ref", product.getReference());
jg.writeStringField("desc", product.getDescription());
jg.writeEndObject();
}
}
- The
@Setup
annotation is here to define our object as a marshaller. - The
mode = Instanciations.SINGLETON
parameter defines that the marshaller must be instanciated once. - The
priority = Priorities.REFERENCE
parameter defines it as the default one for the Product class. - The
AbstractJsonWriter
super-class is the Java-to-JSON Marshaller's base class (it has the@Supports("application/json")
annotation). It helps to write the marshaller and to reuse the existing JSON marshalling.
Creating a JSON-to-Java Marshaller
A JSON-to-Java marshaller must implement the org.nuxeo.ecm.core.io.registry.Reader<EntityType>
class. It must have a @Setup
annotation to register it as a marshaller and a @Supports
annotation to specify the supported mimetype (JSON in our example). The Product class is a POJO, we can either use Jackson POJO marshalling capabilities or create a custom JSON marshalling.
@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE)
public class ProductJsonReader extends AbstractJsonReader<Product> {
public Product read(JsonNode jn) throws IOException {
return new ObjectMapper().readValue(jn, Product.class);
}
}
@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE)
public class ProductJsonReader extends AbstractJsonReader<Product> {
public Product read(JsonNode jn) throws IOException {
Product product = new Product();
product.setReference(jn.get("reference").getIntValue());
product.setDescription(jn.get("description").getTextValue());
return product;
}
}
- The
@Setup
annotation is here to define our object as a marshaller. - The
mode = Instanciations.SINGLETON
parameter defines that the marshaller must be instanciated once. - The
priority = Priorities.REFERENCE
parameter defines it as the default one for theProduct
class. - The
AbstractJsonReader
super-class is the JSON-to-Java Marshaller's base class (it has the@Supports("application/json")
annotation). It helps to write the marshaller and to reuse the existing JSON marshalling.
Each marshaller supports injection of the RenderingContext
or any Nuxeo service using the `@java.inject.Injectannotation. The injected objects are inherited while extending an existing class. The
AbstractJsonWriterand the
AbstractJsonReaderprovide the RenderingContext ("ctx" attribute) and the
MarshallingRegistry` ("registry" attribute).
Managing Lists
The Nuxeo Platform provides built-in abstract classes to manage lists.
@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE)
public class ProductListJsonWriter extends DefaultListJsonWriter<Product> {
public ProductListJsonWriter() {
super("products", Product.class);
}
}
@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE)
public class ProductListJsonReader extends DefaultListJsonReader<Product> {
public ProductListJsonReader() {
super("products", Product.class);
}
}
Registering Your Marshallers
The marshalling service provides an extension point : org.nuxeo.ecm.core.io.MarshallerRegistry/marshallers
. It allows to add new marshallers, override existing ones or unregister some.
<?xml version="1.0"?>
<component name="org.nuxeo.example.marshallers" version="1.0.0">
<extension target="org.nuxeo.ecm.core.io.MarshallerRegistry" point="marshallers">
<register class="org.nuxeo.example.ProductJsonWriter" enable="true" />
<register class="org.nuxeo.example.ProductJsonReader" enable="true" />
<register class="org.nuxeo.example.ProductListJsonWriter" enable="true" />
<register class="org.nuxeo.example.ProductListJsonReader" enable="true" />
</extension>
</component>
Using Your Marshallers
From a JAX-RS endpoint
Make sure your WebEngine application provides the nuxeo-core-io marshalling.
If it extends automation server or REST API v1, it's ok.
Otherwise, you have to register a single JAX-RS object in your application.
public class ProductApplication extends WebEngineModule { public Set<Object> getSingletons() { return Sets.newHashSet(new JsonCoreIODelegate()); } }
From your REST endpoints, just consume or return Product as usual.
Using marshallers@GET @Produces(MediaType.APPLICATION_JSON) public Product doGet() { Product product; // get the product return product; } @POST @Consumes(MediaType.APPLICATION_JSON) public Response doPost(Product product) { // do something with the product return Response.ok().build(); }
Outside JAX-RS
You can use the Nuxeo Platform marshalling service outside the web context. The simplest way is to use
org.nuxeo.ecm.core.io.registry.MarshallerHelper
.MarshallingHelper - Java-to-JSONProduct product = ...; String json = MarshallingHelper.objectToJson(product, CtxBuilder.get());
The
MarshallingHelper
class is a helper to use theMarshallingRegistry
service. This service provides multiple ways to get marshallers depending on your needs.MarshallingRegistry - Java-to-JSONProduct product = ...; OutputStream target = ...; MarshallerRegistry registry = Framework.getService(MarshallerRegistry.class); // get the most priorized JSON Writer for Product Writer<Product> writer = registry.getWriter(CtxBuilder.get(), Product.class, MediaType.APPLICATION_JSON_TYPE); writer.write(object, Product.class, Product.class, APPLICATION_JSON_TYPE, target); // get a specific JSON Writer instance ProductJsonWriter writer = registry.getInstance(CtxBuilder.get(), ProductJsonWriter.class); writer.write(object, Product.class, Product.class, APPLICATION_JSON_TYPE, target); // get the most priorized JSON Writer for Product // associated with the given context and available for use in multiple threads (usefull for use in listeners or schedulers) Writer<Product> writer = registry.getUniqueWriter(CtxBuilder.get(), Product.class, Product.class, MediaType.APPLICATION_JSON_TYPE); writer.write(object, Product.class, Product.class, APPLICATION_JSON_TYPE, target); // get a specific JSON Writer instance // associated with the given context and available for use in multiple threads (usefull for use in listeners or schedulers) ProductJsonWriter writer = registry.getUniqueInstance(CtxBuilder.get(), ProductJsonWriter.class); writer.write(object, Product.class, Product.class, APPLICATION_JSON_TYPE, target); // advanced use for Java class based on generic type List<Product> products = ...; // use TypeUtils from commons-lang3 to get the generic type Type productListType = TypeUtils.parametrize(List.class, Product.class) Writer<List<Product>> writer = registry.getWriter(CtxBuilder.get(), List.class, productListType, MediaType.APPLICATION_JSON_TYPE); writer.write(object, List.class, productListType, APPLICATION_JSON_TYPE, target);
From another marshaller: The easiest way to do that is to extends
AbstractJsonWriter
orAbstractJsonReader
.Java-to-JSON Aggregation@Setup(mode = Instantiations.SINGLETON, priority = Priorities.REFERENCE) public class AnObjectJsonWriter extends AbstractJsonWriter<AnObject> { public void write(AnObject anObject, JsonGenerator jg) throws IOException { jg.writeStartObject(); jg.writeStringField("someField", anObject.getSomeField()); Product product = anObject.getProduct(); // this will generates the product json using the provided Java-to-JSON marshaller writeEntityField("product", product, jg); // same things with 2 calls jg.writeFieldName("product"); writeEntity(product, jg); // or even, use the inherited "registry" attribute to get your marshaller and do what you want jg.writeEndObject(); } }