Ich muss einen benutzerdefinierten Deserializer für eine Klasse mit Generika schreiben. Ich konnte keinen Weg finden, dies zu tun, aber ich kann mir nicht vorstellen, dass ich der Einzige mit diesem Problem bin. Soweit ich durch sie gedacht haben, gäbe es zwei Möglichkeiten, dies zu implementieren, aber keiner von ihnen sind implementierbar:Jackson Deserializer für den generischen Typ
- im Konstruktor der Deserializer eine Klasse Parameter dem Deserializer Providing, funktioniert nicht weil bei der Registrierung des Deserializers die Beziehung zwischen Type.class und der Instanz des Deserializers mit der übergebenen Klasseninstanz verloren geht.
Zum Beispiel:
public class Foo<T> {}
public class FooDeserializer<T> {
public FooDeserializer(Class<T> type) { ... }
...
}
// Boilerplate code...
module.addDeserializer(Foo.class, new FooDeserializer<Bar1>(Bar1.class));
module.addDeserializer(Foo.class, new FooDeserializer<Bar2>(Bar2.class));
Dies funktioniert nicht, wenn eine ObjectMapper Instanz eine Instanz von Foo bekommt, gibt es keine Typinformationen des generischen Parameters zur Verfügung (Typ Löschung), so dass es wählt einfach die letzter Deserializer registriert.
- Es hilft nicht, einen Verweis auf den generischen Typ in der Klasse beizubehalten, da eine instanziierte Version der Klasse nicht an den Deserializer übergeben werden kann (die Schnittstelle ist readValue (String, Klasse)).
Zum Beispiel:
String json = "...";
ObjectMapper mapper = ...;
Foo<Bar1> foo = new Foo<>(Bar1.class);
foo = mapper.readValue(json, Foo.class); // Can't pass empty foo instance with Class<?> field containing Bar1.class
So etwas wie dies erforderlich wäre:
mapper.readValue(json, Foo.class, Bar1.class); // Doesn't exist in jackson
Irgendwelche Vorschläge, wie dies zu tun?
EDIT: ich einen Weg gefunden, um das Problem zu lösen, aber es ist nicht eine saubere Lösung:
Ich erweitere die FooDeserializer mit einem Klasse-Feld den Typ des Foo generischen Parameter zu speichern. Jedes Mal, wenn ich einen JSON in eine neue Foo-Instanz deserialisieren möchte, erhalte ich eine neue ObjectMapper-Instanz (ich verwende ObjectMapper # copy auf einer vorkonfigurierten Instanz einer Factory) und gebe ihr ein neues Modul, das eine Instanz des FooDeserializer enthält der Klassenparameter (ich kenne den Typ zu diesem Zeitpunkt). Module, FooDeserializer und die ObjectMapper-Kopie sind kurzlebig, sie werden nur für diese einzelne Deserialisierungsaktion instanziiert. Wie gesagt, nicht sehr sauber, aber immer noch besser, als Foo viele Male zu unterlegen und für jeden einen Deserializer zu schreiben.
Beispiel:
public class FooDeserializer<T> extends StdDeserializer<T> {
private Class<T> type;
public FooDeserializer(Class<T> type) { this.type = type }
...
}
// Meanwhile, before deserialization:
ObjectMapper mapper = MyObjectMapperFactory.get().copy();
SimpleModule module = new SimpleModule(new Version(0,0,1,null,null,null);
module.addDeserializer(Foo.class, new FooDeserializer(Bar1.class);
mapper.addModule(module);
Foo<Bar1> x = mapper.readValue(json, Foo.class);
Wahrscheinlich dies in eine Dienstprogramm Methode setzt die uglyness zu verstecken.
http://stackoverflow.com/questions/11664894/jackson-deserialize-using-generic-class kann helfen – Wilson