问题描述
我正在尝试 @JsonValue
和 @JsonSerialize
的组合。让我们从我当前的容器类开始:
I am trying a combination of @JsonValue
and @JsonSerialize
. Let's start with my current container class:
public class Container {
private final Map<SomeKey, Object> data;
@JsonValue
@JsonSerialize(keyUsing = SomeKeySerializer.class)
public Map<SomeKey, Object> data() {
return data;
}
}
在这种情况下,自定义序列化器 SomeKeySerializer
未使用。
In this case, the custom serializer SomeKeySerializer
is not used.
如果按以下方式更改容器,则会调用序列化程序:
If I change the container as following, the serializer is called:
public class Container {
@JsonSerialize(keyUsing = SomeKeySerializer.class)
private final Map<SomeKey, Object> data;
}
然而,这不是我想要的,因为这引入了另一个'数据'输出JSON中的级别。
However, this is not what I want, as this introduces another 'data' level in the output JSON.
是否可以组合 @JsonValue
和 @JsonSerialize
以某种方式?
Is it possible to combine @JsonValue
and @JsonSerialize
in some way?
我总是可以为 Container
编写另一个自定义序列化程序,或多或少与 @JsonValue
背后的功能相同。在我看来,这或多或少都是黑客攻击。
I could always write another custom serializer for Container
, which more or less does the same as the functionality behind @JsonValue
. This would be more or less a hack, in my opinion.
杰克逊版本:2.6.2
Jackson version: 2.6.2
推荐答案
这个组合似乎可以做你想要的:创建一个转换器从Container中提取Map,并将@JsonValue添加到SomeKey本身来序列化它:
This combination seems to do what you want: make a Converter to extract the Map from the Container, and add @JsonValue to SomeKey itself to serialize it:
@JsonSerialize(converter = ContainerToMap.class)
public class ContainerWithFieldData {
private final Map<SomeKey, Object> data;
public ContainerWithFieldData(Map<SomeKey, Object> 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<ContainerWithFieldData, Map<SomeKey, Object>> {
@Override
public Map<SomeKey, Object> 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)
I simply can't get annotating an accessor method of Container to DTRT at all easily, not in combination with @JsonValue. Given that @JsonValue on the container is basically designating a converter anyway (that is implemented by calling the annotated method), this is effectively what you're after, although not as pleasant as it seems it should be. (tried with Jackson 2.6.2)
(我从中学到的东西:关键序列化器不像普通的序列化器,即使它们实现JsonSerializer也是如此。他们需要例如,在JsonGenerator上调用writeFieldName而不是writeString。在反序列化方面,JsonDeserializer和KeyDeserializer之间的区别是拼写出来的,但不是在序列化方面。你可以使用@JsonValue从SomeKey创建一个关键的序列化器,但是不通过使用@JsonSerialize(使用= ...)注释SomeKey,这让我感到惊讶。
(Something I learned from this: key serializers aren't like normal serializers, even though they implement JsonSerializer just the same. They need to call writeFieldName on the JsonGenerator, not writeString, for example. On the deserialization side, the distinction between JsonDeserializer and KeyDeserializer is spelled out, but not on the serialization side. You can make a key serializer from SomeKey with @JsonValue, but not by annotating SomeKey with @JsonSerialize(using=...), which surprised me).
这篇关于杰克逊 - 结合@JsonValue和@JsonSerialize的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!