Ich versuche, einen generischen Deserializer für alle Klassen zu implementieren, die sich von einer bestimmten abstrakten Klasse erstrecken oder eine bestimmte Schnittstelle implementieren. In diesem Beispiel verwende ich die Schnittstelle StringConvertible
. Ich muss den konkreten Typ bestimmen und damit kann ich eine Instanz erstellen.Wie verwende ich Jacksons ContextualDeserializer für Root-Werte?
Eine old forum post by Programmer Bruce führte mich zu ContextDeserializer und es funktioniert, wenn die StringConvertible eine Eigenschaft in einer anderen Klasse ist.
Aber wenn ich die StringConvertible direkt deserialisieren möchte, kann ich keinen Weg finden, den konkreten Typ zu erhalten, weil der beanProperty
Parameter null
ist. Offenbar wird das erwartet, nach this question/answer im Jackson JSON Benutzergruppe: The only case where property should be null is when serializing a "root value", meaning the object instance passed directly to ObjectMapper's (or ObjectWriter's) writeValue() method -- in this case there simply isn't a referring property. But otherwise it should always be passed.
unter Hauptmethode Siehe als Beispiel für beide Fälle:
@JsonDeserialize(using = StringConvertibleDeserializer.class)
public final class SomeStringConvertible implements StringConvertible {
private final String value;
public SomeStringConvertible(final String value) {
this.value = value;
}
@Override
@JsonValue
public String stringValue() {
return value;
}
}
public final class SomeWrapper {
public SomeStringConvertible stringConvertible;
public SomeWrapper() {
}
}
public class StringConvertibleDeserializer extends StdDeserializer<StringConvertible> implements ContextualDeserializer {
private final Class<? extends StringConvertible> targetClass;
StringConvertibleDeserializer() {
super(StringConvertible.class);
this.targetClass = null;
}
StringConvertibleDeserializer(final Class<? extends StringConvertible> targetClass) {
super(StringConvertible.class);
this.targetClass = targetClass;
}
@Override
public JsonDeserializer<?> createContextual(final DeserializationContext deserializationContext, @Nullable final BeanProperty beanProperty)
throws JsonMappingException {
final StringConvertibleDeserializer contextualDeserializer;
// ==== Determine target type =====
final Class<? extends StringConvertible> targetClass;
JavaType type = beanProperty.getType(); // -> beanProperty is null when the StringConvertible type is a root value
targetClass = (Class<? extends StringConvertible>) type.getRawClass();
// ==== Create contextual deserializer =====
contextualDeserializer = new StringConvertibleDeserializer(targetClass);
// ==== Return =====
return contextualDeserializer;
}
@Override
public StringConvertible deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
final StringConvertible value;
// ==== Create instance using the target type =====
if (targetClass.equals(SomeStringConvertible.class))
value = new SomeStringConvertible(jsonParser.getText());
else {
throw new RuntimeException();
}
// ==== Return =====
return value;
}
}
public final class JacksonModule extends SimpleModule {
public JacksonModule() {
super();
addDeserializer(StringConvertible.class, new StringConvertibleDeserializer());
}
}
public final class Main {
public static void main(String[] args) {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JacksonModule());
final String wrappedValueJSON = "{\"stringConvertible\":\"hello world\"}";
final String rootValueJSON = "\"hello world\"";
try {
mapper.readValue(wrappedValueJSON, SomeWrapper.class); // This works fine
mapper.readValue(rootValueJSON, SomeStringConvertible.class); // This causes a NPE in createContextual(...) because beanProperty is null
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Frage: Wie kann ich Typ konkreter bekommen im Falle eines Root-Wertes? Oder, wenn es eine bessere Lösung als diese gibt, was würden Sie stattdessen vorschlagen?
Eindrucksvolle Detektivarbeit hier - Danke für das Teilen! – StaxMan
Vielen Dank für das Teilen!Dies war das letzte Puzzleteil für mich, als ich versuchte, dieses spezielle Problem zu lösen: https://gist.github.com/darylteo/a7be65b539c0d8d3ca0de94d96763f33 –