Jackson làm cách nào để chuyển đổi JsonNode thành ArrayNode mà không cần ép kiểu?


116

Tôi đang thay đổi thư viện JSON của mình từ org.json sang Jackson và tôi muốn di chuyển mã sau:

JSONObject datasets = readJSON(new URL(DATASETS));
JSONArray datasetArray =  datasets.getJSONArray("datasets");

Bây giờ ở Jackson, tôi có những thứ sau:

ObjectMapper m = new ObjectMapper();
JsonNode datasets = m.readTree(new URL(DATASETS));      
ArrayNode datasetArray = (ArrayNode)datasets.get("datasets");

Tuy nhiên tôi không thích dàn diễn viên ở đó, có khả năng cho một ClassCastException? Có phương thức nào tương đương với getJSONArraytrong org.jsonđể tôi có cách xử lý lỗi thích hợp trong trường hợp nó không phải là một mảng không?


Rất tiếc, tôi không thể sử dụng ánh xạ đầy đủ vì dữ liệu không cố định tên trường.
Konrad Höffner

1
Nếu tên trường đến từ một tập hợp giới hạn, bạn có thể muốn xác định một lớp có tất cả chúng và sử dụng FAIL_ON_UNKNOWN_PROPERTIEStính năng của bộ giải mã để chỉ trả về giá trị null trong các trường không sử dụng. Nhưng tất nhiên đó chỉ là một tùy chọn nếu bộ tên trường tương đối hạn chế.
fvu

Hm Tôi nghĩ giải pháp này không phù hợp nhất trong trường hợp của tôi nhưng tôi sẽ nhớ nó trong trường hợp tôi gặp sự cố với một bộ giới hạn đã được biết trước!
Konrad Höffner

Câu trả lời:


247

Vâng, thiết kế trình phân tích cú pháp thủ công Jackson khá khác biệt so với các thư viện khác. Đặc biệt, bạn sẽ nhận thấy rằng JsonNodecó hầu hết các chức năng mà bạn thường kết hợp với các nút mảng từ các API khác. Như vậy, bạn không cần phải truyền đến một ArrayNodeđể sử dụng. Đây là một ví dụ:

JSON:

{
    "objects" : ["One", "Two", "Three"]
}

Mã:

final String json = "{\"objects\" : [\"One\", \"Two\", \"Three\"]}";

final JsonNode arrNode = new ObjectMapper().readTree(json).get("objects");
if (arrNode.isArray()) {
    for (final JsonNode objNode : arrNode) {
        System.out.println(objNode);
    }
}

Đầu ra:

"Một"
"Hai"
"Ba"

Lưu ý việc sử dụng isArrayđể xác minh rằng nút thực sự là một mảng trước khi lặp lại. Việc kiểm tra là không cần thiết nếu bạn hoàn toàn tin tưởng vào cấu trúc dữ liệu của mình, nhưng nó có sẵn nếu bạn cần (và điều này không khác với hầu hết các thư viện JSON khác).


2
Bạn đã tiết kiệm cho tôi hàng giờ. Cảm ơn!
Igor Morais

Tôi có thể biết tại sao "cuối cùng" được sử dụng trong dòng "cho (JsonNode cuối cùng objNode: arrNode)" không?
Anthony Vinay

5

Trong Java 8, bạn có thể làm như sau:

import java.util.*;
import java.util.stream.*;

List<JsonNode> datasets = StreamSupport
    .stream(datasets.get("datasets").spliterator(), false)
    .collect(Collectors.toList())

1

Có phương thức nào tương đương với getJSONArray trong org.json để tôi xử lý lỗi thích hợp trong trường hợp nó không phải là một mảng không?

Nó phụ thuộc vào đầu vào của bạn; tức là những thứ bạn lấy từ URL. Nếu giá trị của thuộc tính "bộ dữ liệu" là một mảng kết hợp chứ không phải là một mảng thuần túy, bạn sẽ nhận được một ClassCastException.

Nhưng một lần nữa, độ chính xác của phiên bản cũ của bạn cũng phụ thuộc vào đầu vào. Trong tình huống phiên bản mới của bạn ném a ClassCastException, phiên bản cũ sẽ ném JSONException. Tham khảo: http://www.json.org/javadoc/org/json/JSONObject.html#getJSONArray(java.lang.String)


Được rồi, tôi có thể bắt được ClassCastException, cảm ơn! Đối với sở thích của tôi, nó hơi kém thanh lịch hơn một chút so với việc có một JsonException cụ thể nhưng nếu không thể thì vẫn tốt.
Konrad Höffner

0

Tôi sẽ giả sử vào cuối ngày bạn muốn sử dụng dữ liệu trong ArrayNode bằng cách lặp lại nó. Vì điều đó:

Iterator<JsonNode> iterator = datasets.withArray("datasets").elements();
while (iterator.hasNext()) 
        System.out.print(iterator.next().toString() + " "); 

hoặc nếu bạn tham gia vào các luồng và các hàm lambda:

import com.google.common.collect.Streams;
Streams.stream(datasets.withArray("datasets").elements())
    .forEach( item -> System.out.print(item.toString()) )
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.