Làm thế nào để sử dụng Jackson để giải tuần tự hóa một loạt các đối tượng


779

Tài liệu ràng buộc dữ liệu của Jackson chỉ ra rằng Jackson hỗ trợ giải trừ "Mảng của tất cả các loại được hỗ trợ" nhưng tôi không thể tìm ra cú pháp chính xác cho việc này.

Đối với một đối tượng duy nhất tôi sẽ làm điều này:

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

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

Bây giờ cho một mảng tôi muốn làm điều này:

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

//Java
List<MyClass> entries = ?

Bất cứ ai cũng biết nếu có một lệnh thiếu ma thuật? Nếu không thì giải pháp là gì?


2
Tôi thích thư viện GSON của Google để xử lý JSON. Thật đáng để kiểm tra nếu bạn chưa thử nó ... làm cho nó hoạt động rất dễ dàng và trực quan.
Jesse Webb

11
FWIW Các giải pháp khả thi cho vấn đề cụ thể này với Gson gần như giống hệt với những gì có thể với API Binding Data của Jackson.
Lập trình viên Bruce

17
Gweebz - có lẽ bạn muốn giải thích lý do tại sao bạn cảm thấy GSON là lựa chọn tốt hơn (so với Jackson)?
StaxMan

Câu trả lời:


1656

Đầu tiên tạo một trình ánh xạ:

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

Như Mảng:

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

Như danh sách:

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

Một cách khác để xác định loại Danh sách:

List<MyClass> myObjects = mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(List.class, MyClass.class));

43
Một lưu ý nữa, nếu trong khi phân tích cú pháp bạn gặp lỗi như vậy JsonMappingException: No suitable constructor found for typethì điều đó có nghĩa là bạn cần thêm một hàm tạo mặc định vào lớp của bạn, thêm một hàm tạo không có đối số riêng đã sửa nó cho tôi.
Cú pháp

12
@SyntaxRules thêm hàm tạo rõ ràng là cần thiết nếu bạn có hàm tạo rõ ràng - nếu không, trình biên dịch sẽ tự động tạo hàm tạo "trống" công khai. Điểm tốt. Một vấn đề phổ biến khác là các lớp bên trong cần phải có static- nếu không thì chúng không bao giờ có hàm tạo zero-arg.
StaxMan

244
Btw, List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class))hoạt động nhanh hơn tới 10 lần so với TypeRefence.

5
Tôi đang tìm kiếm một phiên bản loại chung chung.
Stephane

1
@EugeneTskhovrebov theo cách của bạn là sạch nhất cho nội tuyến. Những người khác yêu cầu đúc hoặc khai báo. Tôi đề nghị thêm nó làm câu trả lời của riêng mình để giúp làm nổi bật nó, và cung cấp cho bạn một số đại diện.
Erik B

190

Từ Eugene Tskhovrebov

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

Giải pháp này có vẻ là tốt nhất cho tôi


Đối với những người làm việc với Đại lý trong Java, Lotus Domino, đây là cách để đi. Tôi đã thử một số giải pháp khác, nhưng luôn nhận đượcResourceNotFoundException
John

Bổ sung SyntaxRules trong các ý kiến ​​cho câu trả lời ở trên có thể được yêu cầu cho giải pháp này vì chúng tôi, nó là dành cho tôi. Tôi chỉ muốn thêm rằng nó không bị mất.
Rob

2
hoặcArrays.asList(Json.fromJson(json.get("fieldName"), MyClass[].class))
Al-Mothafar

3
hoặcList<MyClass> myObjects = Arrays.asList(mapper.treeToValue(jsonNode.get("fieldName"), MyClass[].class))
Collin Krawll

@CollinKrawll objectmapper.treetovalue làm gì?
Eswar

35

Để thực hiện chung:

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

4
Cấu trúc đẹp của Lớp <T []>. Chưa bao giờ thấy điều này. Bạn đã tìm thấy thông tin về điều này ở đâu?
Roeland Van Heddegem

11

Đầu tiên tạo một thể hiện của ObjectReader là luồng an toàn.

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

Sau đó sử dụng nó:

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

Đây chính xác là những gì tôi đang tìm kiếm, cảm ơn
độc lập

chúng tôi nhận được - com.fasterxml.jackson.databind.JsonMappingException: Không thể giải trừ phiên bản java.util.ArrayList ra khỏi mã thông báo START_OB DỰ ÁN tại [Nguồn: java.io.FileInputStream@33fec21; dòng: 1, cột: 1]
Dinesh Kumar

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

3

đây là một tiện ích có thể thay đổi json2object hoặc Object2json, bất kể pojo của bạn (thực thể 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;
    }

0

bạn cũng có thể tạo một lớp mở rộng ArrayList:

public static class MyList extends ArrayList<Myclass> {}

và sau đó sử dụng nó như:

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

0

Tôi không thể sử dụng câu trả lời này vì người nói dối của tôi sẽ không cho phép các diễn viên không được kiểm tra.

Đây là một thay thế bạn có thể sử dụng. Tôi cảm thấy nó thực sự là một giải pháp sạch hơn.

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.