如何将JSON字符串转换为Java对象列表?

86

这是我的JSON数组:

[ 
    {
        "firstName" : "abc",
        "lastName" : "xyz"
    }, 
    {
        "firstName" : "pqr",
        "lastName" : "str"
    } 
]

我有一个字符串对象。现在我想将其转换为Java对象并将其存储在Java对象的列表中,例如在学生对象中。 我正在使用以下代码将其转换为Java对象的列表:-

ObjectMapper mapper = new ObjectMapper();
StudentList studentList = mapper.readValue(jsonString, StudentList.class);

我的List类是:

public class StudentList {

    private List<Student> participantList = new ArrayList<Student>();

    //getters and setters
}

我的学生对象是:-

class Student {

    String firstName;
    String lastName;

    //getters and setters
}

我有什么遗漏吗? 我得到了以下异常: -

Exception : com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.aa.Student out of START_ARRAY token

你正在尝试将 List 反序列化为 Student - ByeBye
具体而言,mapper.readValue(jsonString, Student.class) 将一个学生对象序列化,而不是 "如果 JSON 类型为列表,则返回一个学生对象或学生对象列表"。在这种情况下,您应该使用 TypeReference - yshavit
@yshavit:我已经更新了问题。对此我很抱歉。请再次查看一下。 - Nitesh
1
你的JSON看起来不像 {"participantList" : []}。这就是错误信息想要告诉你的。 - OneCricketeer
这里有一个可行的解决方案:从JSON字符串数组中提取数据 - Mehul Boghra
这是一个可行的解决方案。从JSON字符串数组中提取数据并转换为列表 - Mehul Boghra
11个回答

164
你正在要求Jackson解析一个StudentList。告诉它解析一个(学生)List。由于List是通用类型,你通常会使用TypeReference
List<Student> participantJsonList = mapper.readValue(jsonString, new TypeReference<List<Student>>(){});

完美的答案。总是有效的。但我有一个后续问题。如果Student POJO具有嵌套的哈希映射结构,并且jsonString具有应映射到此嵌套的哈希映射的一部分。有人能告诉我如何实现吗? - old_soul_on_the_run
1
嗯,我明白我想要实现什么了。我必须更改JSON结构(我有自由来这样做)。[{“id”:“1”,“name”:“XYZ”,“thisHasToBeHashMap”:{“key1”:“value1”,“key2”:“value2”}}]使用TypeReference <List <Student>>隐式转换此结构。 - old_soul_on_the_run
可以简化为 List<Student> participantJsonList = mapper.readValue(jsonString, new TypeReference<>(){}); - Kxrr

15

对于任何正在寻找答案的人:

1.将jackson-databind库添加到您的构建工具中,如Gradle或Maven。

2.在您的代码中:

ObjectMapper mapper = new ObjectMapper();

List<Student> studentList = new ArrayList<>();

studentList = Arrays.asList(mapper.readValue(jsonStringArray, Student[].class));

6
您也可以使用Gson来处理这种情况。
Gson gson = new Gson();
NameList nameList = gson.fromJson(data, NameList.class);

List<Name> list = nameList.getList();

您的NameList类可以如下所示:

class NameList{
 List<Name> list;
 //getter and setter
}

这个解决方案更简单 StackOverflow。它使用了 TypeToken 类。 - HRoux

4
您可以使用下面的类来读取对象列表。它包含了一个静态方法以读取特定类型的对象列表。它还包含了Jdk8Module更改,提供了新的时间类支持。这是一个干净且通用的类。
List<Student> students = JsonMapper.readList(jsonString, Student.class);

通用的JsonMapper类:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.io.IOException;
import java.util.*;

import java.util.Collection;

public class JsonMapper {

    public static <T> List<T> readList(String str, Class<T> type) {
        return readList(str, ArrayList.class, type);
    }

