Ich versuche, ein Tutorial von Programmierer Bruce durchzuarbeiten, das die Deserialisierung von polymorphem JSON ermöglichen soll.
Die vollständige Liste finden Sie hier Programmer Bruce Tutorials (Great stuff btw)
Ich habe die ersten fünf ohne Probleme durchgearbeitet, aber ich habe beim letzten einen Haken bekommen (Beispiel 6), was natürlich derjenige ist, den ich wirklich brauche, um arbeiten zu können.
Beim Kompilieren wird der folgende Fehler angezeigt
Die Methode readValue (JsonParser, Class) vom Typ ObjectMapper gilt nicht für die Argumente (ObjectNode, Class).
und es wird durch den Codeblock verursacht
public Animal deserialize(
JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
Class<? extends Animal> animalClass = null;
Iterator<Entry<String, JsonNode>> elementsIterator =
root.getFields();
while (elementsIterator.hasNext())
{
Entry<String, JsonNode> element=elementsIterator.next();
String name = element.getKey();
if (registry.containsKey(name))
{
animalClass = registry.get(name);
break;
}
}
if (animalClass == null) return null;
return mapper.readValue(root, animalClass);
}
}
Speziell durch die Linie
return mapper.readValue (root, animalClass);
Hat jemand schon einmal darauf gestoßen und wenn ja, gab es eine Lösung?
Ich würde mich über jede Hilfe freuen, die jemand im Voraus geben kann. Jon D.
quelle
Antworten:
Wie versprochen, gebe ich ein Beispiel für die Verwendung von Anmerkungen zum Serialisieren / Deserialisieren polymorpher Objekte. Dieses Beispiel habe ich in der
Animal
Klasse aus dem Tutorial, das Sie gelesen haben, verwendet.Zunächst Ihre
Animal
Klasse mit den Json-Anmerkungen für die Unterklassen.import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) @JsonSubTypes({ @JsonSubTypes.Type(value = Dog.class, name = "Dog"), @JsonSubTypes.Type(value = Cat.class, name = "Cat") } ) public abstract class Animal { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Dann deine Unterklassen
Dog
undCat
.public class Dog extends Animal { private String breed; public Dog() { } public Dog(String name, String breed) { setName(name); setBreed(breed); } public String getBreed() { return breed; } public void setBreed(String breed) { this.breed = breed; } } public class Cat extends Animal { public String getFavoriteToy() { return favoriteToy; } public Cat() {} public Cat(String name, String favoriteToy) { setName(name); setFavoriteToy(favoriteToy); } public void setFavoriteToy(String favoriteToy) { this.favoriteToy = favoriteToy; } private String favoriteToy; }
Wie Sie sehen können, gibt es nichts Besonderes für
Cat
undDog
die einzige, die über sie wissen das istabstract
KlasseAnimal
, also wenn Deserialisieren, werden Ziel , das SieAnimal
und dasObjectMapper
wird die aktuelle Instanz zurück , wie Sie im folgenden Test sehen können:public class Test { public static void main(String[] args) { ObjectMapper objectMapper = new ObjectMapper(); Animal myDog = new Dog("ruffus","english shepherd"); Animal myCat = new Cat("goya", "mice"); try { String dogJson = objectMapper.writeValueAsString(myDog); System.out.println(dogJson); Animal deserializedDog = objectMapper.readValue(dogJson, Animal.class); System.out.println("Deserialized dogJson Class: " + deserializedDog.getClass().getSimpleName()); String catJson = objectMapper.writeValueAsString(myCat); Animal deseriliazedCat = objectMapper.readValue(catJson, Animal.class); System.out.println("Deserialized catJson Class: " + deseriliazedCat.getClass().getSimpleName()); } catch (Exception e) { e.printStackTrace(); } } }
Ausgabe nach dem Ausführen der
Test
Klasse:{"@type":"Dog","name":"ruffus","breed":"english shepherd"}
Deserialized dogJson Class: Dog
{"@type":"Cat","name":"goya","favoriteToy":"mice"}
Deserialized catJson Class: Cat
Hoffe das hilft,
Jose Luis
quelle
Dog
in der Anmerkung verknüpften Namen zusammenhängt, sondernname
nur ein Feld der serialisierten Klasse ist, wahrscheinlich um Verwirrung zu vermeiden, die ich inpetName
derAnimal
Klasse anstelle von hätte verwenden könnenname
. Das Jackson-Anmerkungsfeldname
ist der Wert, der auf den serialisierten Json als Bezeichner festgelegt werden soll. HTH.@JsonTypeIdResolver
(wahrscheinlich) das tut, was Sie brauchen: gist.github.com/root-talis/36355f227ff5bb7a057ff7ad842d37a3Serializable
, damit dieses Beispiel funktioniert.Sie benötigen nur eine Zeile vor der Deklaration der Klasse
Animal
für die korrekte polymorphe Serialisierung / Deserialisierung:@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") public abstract class Animal { ... }
Diese Zeile bedeutet:
include = JsonTypeInfo.As.PROPERTY
Fügen Sie bei der Serialisierung eine Meta-Eigenschaft hinzu oder lesen Sie bei der Deserialisierung ( ) eine Meta-Eigenschaft namens "@class" (property = "@class"
), die den vollständig qualifizierten Java-Klassennamen (use = JsonTypeInfo.Id.CLASS
) enthält.Wenn Sie also einen JSON direkt (ohne Serialisierung) erstellen, denken Sie daran, die Meta-Eigenschaft "@class" mit dem gewünschten Klassennamen für die korrekte Deserialisierung hinzuzufügen.
Weitere Informationen hier
quelle
Eine einfache Möglichkeit, die polymorphe Serialisierung / Deserialisierung über die Jackson-Bibliothek zu aktivieren, besteht darin, den Jackson-Objekt-Mapper (jackson.databind.ObjectMapper) global zu konfigurieren, um Informationen wie den konkreten Klassentyp für bestimmte Arten von Klassen, z. B. abstrakte Klassen, hinzuzufügen.
Stellen Sie dazu einfach sicher, dass Ihr Mapper richtig konfiguriert ist. Zum Beispiel:
Option 1: Unterstützung der polymorphen Serialisierung / Deserialisierung für abstrakte Klassen (und objekttypisierte Klassen)
Option 2: Unterstützung der polymorphen Serialisierung / Deserialisierung für abstrakte Klassen (und objekttypisierte Klassen) und Arrays dieser Typen.
Referenz: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
quelle
Wenn Sie dann die schnellere XML verwenden,
Diese Änderungen sind möglicherweise erforderlich
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.ObjectNode;
in der Hauptmethode--
verwenden
SimpleModule module = new SimpleModule("PolymorphicAnimalDeserializerModule");
anstatt
new SimpleModule("PolymorphicAnimalDeserializerModule", new Version(1, 0, 0, null));
Nehmen Sie in der Funktion Animal deserialize () die folgenden Änderungen vor
//Iterator<Entry<String, JsonNode>> elementsIterator = root.getFields(); Iterator<Entry<String, JsonNode>> elementsIterator = root.fields(); //return mapper.readValue(root, animalClass); return mapper.convertValue(root, animalClass);
Dies funktioniert für schnellerxml.jackson. Wenn es sich immer noch über die Klassenfelder beschwert. Verwenden Sie für die Feldnamen das gleiche Format wie im json (mit "_" -underscore). da dies
//mapper.setPropertyNamingStrategy(new CamelCaseNamingStrategy());
möglicherweise nicht unterstützt wird.abstract class Animal { public String name; } class Dog extends Animal { public String breed; public String leash_color; } class Cat extends Animal { public String favorite_toy; } class Bird extends Animal { public String wing_span; public String preferred_food; }
quelle