jackson – 结合@JsonValue和@JsonSerialize
我正在尝试@JsonValue
和@JsonSerialize
的组合。 让我们从我当前的容器类开始:
public class Container { private final Map data; @JsonValue @JsonSerialize(keyUsing = SomeKeySerializer.class) public Map data() { return data; } }
在这种情况下,不使用自定义序列化程序SomeKeySerializer
。
如果我按如下方式更改容器,则会调用序列化程序:
public class Container { @JsonSerialize(keyUsing = SomeKeySerializer.class) private final Map data; }
但是,这不是我想要的,因为这会在输出JSON中引入另一个“数据”级别。
是否有可能以某种方式组合@JsonValue
和@JsonSerialize
?
我总是可以为Container
编写另一个自定义序列化程序,它或多或少与@JsonValue
背后的function相同。 在我看来,这或多或少都是黑客攻击。
jackson版本:2.6.2
这个组合似乎可以做你想要的:创建一个Converter从Container中提取Map,并将@JsonValue添加到SomeKey本身来序列化它:
@JsonSerialize(converter = ContainerToMap.class) public class ContainerWithFieldData { private final Map data; public ContainerWithFieldData(Map data) { this.data = data; } } public static final class SomeKey { public final String key; public SomeKey(String key) { this.key = key; } @JsonValue public String toJsonValue() { return "key:" + key; } @Override public String toString() { return "SomeKey:" + key; } } public static final class ContainerToMap extends StdConverter> { @Override public Map convert(ContainerWithFieldData value) { return value.data; } } @Test public void serialize_container_with_custom_keys_in_field_map() throws Exception { ObjectMapper mapper = new ObjectMapper(); assertThat( mapper.writeValueAsString(new ContainerWithFieldData(ImmutableMap.of(new SomeKey("key1"), "value1"))), equivalentTo("{ 'key:key1' : 'value1' }")); }
我根本无法轻易地将容器的访问器方法注释到DTRT,而不是与@JsonValue结合使用。 鉴于容器上的@JsonValue基本上是指定一个转换器(通过调用带注释的方法实现),这实际上是你所追求的,虽然不像它应该的那样令人愉快。 (尝试过Jackson 2.6.2)
(我从中学到的东西:关键序列化器不像普通的序列化器,即使它们实现JsonSerializer也是一样的。例如,他们需要在JsonGenerator上调用writeFieldName,而不是writeString。在反序列化方面,JsonDeserializer和JsonDeserializer之间的区别。 KeyDeserializer是拼写出来的,但不是在序列化方面。你可以使用@JsonValue从SomeKey创建一个关键的序列化器,但不能用@JsonSerialize(使用= …)注释SomeKey,这让我感到惊讶。
您是否尝试过使用@JsonSerialize(using = SomeKeySerializer.class)
而不是keyUsing
?
Doc for using()说:
用于序列化关联值的Serializer类。
…对于keyUsing,你得到:
用于序列化带注释属性的Map键的Serializer类
自己测试了它,它的工作原理……
public class Demo { public static class Container { private final Map data = new HashMap<>(); @JsonValue @JsonSerialize(using = SomeKeySerializer.class) public Map data() { return data; } } public static class SomeKeySerializer extends JsonSerializer
这是我不使用com.fasterxml.jackson.annotation.JsonValue
时的输出
{ "data" : { "aKeyInTheMap" : "theValueForThatKey" } }
这是我使用com.fasterxml.jackson.annotation.JsonValue
时的输出
{ "aKeyInTheMap" : "theValueForThatKey" }