    public static <T> List<T> readList(String str, Class<? extends Collection> type, Class<T> elementType) {
        final ObjectMapper mapper = newMapper();
        try {
            return mapper.readValue(str, mapper.getTypeFactory().constructCollectionType(type, elementType));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static ObjectMapper newMapper() {
        final ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.registerModule(new JavaTimeModule());
        mapper.registerModule(new Jdk8Module());
        return mapper;
    }
}

3

使用以下简单的代码,无需使用任何其他库,除了GSON

String list = "your_json_string";
Gson gson = new Gson();                         
Type listType = new TypeToken<ArrayList<YourClassObject>>() {}.getType();
ArrayList<YourClassObject> users = new Gson().fromJson(list , listType);

3
“不需要使用任何库”...但是你很明显正在使用GSON(上面已经提供了答案)?! - Michael Berry

2
我写了一个方法来实现这个功能,叫做jsonArrayToObjectList。它是一个方便的静态类,可以传入一个包含JSON数组的文件名。
 List<Items> items = jsonArrayToObjectList(
            "domain/ItemsArray.json",  Item.class);

    public static <T> List<T> jsonArrayToObjectList(String jsonFileName, Class<T> tClass) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        final File file = ResourceUtils.getFile("classpath:" + jsonFileName);
        CollectionType listType = mapper.getTypeFactory()
            .constructCollectionType(ArrayList.class, tClass);
        List<T> ts = mapper.readValue(file, listType);
        return ts;
    }

这真的是一个很好的选项,因为这是一个适用于任何POJO类的简单通用函数。 - Arun Kumar

1
StudentList studentList = mapper.readValue(jsonString,StudentList.class);

将这个改为这个。
StudentList studentList = mapper.readValue(jsonString, new TypeReference<List<Student>>(){});

0

Gson 解决方案

最安全的方法是通过 JsonParser.parseString(jsonString).getAsJsonArray() 循环遍历 json 数组,并通过检查 jsonObject.has("key") 逐个解析其元素。

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.Data;

@Data
class Foo {
    String bar;
    Double tar;
}

JsonArray jsonArray = JsonParser.parseString(jsonString).getAsJsonArray();
List<Foo> objects = new ArrayList<>();
jsonArray.forEach(jsonElement -> {
    objectList.add(JsonToObject(jsonElement.getAsJsonObject()));
});

Foo parseJsonToFoo(JsonObject jsonObject) {
    Foo foo = new Foo();
    if (jsonObject.has("bar")) {
        String data = jsonObject.get("bar").getAsString();
        foo.setBar(data);
    }
    if (jsonObject.has("tar")) {
        Double data = jsonObject.get("tar").getAsDouble();
        foo.setTar(data);
    }
    return foo;
}

0

我通过创建JSON的POJO类(Student.class)并在主类中读取JSON中的值来解决了这个问题。

   **Main Class**

    public static void main(String[] args) throws JsonParseException, 
       JsonMappingException, IOException {

    String jsonStr = "[ \r\n" + "    {\r\n" + "        \"firstName\" : \"abc\",\r\n"
            + "        \"lastName\" : \"xyz\"\r\n" + "    }, \r\n" + "    {\r\n"
            + "        \"firstName\" : \"pqr\",\r\n" + "        \"lastName\" : \"str\"\r\n" + "    } \r\n" + "]";

    ObjectMapper mapper = new ObjectMapper();

    List<Student> details = mapper.readValue(jsonStr, new 
      TypeReference<List<Student>>() {      });

    for (Student itr : details) {

        System.out.println("Value for getFirstName is: " + 
                  itr.getFirstName());
        System.out.println("Value for getLastName  is: " + 
                 itr.getLastName());
    }
}

**RESULT:**
         Value for getFirstName is: abc
         Value for getLastName  is: xyz
         Value for getFirstName is: pqr
         Value for getLastName  is: str


 **Student.class:**

public class Student {
private String lastName;

private String firstName;

public String getLastName() {
    return lastName;
}

public String getFirstName() {
    return firstName;
} }

虽然这段代码可能回答了问题,但最好包含一些上下文,解释它的工作原理以及何时使用它。仅有代码的答案从长远来看并不有用。 - Alex Riabov
@AlexRiabov已经为此添加了上下文。 - Atul KS

0
In your json , top most element name should be matched with the name of variable in your wrapper class. That will Jacson to convert my json into participantJsonList.
{
"participantJsonList" : [ 
    {
        "firstName" : "abc",
        "lastName" : "xyz"
    }, 
    {
        "firstName" : "pqr",
        "lastName" : "str"
    } 
]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接