Jackson 反序列化器 - 将空集合更改为空集合

问题描述 投票:0回答:5

我有一个包含集合作为属性的实体:

public class Entity {

    @JsonProperty(value="homes")
    @JsonDeserialize(as=HashSet.class, contentAs=HomeImpl.class)
    private Collection<Home> homes = new ArrayList<Home>();

}

如果请求包含 null 作为请求属性:

{
  "homes": null
}

然后 homes 设置为 null。我想做的是将 home 设置为空列表。我是否需要为此编写特殊的反序列化器,或者是否有一个用于集合的反序列化器?我尝试的是这个反序列化器,但它看起来很丑(它不是通用的,并且使用实现而不是接口)。

public class NotNullCollectionDeserializer extends JsonDeserializer<Collection<HomeImpl>> {

  @Override
  public Collection<HomeImpl> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    return jsonParser.readValueAs(new TypeReference<Collection<HomeImpl>>(){});
  }

  @Override
  public Collection<HomeImpl> getNullValue() {
    return Collections.emptyList();
  }
}

那么几个问题:

  1. 是否有一些 Jackson 属性在反序列化期间将 null 更改为空集合?
  2. 如果第一点不是——我需要为此编写反序列化器吗?如果是的话,我可以写一个通用的吗?
java json jackson
5个回答
58
投票

从 Jackson 2.9 开始,似乎可以使用

@JsonSetter
配置特定属性的 null 处理,例如:

@JsonSetter(nulls = Nulls.AS_EMPTY)
public void setStrings(List<String> strings) {
    this.strings = strings;
}

类似的配置也可以全局应用于集合:

ObjectMapper mapper = objectMapperBuilder()
    .changeDefaultNullHandling(n -> n.withContentNulls(Nulls.AS_EMPTY))
    .build();

或按类型:

ObjectMapper mapper = objectMapperBuilder()
    .withConfigOverride(List.class,
        o -> o.setNullHandling(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY)))
    .build();

我还没能尝试该功能,所以这是基于功能讨论单元测试的检查。 YMMV.


15
投票

我也找不到杰克逊的属性或注释。所以我对第一个问题必须回答“否”。但我会推荐一个简单的设置器而不是特殊的反序列化器:

public class Entity {

    @JsonDeserialize(contentAs = HomeImpl.class)
    private Collection<Home> homes = new ArrayList<>();

    public void setHomes(List<Home> homes) {
        if (homes != null)
            this.homes = homes;
    }
}

这是通用的,因为它只使用

Home
接口而不是
HomeImpl
。您不需要
@JsonProperty
,因为杰克逊会将
setHomes
homes
联系起来。


3
投票

对我有用的只是删除设置器并使属性成为最终属性。 Jackson 2 然后将使用 getter 来修改列表。

public class Entity {

  @JsonProperty(value="homes")
  @JsonDeserialize(as=HashSet.class, contentAs=HomeImpl.class)
  private final Collection<Home> homes = new ArrayList<Home>();

  public List<Home> getHomes() {
     return homes;
  }
}

负责的功能是默认情况下打开的 USE_GETTERS_AS_SETTERS:https://github.com/FasterXML/jackson-databind/wiki/Mapper-Features


0
投票

我认为在我的情况下最干净的解决方案在两种情况下都按预期工作(反序列化后得到空列表而不是 null):

  1. json(请求)中省略了属性
  2. 属性在 json(请求)中显式设置为 null

是:

@Valid // javax.validation
@Schema(required = false) // swagger.v3 
@JsonProperty(required = false, defaultValue = "") // jackson 2.13
private List<@NotEmpty @Size(max = 100) String> actions = new ArrayList<>();

public List<String> getActions() {
    return actions;
}

@JsonSetter(nulls = Nulls.AS_EMPTY)
public void setActions(List<String> actions) {
    this.actions = actions;
}

备注:

  • 当属性显式设置为 null 时:使用默认注释
  • 当属性省略时:添加初始化
    = new ArrayList<>();
  • 使用时,例如java 验证,那么这个解决方案仅适用于可选(
    required = false
    )列表

0
投票

至少在2.16中,可以使用

configOverride
来设置。

import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MutableConfigOverride;
import org.junit.jupiter.api.Test;

import java.util.List;

public class Temp {
    static class Dto {
        public List<Object> list;
    }

    @Test
    void test() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        MutableConfigOverride override = mapper.configOverride(List.class);
        override.setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));

        Dto temp = mapper.readValue("{\"list\":null}", Dto.class);
        System.out.println(temp.list.size()); // -> 0
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.