2015-12-04 3 views
5

Ich verwende Jackson, um polymorphe Typen von JSON zu entpacken. Ich verwende die @JsonTypeInfo, @JsonSubTypes und @JsonTypeName Annotationen ähnlich wie in Beispiel 4 in this post. Meine Frage ist, sagen Sie jetzt, ich brauche jemand anderen, um meinen Code zu erweitern und eine 3. Klasse hinzuzufügen: public class Duck extends Animal außerhalb der ursprünglichen Codebasis. Wie kann ich (oder die anderen) die SubType-Informationen hinzufügen, ohne den Quellcode (Annotation) von public abstract Animal class zu ändern?Add SubType Informationen zur Laufzeit mit Jackson für Polymorphismus

UPDATE:

Ich bin gezwungen @JsonTypeName zu verwenden, um die POJO Versionsänderungen zu lösen. Zum Beispiel:

package my.zoo; 
@JsonTypeInfo( 
    use = JsonTypeInfo.Id.NAME, 
    include = JsonTypeInfo.As.PROPERTY, 
    property = "type") 
@JsonSubTypes({ 
    @Type(value = Cat.class, name = "[email protected]"), 
    @Type(value = Dog.class, name = "[email protected]"), 
    @Type(value = Catv2.class, name = "[email protected]")}) 
public abstract class Animal { 
    ... 
} 

@JsonTypeName("[email protected]") 
public class Cat extends Animal { 
    ... 
} 

@JsonTypeName("[email protected]") 
public class Catv2 extends Animal { 
    ... 
} 

@JsonTypeName("[email protected]") 
public class Dog extends Animal { 
    ... 
} 

// in another java package/project 
package another.zoo; 
import my.zoo.*; 

@JsonTypeName("[email protected]") 
public class Dogv2 extends Animal { 
    ... 
} 

nun das Problem, das ich bin vor ist, dass ich nicht ein JSON entpacken kann, die ohne Zugabe von @Type(value = another.zoo.Dogv2.class, name = "[email protected]")}) zur Animal Klasse geben Sie den Namen „[email protected]“ hat. Es ist also offensichtlich nicht möglich, dies mit Anmerkungen zu tun. Gibt es eine Möglichkeit, dies zur Laufzeit zu tun? 2

UPDATE:

Ich habe gerade this SO question mit dem gleichen/ähnlichen Anwendungsfall. Meine Sorge hier ist, dass die Verwendung von Annotation verhindert, dass Personen Ihre Basisklasse/Schnittstelle erweitern/implementieren. Ich möchte eine Möglichkeit, die Erweiterbarkeit meiner Basisklasse/Schnittstelle beizubehalten, und sicherstellen, dass meine (Un-) Marshalling-Logik mit zukünftigen konkreten Typen funktioniert.

Antwort

3

Ich endete mit Reflections-Bibliothek, um alle Untertypen der Animal Klasse zu finden, und registrieren JsonSubTypes mit mapper.registerSubtypes(Class<?>... classes) Methode.

+0

Was haben Sie mit der @ JsonTypeInfo-Annotation gemacht? Haben Sie JsonTypeInfo.Id.NAME verwendet? – ampofila

+0

@ampofila, der Modellcode ist wie im Beispielcode gezeigt. Das. RegisterSubtypes() - Aufrufe wurden während des Bootstrappings im Anwendungstreiber ausgeführt. Jackson würde sich um alles kümmern, wenn er den JSer deserialisiert. – derrdji

+0

Danke für die schnelle Antwort.Jedoch bin ich nicht sicher, wie man einen REST-Service abfängt (ich habe einen Controller, der als Schnittstelle die Schnittstelle nimmt und den eingehenden json automatisch unmarshalls). Ihr Weg funktioniert, wenn ich etwas aus einer Datei lese, aber es ist nicht für eine POST-Anfrage mit REST geeignet. – ampofila

2

Verwenden Sie nicht @JsonSubTypes. Verwenden Sie @JsonTypeInfo#use mit JsonTypeInfo.Id.CLASS, um Typen für Serialisierung und Deserialisierung zu identifizieren.

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type") 
abstract class Animal { /* whatever */ } 

Jackson speichert dann den vollständig qualifizierten Namen des Objekts serialisiert werden und es zu verwenden, wieder eine Zielklasse für die Deserialisierung zu bestimmen.

Sie müssen sicherstellen, dass keine der Unterklassen eine Eigenschaft mit dem Namen type hat.


Es ist möglich, diese Arbeit mit @JsonSubTypes zu machen, aber es geht Mixins und ist nicht eine sehr wartbar Lösung.

+0

Danke für den Tipp! Ich bin jedoch gezwungen, @ JsonTypeName ("") Annotation wie im aktualisierten Beispiel zu verwenden. Gibt es eine Möglichkeit, damit zu arbeiten? – derrdji

+0

@SotiriosDelimanolis Ja, aber auf diese Weise müssen Sie immer noch den vollständigen Klassennamen im JSON-Text übergeben (zB. {"Type": "my.class", "data": {...}}). Recht? – ampofila

+0

@ampofila In diesem Setup ja. Es gibt ['JsonTypeInfo.Id.Custom'] (http://fasterxml.github.io/jackson-annotations/javadoc/2.6/com/fasterxml/jackson/annotation/JsonTypeInfo.Id.html#CUSTOM) für weitere Optionen. –