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?

Ollie Edwards
sumber
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));
Programmer Bruce
sumber
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

Marthym
sumber
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);
}
Obi Wan - PallavJha
sumber
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);
Greg D
sumber
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();
}
Jerome
sumber
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;
    }
Tiago Medici
sumber
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);
pero_hero
sumber
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;
}
lbenedetto
sumber