Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping between JSON formats in Java

Tags:

java

json

I'm coming to Java from JavaScript/Ruby. Let's say I've got the following JSON object for an animal:

{
  name: {
    common: "Tiger",
    latin: "Panthera tigris"
  }
  legs: 4
}

I'm dealing with lots of animal APIs, and I want to normalize them all into my own common format, like:

{
  common_name: "Tiger",
  latin_name: "Panthera tigris",
  limbs: {
    legs: 4,
    arms: 0
  }
}

In, say, JavaScript, this would be straightforward:

normalizeAnimal = function(original){
  return {
    common_name: original.name.common,
    latin_name: original.name.latin,
    limbs: {
      legs: original.legs || 0,
      arms: original.arms || 0
    }
  }
}

But what about in Java? Using the JSONObject class from org.json, I could go down the road of doing something like this:

public JSONObject normalizeAnimal(JSONObject original) throws JSONException{
  JSONObject name = original.getJSONObject("name");
  JSONObject limbs = new JSONObject();
  JSONObject normalized = new JSONObject();
  normalized.put("name_name", name.get("common"));
  normalized.put("latin_name", name.get("latin"));
  try{
    limbs.put("legs", original.get("legs");
  }catch(e){
    limbs.put("legs", 0);
  };
  try{
    limbs.put("arms", original.get("arms");
  }catch(e){
    limbs.put("arms", 0);
  };
  normalized.put("limbs", limbs);
  return normalized;
}

This gets worse as the JSON objects I'm dealing with get longer and deeper. In addition to all of this, I'm dealing with many providers for animal objects and I'll eventually be looking to have some succinct configuration format for describing the transformations (like, maybe, "common_name": "name.common", "limbs.legs": "legs").

How would I go about making this suck less in Java?

like image 664
user225643 Avatar asked Sep 28 '12 18:09

user225643


People also ask

How do I map one JSON to another JSON?

You can use the Jackson API to add field or transform a JSON without creating POJO's. It provides a object form called JsonNode , JsonObject and JsonArray types which can be transformed like i did in the below code. I hope this helps you.

How do I map JSON?

The first way to convert JSON to Map in Java is by using Jackson. In Jackson, there is a method available with the name readValue(json, Map. class) and we can call this method by using the ObjectMapper object. This method takes JSON as input.

Can we have map in JSON?

There are a number of ways to convert a Java Map into JSON. It is quite common to convert Java Arrays and Maps into JSON and vice versa. In this post, we look at 3 different examples to convert Java Map to JSON. We will be using Jackson, Gson and org.


3 Answers

Use a library like Gson or Jackson and map the JSON to a Java Object.

So you're going to have a bean like

public class JsonAnima {
    private JsonName name;
    private int legs; 
}
public class JsonName {
    private String commonName;
    private String latinName;
}

which can be easily converted with any library with something like (with Jackson)

ObjectMapper mapper = new ObjectMapper();
JsonAnimal animal = mapper.readValue(jsonString, JsonAnimal.class);

then you can create a "converter" to map the JsonAnimal to you Animal class.

This can be a way of doing it. : )


Some links:

Gson: http://code.google.com/p/google-gson/

Jackson: http://wiki.fasterxml.com/JacksonHome

like image 173
Enrichman Avatar answered Oct 13 '22 15:10

Enrichman


If you'll be using this for many different types of objects, I would suggest to use reflection instead of serializing each object manually. By using reflection you will not need to create methods like normalizeAnimal, you just create one method or one class to do the serialization to json format.

If you search for "mapping json java" you'll find some useful references. Like gson. Here is an example that is on their website:



    class BagOfPrimitives {
      private int value1 = 1;
      private String value2 = "abc";
      private transient int value3 = 3;
      BagOfPrimitives() {
        // no-args constructor
      }
    }

    //(Serialization)
    BagOfPrimitives obj = new BagOfPrimitives();
    Gson gson = new Gson();
    String json = gson.toJson(obj);  
    ///==> json is {"value1":1,"value2":"abc"}

    ///Note that you can not serialize objects with circular references since that will result in infinite recursion. 

    //(Deserialization)
    BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);   
    //==> obj2 is just like obj

like image 40
Filipe Avatar answered Oct 13 '22 15:10

Filipe


The pure Java solutions all are challenged to deal with unreliable structure of your source data. If you're running in a JVM, I recommend that you consider using Groovy to do the Parse and the Build of your source JSON. The result ends up looking a lot like the Javascript solution you outlined above:

import groovy.json.JsonBuilder
import groovy.json.JsonSlurper

def originals = [
  '{ "name": { "common": "Tiger", "latin": "Panthera tigris" }, "legs": 4 }',
  '{ "name": { "common": "Gecko", "latin": "Gek-onero" }, "legs": 4, "arms": 0 }',
  '{ "name": { "common": "Liger" }, "legs": 4, "wings": 2 }',
  '{ "name": { "common": "Human", "latin": "Homo Sapien" }, "legs": 2, "arms": 2 }'
]

originals.each { orig ->

  def slurper = new JsonSlurper()
  def parsed = slurper.parseText( orig )

  def builder = new JsonBuilder()
  // This builder looks a lot like the Javascript solution, no?
  builder { 
      common_name parsed.name.common
      latin_name parsed.name.latin
      limbs {
          legs parsed.legs ?: 0
          arms parsed.arms ?: 0
      }
  }

  def normalized = builder.toString()
  println "$normalized"
}

Running the script above deals with "jagged" JSON (not all elements have the same attributes) and outputs like...

{"common_name":"Tiger","latin_name":"Panthera tigris","limbs":{"legs":4,"arms":0}}
{"common_name":"Gecko","latin_name":"Gek-onero","limbs":{"legs":4,"arms":0}}
{"common_name":"Liger","latin_name":null,"limbs":{"legs":4,"arms":0}}
{"common_name":"Human","latin_name":"Homo Sapien","limbs":{"legs":2,"arms":2}}
like image 1
Bob Kuhar Avatar answered Oct 13 '22 15:10

Bob Kuhar