【问题标题】:Multiple Jackson Serializers of Same Return Type相同返回类型的多个 Jackson 串行器
【发布时间】:2013-11-17 23:40:06
【问题描述】:

我正在使用 Jackson 进行 JSON 序列化,并编写了几个自定义的 String 序列化器,一个用于类的每个 getter 方法。每个方法都返回相同的类型Set<String>,但每个方法都使用不同的序列化程序。

不幸的是,Jackson 并没有使用每个序列化器,每个方法使用一个序列化器,而是为两个序列化器使用一个序列化器。它似乎采用任何方法首先按字母顺序排列,并将其序列化程序用于两种方法。我期望的是第一种方法上注解的序列化器用于第一种方法,第二种方法上注解的序列化器用于第二种方法。调试似乎表明 Jackson 在映射中具有序列化程序,该映射由方法的返回类型作为键(两者相同)。

一个例子:

public class FooBar {

  private Set<String> foos = new HashSet<String>();
  private Set<String> bars = new HashSet<String>();

  @JsonProperty("FooWrapper")
  @JsonSerialize(contentUsing = FooSerializer.class)
  public Set<String> getFoos() {
    return foos;
  }

  @JsonProperty("BarWrapper")
  @JsonSerialize(contentUsing = BarSerializer.class)
  public Set<String> getBars() {
    return bars;
  }
}

关于如何使用FooSerializer 序列化getFoos() 方法和使用BarSerializer 序列化getBars() 方法的任何建议?在此示例中,两种方法都调用了BarSerializer

请注意,如果我将其中一种方法的签名更改为另一种集合类型,以使它们不同 - 例如 List&lt;String&gt; - 序列化有效。

提前致谢。

【问题讨论】:

  • 我们能知道您使用的 Jackson 版本吗?
  • 我已经用 Jackson(org.codehaus.jackson) 1.9.11 检查了这种行为,但它不起作用。之后,我将 Jackson 库更新到 2.2.2 版(com.fasterxml.jackson),效果非常好。你能在你的项目中升级 Jackson 库吗?
  • 我不认为我可以,因为另一个使用 Jackson
  • 我最终升级到 Jackson 2.x,一切都很好。谢谢。

标签: java json jackson


【解决方案1】:

我认为在将ObjectMapper@JsonSerialize(contentUsing = BarSerializer.class) 结合使用时,1.9.xx 版本无法实现您想要实现的目标。

Jackson 确实缓存了序列化程序,它基于与序列化程序关联的JavaType(在本例中为Set&lt;String&gt; 缓存它们。见StdSerializerProvider.findValueSerializer(JavaType valueType, BeanProperty property)

虽然BeanProperty 被传递给此方法,但它不用作缓存键的一部分。您可以继承 StdSerializerProvider 并在缓存值序列化程序时考虑 BeanProperty 参数,但这可能不是解决问题的最简单方法。

作为一种快速解决方法是使用@JsonSerialize(using = FooCollectionSerializer.class) 并自己处理序列化集合。通过这样做,序列化程序将directly coupled 转换为用于序列化属性的BeanPropertyWriter。使用@JsonSerialize(contentUsing = BarSerializer.class) 时,没有与BeanPropertyWriter 耦合的序列化程序会触发serializer lookup,该serializer lookup 基于JavaType 缓存序列化程序

public class FooBar {

    private Set<String> foos = new HashSet<>();
    private Set<String> bars = new HashSet<>();

    @JsonProperty("FooWrapper")
    @JsonSerialize(using = FooCollectionSerializer.class)
    public Set<String> getFoos() {
        return foos;
    }

    @JsonProperty("BarWrapper")
    @JsonSerialize(using = BarCollectionSerializer.class)
    public Set<String> getBars() {
        return bars;
    }

    public static class FooCollectionSerializer extends JsonSerializer<Collection<String>> {

        JsonSerializer<Collection<String>> serializer;

        public FooCollectionSerializer() {
            //let Jackson deal with serializing the collection and just specify how you want to serialize indivial items
            this.serializer = new StringCollectionSerializer(null, new FooSerializer());
        }

        @Override
        public void serialize(Collection<String> value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            serializer.serialize(value, jgen, provider);
        }
    }

    public static class FooSerializer extends SerializerBase<String> {
        public FooSerializer() {
            super(String.class);
        }

        @Override
        public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            jgen.writeString(value);
        }
    }

    public static class BarCollectionSerializer extends JsonSerializer<Collection<String>> {

        @Override
        public void serialize(Collection<String> values, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            //handle serializing the collection yourself
            jgen.writeStartArray();
            for (String value : values) {
                jgen.writeString(value);

            }
            jgen.writeEndArray();
        }
    }
}

【讨论】:

  • 我最终升级到 Jackson 2,这需要我将另一个工具(Spring 集成)升级到非官方版本 - 但一切正常。我奖励你提供一个让 Jackson
猜你喜欢
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 2019-05-25
  • 2016-01-29
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多