ChatGPT解决这个技术问题 Extra ChatGPT

How to use Jackson to deserialise an array of objects

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?

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.
FWIW The possible solutions to this specific problem with Gson are almost identical to what's possible with Jackson's Data Binding API.
Gweebz -- maybe you would like to explain why you feel GSON is a better choice (compared to Jackson)?

M
Moebius

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));

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>>() {});
M
Marthym

From Eugene Tskhovrebov

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

This solution seems to be the best for me.


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))
@CollinKrawll what does objectmapper.treetovalue do?
P
Pallav Jha

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);
}

Nice construct of Class. Never saw this. Where did you find information about this?
G
Greg D

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);

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
h
hantian_pang

try this

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

l
lbenedetto

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;
}

A
Alessandro Da Rugna
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();
}

T
Tiago Medici

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;
    }

p
pero_hero

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);