1129

The Jackson data binding documentation indicates that Jackson supports deserialising "Arrays of all supported types" but I can't figure out the exact syntax for this.

For a single object I would do this:

//json input
{
    "id" : "junk",
    "stuff" : "things"
}

//Java
MyClass instance = objectMapper.readValue(json, MyClass.class);

Now for an array I want to do this:

//json input
[{
    "id" : "junk",
    "stuff" : "things"
},
{
    "id" : "spam",
    "stuff" : "eggs"
}]

//Java
List<MyClass> entries = ?

Anyone know if there is a magic missing command? If not then what is the solution?

3
  • 2
    I prefer Google's GSON library for dealing with JSON. It is worth checking out if you haven't tryed it yet... makes working with it very easy and intuitive. Commented Jun 14, 2011 at 20:51
  • 15
    FWIW The possible solutions to this specific problem with Gson are almost identical to what's possible with Jackson's Data Binding API. Commented Jun 14, 2011 at 21:01
  • 24
    Gweebz -- maybe you would like to explain why you feel GSON is a better choice (compared to Jackson)? Commented Jun 15, 2011 at 17:28

11 Answers 11

2364

First create a mapper :

import com.fasterxml.jackson.databind.ObjectMapper;// in play 2.3
ObjectMapper mapper = new ObjectMapper();

As Array:

MyClass[] myObjects = mapper.readValue(json, MyClass[].class);

As List:

List<MyClass> myObjects = mapper.readValue(jsonInput, new TypeReference<List<MyClass>>(){});

Another way to specify the List type:

List<MyClass> myObjects = mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(List.class, MyClass.class));
Sign up to request clarification or add additional context in comments.

18 Comments

One extra note, if while parsing you get an error such as JsonMappingException: No suitable constructor found for type then it means you need to added a default constructor to your class adding a private no-arg constructor fixed it for me.
@SyntaxRules adding explicit constructor is necessary if you have an explicit constructor -- if not, compiler automatically creates public "empty" constructor. Good point. Another common problem is that inner classes need to be static -- otherwise they never have zero-arg constructor.
Btw, List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class)) works up to 10 time faster than TypeRefence.
I'm looking for a generic type version.
In response to my own comment above, first parse the json string to a jsonNode and then access the property of the array like this: JsonNode jsonNode = MAPPER.readTree(json); String arrayString = jsonNode.get("data").toString(); Then follow @Programmer Bruce's instructions above. List<Source> sources = MAPPER.readValue(arrayString, new TypeReference<List<Source>>() {});
|
291

From Eugene Tskhovrebov

List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class))

This solution seems to be the best for me.

5 Comments

For those working with Agents in Java, Lotus Domino, this is the way to go. I tried some of the other solutions, but always got a ResourceNotFoundException
SyntaxRules addition in the comments for the answer above may be required for this solution as we, it was for me. I just wanted to add that so that it is not lost.
or Arrays.asList(Json.fromJson(json.get("fieldName"), MyClass[].class))
or List<MyClass> myObjects = Arrays.asList(mapper.treeToValue(jsonNode.get("fieldName"), MyClass[].class))
This is an excellent solution for the simple case of a root json array!
61

try this

List<MyClass> list = mapper.readerForListOf(MyClass.class).readValue(json)

4 Comments

This answer worked for me: Java 11, Jackson 2.10.5.
Answer worked for me, and is clear and concise. Love it. For me, I had a generic method that passed in a Class<T> myGenericClass and was able to do: List<T> list = mapper.readerForListOf(myGenericClass).readValue(json); Which worked nicely for my solution. Thanks again!
Good luck testing this! Cannot invoke "com.fasterxml.jackson.databind.ObjectReader.readValue(byte[])" because the return value of "com.fasterxml.jackson.databind.ObjectMapper.readerForListOf(java.lang.Class)" is null
Works great ! The unsung hero
60

For Generic Implementation:

public static <T> List<T> parseJsonArray(String json,
                                         Class<T> classOnWhichArrayIsDefined) 
                                         throws IOException, ClassNotFoundException {
   ObjectMapper mapper = new ObjectMapper();
   Class<T[]> arrayClass = (Class<T[]>) Class.forName("[L" + classOnWhichArrayIsDefined.getName() + ";");
   T[] objects = mapper.readValue(json, arrayClass);
   return Arrays.asList(objects);
}

1 Comment

Nice construct of Class<T[]>. Never saw this. Where did you find information about this?
18

First create an instance of ObjectReader which is thread-safe.

ObjectMapper objectMapper = new ObjectMapper();
ObjectReader objectReader = objectMapper.reader().forType(new TypeReference<List<MyClass>>(){});

Then use it :

List<MyClass> result = objectReader.readValue(inputStream);

3 Comments

