/simplerialize

A thin wrapper on top of Jackson and Woodstox to offer a unified API for serializing to XML and JSON while sacrificing flexibility and customization

Primary LanguageJavaOtherNOASSERTION

About

This is an opinionated library with a narrow use case. Please treat it as such.

This library offers

  • API neutral serialization to XML and JSON
  • Only serialization - no deserialization
  • Serialization specification in code (no schemas - neither compilation nor generation)
  • Compact output regardless of format
  • Good performant streaming serialization (thanks to Jackson and Woodstox)
  • Non-customizable output

Beware that this library may

  • ...fail horribly for your particular case
  • ...provide you with an inconsistent model depending on context and usage

In other words, don't trust it until you've made it prove itself for your specific use case - write tests.

Example

The following...

    Serializer serializer = (json) ? new JacksonJsonSerializer(...) : new WoodstoxXmlSerializer(...)
    serializer.start();
    serializer.startContainer("root");
    {
        serializer.eachComplex("objects", Collections.singletonMap("foo", "bar").entrySet());
        serializer.eachPrimitive("primitives", Arrays.asList("1", 1, true));
        serializer.startContainer("a");
        {
            serializer.startContainer("b");
            {
                serializer.writeNameValue("name", "value");
            }
            serializer.endContainer();
        }
        serializer.endContainer();
    }
    serializer.endContainer();
    serializer.close();

...will result in this JSON...

    {
        "root":
        {
            "objects":
            [
                {"foo":"bar"}
            ],
            "primitives": [ "1", 1, true ],
            "a":
            {
                "b": { "name":"value" }
            }
        }
    }

...this XML...

    <?xml version='1.0' encoding='UTF-8'?>
    <root>
        <objects foo="bar" />
        <primitives>
            <value>1</value>
            <value>1</value>
            <value>true</value>
        </primitives>
        <a>
            <b name="value" />
        </a>
    </root>

...or if you're a fan of chaining the above code could also be written as...

    serializer.start()
    .startContainer("root")
        .eachComplex("objects", Collections.singletonMap("foo", "bar").entrySet())
        .eachPrimitive("primitives", Arrays.asList("1", 1, true))
        .startContainer("a")
            .startContainer("b")
                .writeNameValue("name", "value")
            .endContainer()
        .endContainer()
    .endContainer()
    .close();

Exeptions:

Everything throws IOException which either means you screwed up your serialization causing invalid XML or JSON or the underlying serialization library encountered an error when writing to the underlying writer.

Dependencies

  • SLF4J: We depend on SLF4J so that you can plug in whatever logging you see fit
  • Jackson and Woodstox for the actual serialization
  • Guava we support serializing Optional instances.

Background and rationale

Our scenario

We have a lot of HTTP based API services. These are almost entirely accessed using GET with various path and query parameters. They produce their response in either XML or JSON depending on the clients accept header or file extension (.xml or .json). The response is often a subset of the POJOs and their fields so we must explicitly define what to serialize. Also the POJOs are usually defined in libraries where no serialization logic belongs. These services need to serialize transparently to JSON and XML, be efficient and they never need to deserialize XML or JSON input back to POJOs.

XML and JSON serialization in Java

There are lots of good and great Java libraries out there for serializing POJOs to XML or JSON. We're using, have used or have tried Jaxb, Jackson, Woodstox, Simple, XStream, org.json, VTD-XML and Gson.

The problem

We're not interested in de-serialization. Period. A few of our services accept small JSON inputs - we handle that input "manually", often with Gson. Not requiring deserialization makes the quirks in [insert-library-name-here] a much bigger pain. For example we don't want to add private no-arg constructors to our immutable POJOs. Then when you've started to irritate yourself on that you can also choose to irritate yourself on the annotations, or the lack of annotations, or the inability to serialize [insert-collection-class-here] without having to write an adapter - whichever fuels your rage. And when you've become agitated enough you may write a library such as this, for fun and dubious profit.