Cara menggunakan Jackson untuk men-deserialise array objek


780

The Data Jackson mengikat dokumentasi menunjukkan bahwa Jackson mendukung deserialising "Array dari semua jenis didukung" tapi saya tidak tahu sintaks yang tepat untuk ini.

Untuk satu objek saya akan melakukan ini:

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

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

Sekarang untuk sebuah array saya ingin melakukan ini:

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

//Java
List<MyClass> entries = ?

Adakah yang tahu jika ada perintah sihir yang hilang? Jika tidak maka apa solusinya?


2
Saya lebih suka perpustakaan GSON Google untuk berurusan dengan JSON. Perlu dicoba jika Anda belum mencobanya ... membuatnya bekerja dengan sangat mudah dan intuitif.
Jesse Webb

11
FWIW Solusi yang mungkin untuk masalah spesifik ini dengan Gson hampir identik dengan apa yang mungkin terjadi dengan API Pengikatan Data Jackson.
Programmer Bruce

17
Gweebz - mungkin Anda ingin menjelaskan mengapa Anda merasa GSON adalah pilihan yang lebih baik (dibandingkan dengan Jackson)?
StaxMan

Jawaban:


1657

Pertama-tama buat mapper:

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

Sebagai array:

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

Sebagai daftar:

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

Cara lain untuk menentukan jenis Daftar:

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

43
Satu catatan tambahan, jika saat parsing Anda mendapatkan kesalahan seperti JsonMappingException: No suitable constructor found for typeitu berarti Anda perlu menambahkan konstruktor default ke kelas Anda menambahkan konstruktor no-arg pribadi memperbaikinya untuk saya.
SyntaxRules

12
@SyntaxRules menambahkan konstruktor eksplisit diperlukan jika Anda memiliki konstruktor eksplisit - jika tidak, kompiler secara otomatis membuat konstruktor "kosong" publik. Poin yang bagus. Masalah umum lainnya adalah bahwa kelas dalam perlu static- jika tidak, mereka tidak akan memiliki konstruktor zero-arg.
StaxMan

244
Btw, List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class))bekerja hingga 10 kali lebih cepat dari TypeRefence.

5
Saya mencari versi tipe umum.
Stephane

1
@EugeneTskhovrebov cara Anda adalah yang terbersih untuk inlining. Yang lain membutuhkan casting atau mendeklarasikan. Saya sarankan menambahkannya sebagai jawaban sendiri untuk membantu menyorotnya, dan memberi Anda beberapa perwakilan.
Erik B

190

Dari Eugene Tskhovrebov

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

Solusi ini tampaknya menjadi yang terbaik untuk saya


Bagi mereka yang bekerja dengan Agen di Jawa, Lotus Domino, inilah cara yang harus ditempuh. Saya mencoba beberapa solusi lain, tetapi selalu mendapatResourceNotFoundException
John

Tambahan Sintaksis dalam komentar untuk jawaban di atas mungkin diperlukan untuk solusi ini karena kami, itu untuk saya. Saya hanya ingin menambahkan itu agar tidak hilang.
Rob

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

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

@CollinKrawll apa yang dilakukan objectmapper.treetovalue?
Eswar

35

Untuk Implementasi Generik:

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
Konstruksi bagus dari Kelas <T []>. Tidak pernah melihat ini. Di mana Anda menemukan informasi tentang ini?
Roeland Van Heddegem

11

Pertama buat instance dari ObjectReader yang aman-utas.

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

Kemudian gunakan:

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

Ini persis apa yang saya cari, terima kasih
berdiri sendiri

kita mendapatkan - com.fasterxml.jackson.databind.JsonMappingException: Tidak dapat membatalkan deserialisasi instance java.util.ArrayDaftar di luar token START_OBJECT di [Sumber: java.io.FileInputStream@33fec21; baris: 1, kolom: 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

di sini adalah utilitas yang dapat mengubah json2object atau Object2json, apa pun pojo Anda (entitas 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

Anda juga bisa membuat kelas yang meluas ArrayList:

public static class MyList extends ArrayList<Myclass> {}

dan kemudian gunakan seperti:

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

0

Saya tidak dapat menggunakan jawaban ini karena linter saya tidak akan mengizinkan gips yang tidak dicentang.

Inilah alternatif yang bisa Anda gunakan. Saya merasa ini sebenarnya solusi yang lebih bersih.

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;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.