Jak używać Jacksona do deserializacji szeregu obiektów

779

Dokumentacja powiązania danych Jacksona wskazuje, że Jackson obsługuje deserializację „Tablic wszystkich obsługiwanych typów”, ale nie mogę ustalić dokładnej składni.

Dla pojedynczego obiektu zrobiłbym to:

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

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

Teraz dla tablicy chcę to zrobić:

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

//Java
List<MyClass> entries = ?

Czy ktoś wie, czy brakuje magicznej komendy? Jeśli nie, to jakie jest rozwiązanie?

Ollie Edwards
źródło
2
Wolę bibliotekę GSON Google do obsługi JSON. Warto sprawdzić, czy jeszcze tego nie próbowałeś ... sprawia, że ​​praca z nim jest bardzo łatwa i intuicyjna.
Jesse Webb
11
FWIW Możliwe rozwiązania tego konkretnego problemu z Gsonem są prawie identyczne jak w przypadku interfejsu API Data Binding Jacksona.
Programista Bruce
17
Gweebz - może chciałbyś wyjaśnić, dlaczego uważasz, że GSON jest lepszym wyborem (w porównaniu z Jacksonem)?
StaxMan

Odpowiedzi:

1654

Najpierw utwórz mapera:

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

As Array:

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

Jak lista:

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

Inny sposób określenia typu listy:

List<MyClass> myObjects = mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(List.class, MyClass.class));
Programista Bruce
źródło
43
Jedna dodatkowa uwaga, jeśli podczas analizowania wystąpi błąd, taki jak JsonMappingException: No suitable constructor found for typewtedy, oznacza to, że musisz dodać domyślny konstruktor do swojej klasy, dodając prywatny konstruktor bez argonu, który to naprawił.
Składnia Reguły
12
@SyntaxRules dodanie jawnego konstruktora jest konieczne, jeśli masz jawny konstruktor - jeśli nie, kompilator automatycznie tworzy publiczny „pusty” konstruktor. Słuszna uwaga. Innym częstym problemem jest to, że klasy wewnętrzne muszą być static- w przeciwnym razie nigdy nie będą miały konstruktora zero-arg.
StaxMan,
244
Btw, List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class))działa do 10 razy szybciej niż TypeRefence.
5
Szukam wersji typu ogólnego.
Stephane
1
@EugeneTskhovrebov twoja droga jest najczystsza do wkładania. Inne wymagają odlewania lub deklarowania. Sugeruję dodanie go jako własnej odpowiedzi, aby pomóc go podświetlić i dać ci kilka powtórzeń.
Erik B,
190

Od Eugeniusza Cchowrebowa

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

To rozwiązanie wydaje mi się najlepsze

Marthym
źródło
Dla tych, którzy pracują z agentami w Javie, Lotus Domino, jest to odpowiedni sposób. Próbowałem kilka innych rozwiązań, ale zawsze dostałemResourceNotFoundException
John
Dodanie składni Reguły w komentarzach do powyższej odpowiedzi może być wymagane dla tego rozwiązania, ponieważ my, to było dla mnie. Chciałem tylko to dodać, aby się nie zgubić.
Rob
2
lubArrays.asList(Json.fromJson(json.get("fieldName"), MyClass[].class))
Al-Mothafar,
3
lubList<MyClass> myObjects = Arrays.asList(mapper.treeToValue(jsonNode.get("fieldName"), MyClass[].class))
Collin Krawll
@CollinKrawll co robi objectmapper.treetovalue?
Eswar,
35

Do realizacji ogólnej:

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
źródło
4
Fajna konstrukcja klasy <T []>. Nigdy tego nie widziałem. Gdzie znalazłeś informacje na ten temat?
Roeland Van Heddegem,
11

Najpierw utwórz instancję ObjectReadera, która jest bezpieczna dla wątków.

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

Następnie użyj go:

List<MyClass> result = objectReader.readValue(inputStream);
Greg D.
źródło
Właśnie tego szukam, dziękuję
samodzielny
dostajemy - com.fasterxml.jackson.databind.JsonMappingException: Nie można deserializować wystąpienia java.util.ArrayList z tokenu START_OBJECT pod adresem [Źródło: java.io.FileInputStream@33fec21; wiersz: 1, kolumna: 1]
Dinesh Kumar
7
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
źródło
3

tutaj jest narzędzie, które jest w stanie przekształcić json2object lub Object2json, bez względu na twoje pojęcie (encja 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
źródło
0

możesz także stworzyć klasę, która rozszerza ArrayList:

public static class MyList extends ArrayList<Myclass> {}

a następnie użyj go w następujący sposób:

List<MyClass> list = objectMapper.readValue(json, MyList.class);
pero_hero
źródło