3

I've got a JSON string that I want to convert to a Map structure where Object is either a Java version of a basic type (i.e. String, Int, Double), a Map. or a List.

The sample string I'm using for my tests is:

"{\"cases\":[{\"documents\":[{\"files\":[{\"name\":\"a.pdf\"}]}]}]}"

This should read as an array of cases that each have an array of documents, that each have an array of files, that each have a name

I've tried Google's Gson, but

Gson gson = new Gson();
List<Map<String, Object>> results = gson.fromJson(dictString, List.class);

gives me:

com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter@561777b1 failed to deserialize json object {"cases":[{"documents":[{"files":[{"name":"a.pdf"}]}]}]} given the type interface java.util.List

and I tried Jackson, but

List<Map<String, Object>> results = (List<Map<String, Object>>) new ObjectMapper().readValue(dictString, List.class);

gave me:

org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.List out of START_OBJECT token
 at [Source: java.io.StringReader@1c5aebd9; line: 1, column: 1]

Do you have any suggestions? Either for how to use either of the above correctly, or for another parser that gives me what I want?

Cheers

Nik

niklassaers
  • 8,480
  • 20
  • 99
  • 146

4 Answers4

1

I stumbled in here with the same problem and I found a simple solution. I'm posting a more clear answer just in case it helps someone else:

String jsonString = "{ \"first-name\" : \"John\" }";

//creates, essentially a wrapper for a HashMap containing your JSON dictionary
JSONObject genericMap = new JSONObject(jsonString);

//calls to "put" and "get" are delegated to an internal hashmap
String name = (String) genericMap.get("first-name");
assertEquals("John", name); //passes

genericMap.put("last-name", "Doe"); //add any object to the hashmap

//the put methods can be used fluidly
genericMap.put("weight", 150).put("height", "5'10").put("age", "32");

//finally, you can write it back out to JSON, easily
String newJson = genericMap.toString(4); //pretty-print with 4 spaces per tab
log.debug(newJson);

this prints the following:

{
    "age": "32",
    "first-name": "John",
    "height": "5'10",
    "last-name": "Doe",
    "weight": 150
}

Add this dependency to your project like this:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20090211</version>
</dependency>

Or download the JAR directly:
http://repo1.maven.org/maven2/org/json/json/20090211/json-20090211.jar

I already had this class available (it was a transient dependency of something else in our project). So be sure to check if it's already there first. You might get lucky, too.

gMale
  • 17,147
  • 17
  • 91
  • 116
0

Using gson library:

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>${gson.version}</version>
</dependency>

First you need to create a type. Let's suppose you need a Map<String,Foo> then change:

private static final Type INPUT_MAP_TYPE = new TypeToken<Map<String, Foo>>() {}.getType();

Then, have a generic method of the type:

protected <T> T readJson(String fileName, Type type) {
    InputStreamReader ir = new InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName));
    return new Gson().fromJson(ir, type);
}

Where Type is in package java.lang.reflect;

Enjoy:

Map<String, Foo> inputParams = readJson("path/to/my.json", INPUT_MAP_TYPE);
moldovean
  • 3,132
  • 33
  • 36
0

Given your description, it sounds like your definition doesn't match up. It dounds like it should be something like: List<List<list<String>>>

It's a bit more manual but have a look here:

http://json.org/java/

This will give you a JSONObject that is much easier to use than parsing the string yourself, but you will still have to drill into it and manually build your map. Kind of a half and half solution.

Brad Gardner
  • 1,627
  • 14
  • 14
  • 1
    No, the List>> is just the sample data, I want to have a map that I can traverse for any JSON dictionary – niklassaers May 06 '11 at 13:22
  • 1
    I don't think you are going to be able to map this: "{\"cases\":[{\"documents\":[{\"files\":[{\"name\":\"a.pdf\"}]}]}]}" to a List> structure without manual work because the structures simply don't match. I would still go with using the JSONObject approach then building your map manually. – Brad Gardner May 06 '11 at 13:56
  • I already do so in both PHP and Cocoa, so I'm a bit surprised by this prediction. I'm not looking for an Object-mapper, I'm looking for a mapper of a JSON represented dictionary to a Map-based dictionary. – niklassaers May 06 '11 at 19:28
  • The link given is broken! – Romeo Sierra May 07 '19 at 11:49
0

The easiest thing might be just to do it yourself: use something like GSON or tapestry's JSONObject to construct a java representatin of your json, then just iterate through it and build whatever map structure you like.

Richard H
  • 38,037
  • 37
  • 111
  • 138