Verwendung von Jackson zum Deserialisieren einer Reihe von Objekten


779

Aus der Jackson-Datenbindungsdokumentation geht hervor , dass Jackson das Deserialisieren von "Arrays aller unterstützten Typen" unterstützt, aber ich kann die genaue Syntax dafür nicht herausfinden.

Für ein einzelnes Objekt würde ich Folgendes tun:

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

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

Nun möchte ich für ein Array Folgendes tun:

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

//Java
List<MyClass> entries = ?

Weiß jemand, ob ein magischer Befehl fehlt? Wenn nicht, was ist dann die Lösung?


2
Ich bevorzuge die GSON-Bibliothek von Google für den Umgang mit JSON. Es lohnt sich zu prüfen, ob Sie es noch nicht ausprobiert haben ... macht die Arbeit damit sehr einfach und intuitiv.
Jesse Webb

11
FWIW Die möglichen Lösungen für dieses spezielle Problem mit Gson sind fast identisch mit denen, die mit Jacksons Datenbindungs-API möglich sind.
Programmierer Bruce

17
Gweebz - vielleicht möchten Sie erklären, warum GSON Ihrer Meinung nach die bessere Wahl ist (im Vergleich zu Jackson)?
StaxMan

Antworten:


1656

Erstellen Sie zuerst einen Mapper:

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

Als Array:

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

Als Liste:

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

Eine andere Möglichkeit, den Listentyp anzugeben:

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

43
Ein zusätzlicher Hinweis: Wenn beim Parsen ein Fehler auftritt, JsonMappingException: No suitable constructor found for typebedeutet dies, dass Sie Ihrer Klasse einen Standardkonstruktor hinzufügen müssen, indem Sie einen privaten Konstruktor ohne Argumente hinzufügen, der ihn für mich behoben hat.
SyntaxRules

12
@SyntaxRules Hinzufügen eines expliziten Konstruktors ist erforderlich, wenn Sie einen expliziten Konstruktor haben. Andernfalls erstellt der Compiler automatisch einen öffentlichen "leeren" Konstruktor. Guter Punkt. Ein weiteres häufiges Problem ist, dass innere Klassen sein müssen static- andernfalls haben sie niemals einen Null-Arg-Konstruktor.
StaxMan

244
Übrigens, List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class))arbeitet bis zu 10 Mal schneller als TypeRefence.

5
Ich suche eine generische Version.
Stephane

1
@EugeneTskhovrebov Ihr Weg ist der sauberste zum Inlining. Die anderen müssen gegossen oder deklariert werden. Ich schlage vor, es als eigene Antwort hinzuzufügen, um es hervorzuheben, und Ihnen einige Wiederholungen zu geben.
Erik B

190

Von Eugene Tskhovrebov

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

Diese Lösung scheint für mich die beste zu sein


Für diejenigen, die mit Agenten in Java, Lotus Domino, arbeiten, ist dies der richtige Weg. Ich habe einige der anderen Lösungen ausprobiert, aber immer eineResourceNotFoundException
John

Die Hinzufügung von SyntaxRules in den Kommentaren für die obige Antwort kann für diese Lösung erforderlich sein, so wie wir es für mich waren. Ich wollte das nur hinzufügen, damit es nicht verloren geht.
Rob

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

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

@CollinKrawll Was macht objectmapper.treetovalue?
Eswar

35

Für die generische Implementierung:

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
Schönes Konstrukt der Klasse <T []>. Ich habe das nie gesehen. Wo haben Sie Informationen dazu gefunden?
Roeland Van Heddegem

11

Erstellen Sie zunächst eine Instanz von ObjectReader, die threadsicher ist.

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

Dann benutze es:

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

Dies ist genau das, wonach ich suche, danke
Standalone

wir bekommen - com.fasterxml.jackson.databind.JsonMappingException: Instanz von java.util.ArrayList kann nicht aus dem START_OBJECT-Token unter [Quelle: java.io.FileInputStream@33fec21; Zeile: 1, Spalte: 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();
}

3

Hier ist ein Dienstprogramm, mit dem Sie json2object oder Object2json transformieren können, unabhängig von Ihrem Pojo (Entität 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

Sie können auch eine Klasse erstellen, die Folgendes erweitert ArrayList:

public static class MyList extends ArrayList<Myclass> {}

und dann benutze es wie:

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

0

Ich konnte diese Antwort nicht verwenden da mein Linter keine ungeprüften Würfe zulässt.

Hier ist eine Alternative, die Sie verwenden können. Ich denke, es ist tatsächlich eine sauberere Lösung.

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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.