我有一个相对复杂的对象,其中包含许多字段。我需要使用自定义序列化程序序列化其中一个字段,但需要模拟@JsonUnwrapped
功能。
为了简单起见,我将其分为两个领域:
public class MyClass
{
@JsonProperty("subject")
private final String subject;
@JsonSerialize(using=MySenderSerializer.class)
private final MailActor sender;
}
我的自定义序列化程序类如下:
public class MySenderSerializer extends StdSerializer<MailActor>
{
public MySenderSerializer()
{
super(MailActor.class, true);
}
@Override
public void serialize(final MailActor value, final JsonGenerator gen, final SerializerProvider provider) throws IOException
{
gen.writeStringField("from_name", value.getName());
gen.writeStringField("from_email", value.getAddress());
}
}
所有这些都很好,除了输出JSON看起来像这样:
{
...
"subject": "test subject",
"sender": {
"from_name": "test from",
"from_email": "test@test.com"
},
...
}
我需要打开sender
字段,以便JSON看起来像这样:
{
...
"subject": "test subject",
"from_name": "test from",
"from_email": "test@test.com",
...
}
如果我使用的是标准序列化程序,我可以使用@JsonUnwrapped
注释来执行此操作,但它似乎与自定义序列化程序不兼容。如何在不为MyClass
对象编写自定义序列化程序的情况下获取所需的JSON输出?
答案 0 :(得分:1)
我也不得不寻找 @JsonUnwrapped 的替代品,因为这引起了我对这个问题的一些无关问题。
我实施的解决方案同样适用于您的情况,使用 @JsonAnyGetter 。在MyClass中忽略需要特殊序列化的属性,而是将其添加到 JsonAnyGetter :
public class MyClass
{
@JsonProperty("subject")
private final String subject;
@JsonIgnore
private final MailActor sender;
@JsonAnyGetter
public Map<String, Object> serializeActor() {
return sender.serializeToMap();
// Of course, here you could create an empty map
// and add the properties of many different classes.
}
}
然后在MailActor类中实现该方法,该方法将返回具有您可能需要的属性的地图。
public Map<String, Object> serializeToMap() {
final Map<String, Object> properties = new ArrayMap<>();
properties.put("from_name", this.getName());
properties.put("from_email", this.getAddress());
return properties;
}
这样做的问题是反序列化对象,因为@JsonAnySetter没有在地图中获得带有JSON的地图,就像你用上面的例子一样。在你的情况下,它更难,因为你的班级&#39;属性是最终的。您需要使用必须创建所有属性的@JsonCreator。有点像:
@JsonCreator
public MyClass( Map< String, String > json ) {
if (json.containsKey("subject")) {
subject = json.get("subject");
} else {
subject = "";
}
String name, address;
if (json.containsKey("from_name")) {
name = json.get("from_name");
} else {
name = "";
}
if (json.containsKey("from_email")) {
address = json.get("from_email");
} else {
address = "";
}
sender = new MailActor(name, address);
}
自从您发布问题以来已经有一段时间了,希望这对某些寻找替代方案的人有所帮助。
答案 1 :(得分:0)
嗯,那是因为你设计它是这样的,当杰克逊映射一个对象时,它会将内部属性映射为该对象的子属性,如果你希望它将这两个字段序列化,就好像它们是成员一样MyClass而不是MailActor,然后将它们声明为。
这可能会指出您的对象设计可能存在一些小缺陷。
我会为MyClass对象编写一个客户序列化程序,但从长远来看仍然不是一个可行的解决方案。