jolt: JSON Transforms Simplified

Every now and then it comes up that a REST API you are working with is a little inconsistent with the JSON that it returns. Sometimes a property you want is an array when it has multiple values but an object when there is only one. It’s annoying when you encounter these APIs and it happens more often than you think. Jolt is a package that handles JSON transformations really well and is perfect for this exact situation.

What I especially like about it is that it separates JSON transformation logic into separate files that can be read in at runtime. That allows it to be more configuration driven as oppose to being in your code. Here are a few examples that you can play with to get a feeling for things.

Step 1: Include jolt as a dependency

Create a new starter project using Gradle as your dependency manager. Add jolt as a dependency.

compile group: 'com.bazaarvoice.jolt', name: 'jolt-complete', version: '0.1.1'

Step 2: Get a JSON string to transform

Add this JSON to your src/main/resources folder as a file named jolt-me.js. We are going to use it as the target for our jolt transformations.

{
    "hello": "world",
    "I'm an array": [
        {
            "object": 1
        }
    ]
}

The following snippet will read that JSON file and covert it into a String instance.

Scanner scanner = new Scanner(ClassLoader.getSystemResourceAsStream("jolt-me.js"));
StringBuilder inputJSON = new StringBuilder();
while(scanner.hasNextLine()) {
    inputJSON.append(scanner.nextLine() + "\n");
}
scanner.close();

Step 3: Create a transformation JSON

All jolt transformations are executed using an instance of Chainr. To create an instance, you feed it JSON that defines the transformations that you want it to perform. Jolt provides several types of transformations out of the box. The two I find the most usefully are Shift and Cardinality.

Step 3.1: Shift transform

Shift transformations are for moving properties around and renaming them. Hence why it is called shift. Here is a simple example below. Safe it in a file named shift-spec.js in your src/main/resources folder:

[
    {
        "operation": "shift",
        "spec": {
            "hello": "blue",
            "*": "&"
        }
    }
]

The following snippet loads and runs the shift transformation.

Chainr chainr = Chainr.fromSpec(JsonUtils.jsonToList(ClassLoader.getSystemResourceAsStream("shift-spec.js")));
System.out.println(JsonUtils.toPrettyJsonString(
        chainr.transform(JsonUtils.jsonToObject(inputJSON.toString()))
    )
);

That results in the following output:

{
  "blue" : "world",
  "I'm an array" : [ {
    "object" : 1
  } ]
}

Step 3.2: Cardinality transform

This transformation is by far my favorite. The cardinality transform is specifically for dealing with JSON properties that are sometimes arrays and sometimes objects. In other words, the API you are working with is not consistent in how it returns data. I don’t know why this happens so often but I suspect developers of those APIs are trying to make things easier by considering the context in which their end points are getting called. However, it really has the opposite effect especially when you are trying to deserialize that JSON into a POJO.

Create the file cardinality-spec.js in src/main/resources with the contents below.

[
    {
        "operation": "cardinality",
        "spec": {
            "I'm an array": "ONE"
        }
    }
]

As with the previous step, you use a Chainr instance to execute the transformation. For example:

Chainr chainr = Chainr.fromSpec(JsonUtils.jsonToList(ClassLoader.getSystemResourceAsStream("cardinality-spec.js")));
System.out.println(JsonUtils.toPrettyJsonString(
        chainr.transform(JsonUtils.jsonToObject(inputJSON.toString()))
    )
);

That gives the following output. Notice that I'm an array is not an array anymore. It’s an object.

{
  "hello" : "world",
  "I'm an array" : {
    "object" : 1
  }
}

Step 3.3 Chaining transforms

What is really cool is that you can chain transforms together. So let’s combine the previous two transforms into a single JS file called chain-spec.js in your src/main/resources folder. The contents should be the following:

[
    {
        "operation": "cardinality",
        "spec": {
            "I'm an array": "ONE"
        }
    },
    {
        "operation": "shift",
        "spec": {
            "hello": "blue",
            "*": "&"
        }
    }
]

This familiar Chainr snippet will execute it.

Chainr chainr = Chainr.fromSpec(JsonUtils.jsonToList(ClassLoader.getSystemResourceAsStream("chain-spec.js")));
System.out.println(JsonUtils.toPrettyJsonString(
         chainr.transform(JsonUtils.jsonToObject(inputJSON.toString()))
    )
);

That gives you the following. As you can see, both the shift and cardinality transforms were performed on our JSON data.

{
  "blue" : "world",
  "I'm an array" : {
    "object" : 1
  }
}

Closing Thoughts

Jolt is pretty convenient as an off the shelf utility for quickly doing some JSON transformations. The implementation of its JsonUtils is a little clunky and it is annoying how it doesn’t support generics so explicit casting has to be done. Regardless, that is pretty minimal pain compared to having to do these transformations using POJOs.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: