Jackson ObjectMapper with arbitrary JSON keys

aaronsnoswell picture aaronsnoswell · Jul 16, 2012 · Viewed 12.3k times · Source

I'm using Jackson 1.9.5 in an Android project to parse JSON files.

So far I haven't had any problems, and can parse files fine using the following code:

AssetManager mgr = getAssets();
ObjectMapper mapper = new ObjectMapper();

try {
    InputStream ifp = mgr.open("detail_schema.json");
    schema = mapper.readValue(ifp, DetailSchema.class);
} catch (IOException e) {
    e.printStackTrace();
}

Where the DetailSchema class consists of a mix of primitive types and classes. I'm now running into a problem where I want to parse some JSON like the following:

"fields": {
    "Suburb": "Paddington",
    "State": "NSW",
    "Post Code": "2074",
    "Lollipop": "Foo Bar Haz"
}

Where I can't possibly know the map keys before hand (they can be user-defined). As such, I'm not sure what the associated Java class should look like.

Ie, for this example, it could look like:

public class MyClass {

    public String Suburb;
    public String State;
    public String PostCode;
    public String Lollipop;

}

But this may not be correct for another instance of the JSON file. Ideally I need some way for Jackson to map values to something like a NameValuePair. I suspect that the automatic object mapping may not be an option in this case - can someone confirm or deny this?

Answer

waxwing picture waxwing · Jul 16, 2012

You have two options. Either you can use readTree in ObjectMapper, which returns a JsonNode. Working with a JsonNode is much like working with a tree, so you can get children nodes, read values, et cetera:

InputStream ifp = mgr.open("detail_schema.json");
JsonNode root = mapper.readTree(ifp);
JsonNode fields = root.get("fields");
for (JsonNode children : fields) {
    // ...
}

Then you'd need to build your DetailSchema object manually.

Or, you can let Jackson deserialize it as a Map, in which case you'd use your code but where MyClass would be like this:

public class MyClass {
    public Map<String, Object> fields;

    // getter/setters
}

You can probably type the map values as String as well if you are sure the inputs are text in json. (Actually, I'm not sure what type enforcement Jackson does, maybe it will allow anything anyway...)