如何使用 Jackson 将字符串反序列化为自定义对象?
How do I deserialize a string as a custom object with Jackson?
我有这个 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
中,所以我真的需要一个单独的反序列化器来 Name
.
var tree = parser.getCodec().readTree(parser);
var name = (TextNode) tree.get("name");
return Person.create(Name.valueOf(name.asText()));
如何在不求助于中间 POJO 的情况下进行反序列化?
如果你可以修改Person,你可以使用@JsonCreator:
@JsonCreator
public static Person create(@JsonProperty("name") String name) {
Name nameInstance = Name.valueOf(name);
return new Person(nameInstance);
}
这将正确使用 JSON,将“名称”属性 映射到方法的第一个参数。
如果您无法修改 class,您可以使用 mixin 方法,创建 mixin:
interface PersonMixin {
@JsonCreator
public static Person create(@JsonProperty("name") Name name) {return null;}
}
并在映射器中注册:
mapper.addMixIn(Person.class, PersonMixin.class);
我必须对 NameDeserializer
使用 parser.getValueAsString()
,对 PersonDeserializer
使用 codec.treeToValue()
:
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);
}
}
我有这个 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
中,所以我真的需要一个单独的反序列化器来 Name
.
var tree = parser.getCodec().readTree(parser);
var name = (TextNode) tree.get("name");
return Person.create(Name.valueOf(name.asText()));
如何在不求助于中间 POJO 的情况下进行反序列化?
如果你可以修改Person,你可以使用@JsonCreator:
@JsonCreator
public static Person create(@JsonProperty("name") String name) {
Name nameInstance = Name.valueOf(name);
return new Person(nameInstance);
}
这将正确使用 JSON,将“名称”属性 映射到方法的第一个参数。
如果您无法修改 class,您可以使用 mixin 方法,创建 mixin:
interface PersonMixin {
@JsonCreator
public static Person create(@JsonProperty("name") Name name) {return null;}
}
并在映射器中注册:
mapper.addMixIn(Person.class, PersonMixin.class);
我必须对 NameDeserializer
使用 parser.getValueAsString()
,对 PersonDeserializer
使用 codec.treeToValue()
:
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);
}
}