簡體   English   中英

傑克遜 - 結合@JsonValue和@JsonSerialize

[英]Jackson - combine @JsonValue and @JsonSerialize

我正在嘗試@JsonValue@JsonSerialize的組合。 讓我們從我當前的容器類開始:

public class Container {
    private final Map<SomeKey, Object> data;

    @JsonValue
    @JsonSerialize(keyUsing = SomeKeySerializer.class)
    public Map<SomeKey, Object> data() {
        return data;
    }
}

在這種情況下,不使用自定義序列化程序SomeKeySerializer

如果我按如下所示更改容器,則會調用序列化程序:

public class Container {
    @JsonSerialize(keyUsing = SomeKeySerializer.class)
    private final Map<SomeKey, Object> data;
}

但是,這不是我想要的,因為這會在輸出JSON中引入另一個“數據”級別。

是否有可能以某種方式組合@JsonValue@JsonSerialize

我總是可以為Container編寫另一個自定義序列化程序,它或多或少與@JsonValue背后的功能相同。 在我看來,這或多或少都是黑客攻擊。

傑克遜版本:2.6.2

這個組合似乎可以做你想要的:創建一個Converter從Container中提取Map,並將@JsonValue添加到SomeKey本身來序列化它:

@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)

(我從中學到了一些東西:關鍵序列化器不像普通的序列化器,即使它們實現JsonSerializer也是一樣的。例如,它們需要在JsonGenerator上調用writeFieldName,而不是writeString。在反序列化方面,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<String, String> data = new HashMap<>();

    @JsonValue
    @JsonSerialize(using = SomeKeySerializer.class)
    public Map<String, String> data() {
      return data;
    }
  }

  public static class SomeKeySerializer extends JsonSerializer<Map> {

    @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"
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM