我有这个 JSON 想要解析:
{
"name": "john",
}
我必须使用以下层次结构。这些类是不可变的,我必须通过静态工厂方法访问它们(这是必要的,因此建议修改 Name
或 Person
是没有意义的)。
class Name {
static Name valueOf(String name) {...}
private Name() {}
String name();
}
class Person {
static Person create(Name name) {...}
private Person() {...}
Name name();
}
为此,我想用 Jackson 反序列化一个 Person
,所以我写了这个:
public class NameJsonDeserializer extends JsonDeserializer<Name> {
@Override public Name deserialize(JsonParser parser, DeserializationContext context) {
var tree = parser.getCodec().readTree(parser);
var name = tree.asToken().asString();
return Name.valueOf(name);
}
}
public class PersonJsonDeserializer extends JsonDeserializer<Person> {
@Override public Person deserialize(JsonParser parser, DeserializationContext context) {
var tree = parser.getCodec().readTree(parser);
var name = (ObjectNode) tree.get("name");
return Person.create(name);
}
}
当然,这行不通。它甚至无法编译。
我知道我可以编写类似于以下内容的内容,但是 Name
到处都在使用,而且并不总是在 Person
中,所以我真的需要一个单独的 {{1} 反序列化器}.
Name
如何在不求助于中间 POJO 的情况下反序列化?
答案 0 :(得分:1)
如果你可以修改Person,你可以使用@JsonCreator:
@JsonCreator
public static Person create(@JsonProperty("name") String name) {
Name nameInstance = Name.valueOf(name);
return new Person(nameInstance);
}
这将正确使用该 JSON,将“name”属性映射到方法的第一个参数。
如果你不能修改类,你可以使用mixin方法,创建mixin:
interface PersonMixin {
@JsonCreator
public static Person create(@JsonProperty("name") Name name) {return null;}
}
并在映射器中注册它:
mapper.addMixIn(Person.class, PersonMixin.class);
答案 1 :(得分:1)
我必须对 parser.getValueAsString()
使用 NameDeserializer
,对 codec.treeToValue()
使用 PersonDeserializer
:
public class NameJsonDeserializer extends JsonDeserializer<Name> {
@Override public Name deserialize(JsonParser parser, DeserializationContext context) {
var name = parser.getValueAsString();
return Name.valueOf(name);
}
}
public class PersonJsonDeserializer extends JsonDeserializer<Person> {
@Override public Person deserialize(JsonParser parser, DeserializationContext context) {
var codec = parser.getCodec();
var tree = codec.readTree(parser);
var name = codec.treeToValue(tree.get("name"), Name.class);
return Person.create(name);
}
}