使用 Jackson 和 Spring 将 JavaScript 数组反序列化为 Java LinkedHashSet 不会删除重复项



假设我有此客户端JSON输入:

{
   id: "5",
   types: [
      {id: "1", types:[]},
      {id: "2", types:[]},
      {id: "1", types[]}
   ]
}

我有这个课:

class Entity {
    private String id;
    private Set<Entity> types = new LinkedHashSet<>();
    public String getId() {
        return this.id;
    }
    public String setId(String id) {
        this.id = id;
    }
    public Set<Entity> getTypes() {
        return types;
    }
    @JsonDeserialize(as=LinkedHashSet.class)
    public void setTypes(Set<Entity> types) {
        this.types = types;
    }
    @Override
    public boolean equals(Object o){
        if (o == null || !(o instanceof Entity)){
            return false;
        }
        return this.getId().equals(((Entity)o).getId());
    }
}

我有这个java弹簧端点,我在邮政请求的正文中传递输入:

@RequestMapping(value = "api/entity", method = RequestMethod.POST)
public Entity createEntity(@RequestBody final Entity in) {
    Set<Entity> types = in.getTypes();
    [...]
}

我想要:

Set<Entity> types = in.getTypes();

只有两个条目以正确的顺序...因为其中一个是基于ID的重复。相反,我在linkedhashset(!)

中获得了重复。

我从我的代码中认为,删除重复项会自动工作,但显然不是。

这个问题比更广泛的上下文,为什么我需要覆盖Java中的等值和哈希码方法?由于它正在使用隐式杰克逊通过Java Spring序列化。

仅覆盖equals方法将无效,因为基于哈希的集合使用equalshashCode方法来查看两个对象是否相同。您需要在Entity类中覆盖hashCode()方法,因为hashCode()equals()方法都必须正确实现以使用基于哈希的集合。

如果您的要求是,如果Entity类的两个对象的某些字段相同,则两个对象应视为等效,在这种情况下,您必须同时覆盖equals()hashCode()方法。

例如 - 如果需要实体类中的id字段才能确定两个对象是否相等,则您将覆盖equals(),类似的内容:

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o instanceof Entity){
        Entity that = (Entity) o;
        return this.id == null ? that.id == null : this.id.equals(that.id);
    }
    return false;
}

但随之而来的是,如果ID具有相同的值,则需要以产生相同的主题的方式覆盖hashCode()方法:

@Override
public int hashCode() {
    int h = 17;
    h = h * 31 + id == null ? 0 : id.hashCode();
    return h;
}

现在,它才能与基于哈希的集合正常使用,因为这两种方法都用于唯一识别对象。


有关此的更多信息:

  • java中的hashcode和equals方法之间的关系
  • 为什么我需要覆盖Java中的等效方法?

假设如果Entity类的成员即idtype是相同的,那么Entity类的对象是完全错误的,除非并且直到您覆盖hashcode()equals()函数,否则明确。/p>

如果您不覆盖hashCode()中的CC_21和equals()函数,那么即使它们在成员中具有相同的数据,这两个对象也会有所不同。

在java中,对象平等是通过覆盖equals()hashcode()合同来确定的。

对象中有equals()hashCode()的默认实现。如果您不提供自己的实施,则将使用这些实施。对于equals(),这意味着==比较:仅当对象完全是同一对象时。

回答您的问题LinkedHashSet中的对象是从Object类继承equals()hashcode()方法的默认行为。Entity LinkedHashSet类的覆盖equals()hashcode()

hashcode()equals()的默认行为请参见下面。

最新更新