we do get - com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at [Source: java.io.FileInputStream@33fec21; line: 1, column: 1]
That can be overcome by adding this extra layer of configuration to our ObjectMapper() instance: mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
do not work with error Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at
17

Working with an ArrayList, these different syntaxes all worked for me:

ArrayList<MyClass> arrayList = ...

Using objectMapper.getTypeFactory().constructCollectionType:

objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, MyClass.class));

Using new TypeReference:

objectMapper.readValue(json, new TypeReference<ArrayList<MyClass>>(){});

Using new ArrayList<>(Arrays.asList):

new ArrayList<>(Arrays.asList(objectMapper.readValue(json, MyClass[].class)));

I can't say which one is the best to use, but I ended up using the last one:

ArrayList<MyClass> arrayList = new ArrayList<>(Arrays.asList(objectMapper.readValue(json, MyClass[].class)));

Comments

10

I was unable to use this answer because my linter won't allow unchecked casts.

Here is an alternative you can use. I feel it is actually a cleaner solution.

public <T> List<T> parseJsonArray(String json, Class<T> clazz) throws JsonProcessingException {
  var tree = objectMapper.readTree(json);
  var list = new ArrayList<T>();
  for (JsonNode jsonNode : tree) {
    list.add(objectMapper.treeToValue(jsonNode, clazz));
  }
  return list;
}

Comments

8
try {
    ObjectMapper mapper = new ObjectMapper();
    JsonFactory f = new JsonFactory();
    List<User> lstUser = null;
    JsonParser jp = f.createJsonParser(new File("C:\\maven\\user.json"));
    TypeReference<List<User>> tRef = new TypeReference<List<User>>() {};
    lstUser = mapper.readValue(jp, tRef);
    for (User user : lstUser) {
        System.out.println(user.toString());
    }

} catch (JsonGenerationException e) {
    e.printStackTrace();
} catch (JsonMappingException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

Comments

7

here is an utility which is up to transform json2object or Object2json, whatever your pojo (entity T)

import java.io.IOException;
import java.io.StringWriter;
import java.util.List;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

/**
 * 
 * @author TIAGO.MEDICI
 * 
 */
public class JsonUtils {

    public static boolean isJSONValid(String jsonInString) {
        try {
            final ObjectMapper mapper = new ObjectMapper();
            mapper.readTree(jsonInString);
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public static String serializeAsJsonString(Object object) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper objMapper = new ObjectMapper();
        objMapper.enable(SerializationFeature.INDENT_OUTPUT);
        objMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        StringWriter sw = new StringWriter();
        objMapper.writeValue(sw, object);
        return sw.toString();
    }

    public static String serializeAsJsonString(Object object, boolean indent) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper objMapper = new ObjectMapper();
        if (indent == true) {
            objMapper.enable(SerializationFeature.INDENT_OUTPUT);
            objMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        }

        StringWriter stringWriter = new StringWriter();
        objMapper.writeValue(stringWriter, object);
        return stringWriter.toString();
    }

    public static <T> T jsonStringToObject(String content, Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
        T obj = null;
        ObjectMapper objMapper = new ObjectMapper();
        obj = objMapper.readValue(content, clazz);
        return obj;
    }

    @SuppressWarnings("rawtypes")
    public static <T> T jsonStringToObjectArray(String content) throws JsonParseException, JsonMappingException, IOException {
        T obj = null;
        ObjectMapper mapper = new ObjectMapper();
        obj = mapper.readValue(content, new TypeReference<List>() {
        });
        return obj;
    }

    public static <T> T jsonStringToObjectArray(String content, Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
        T obj = null;
        ObjectMapper mapper = new ObjectMapper();
        mapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        obj = mapper.readValue(content, mapper.getTypeFactory().constructCollectionType(List.class, clazz));
        return obj;
    }

1 Comment

How do I parameterize the collection type?
2

This works for me.

Json:

[
   {
      "question":"How are you feeling today?",
      "key":"feeling",
      "answer":"unwell"
   },
   {
      "question":"How many hours of sleep did you get last night?",
      "key":"sleep_hours",
      "answer":"8"
   },
   {
      "question":"Have you been having nightmares lately?",
      "key":"nightmares",
      "answer":"Recently"
   }
]

java code:

private String getFeelByAnswer(String answer) {
    ObjectMapper mapper = new ObjectMapper();
    try {
        JsonNode nodes = mapper.readTree(answer);
        String feeling = "";
        for (JsonNode node : nodes) {
            if (node.get("key").asText().equals("feeling")) {
                feeling = node.get("answer").asText();
            }
        }
        return feeling;

    } catch (Exception e) {
        log.info("Feeling not found.");
    }
    return "";
}

Comments

-2

you could also create a class which extends ArrayList:

public static class MyList extends ArrayList<Myclass> {}

and then use it like:

List<MyClass> list = objectMapper.readValue(json, MyList.class);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.