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 { @Override public void serialize(Map value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { jgen.writeStartObject(); jgen.writeObjectField("aKeyInTheMap", "theValueForThatKey"); jgen.writeEndObject(); } } public static void main(String[] args) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(SerializationFeature.INDENT_OUTPUT); String s = objectMapper.writeValueAsString(new Container()); System.out.println(s); } } 

这是我不使用com.fasterxml.jackson.annotation.JsonValue时的输出

 { "data" : { "aKeyInTheMap" : "theValueForThatKey" } } 

这是我使用com.fasterxml.jackson.annotation.JsonValue时的输出

 { "aKeyInTheMap" : "theValueForThatKey" }