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

使用Jackson和Spring将JavaScript数组反序列化为Java LinkedHashSet';不要删除重复项,java,json,spring-boot,jackson,Java,Json,Spring Boot,Jackson,假设我有这个客户端JSON输入: { id: "5", types: [ {id: "1", types:[]}, {id: "2", types:[]}, {id: "1", types[]} ] } 我有这门课: class Entity { private String id; private Set<Entity> types = new LinkedHashSet<>(); pub

假设我有这个客户端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());
    }
}
类实体{
私有字符串id;
私有集类型=新LinkedHashSet();
公共字符串getId(){
返回此.id;
}
公共字符串集合id(字符串id){
this.id=id;
}
公共集getTypes(){
返回类型;
}
@JsonDeserialize(as=LinkedHashSet.class)
公共void集合类型(集合类型){
this.types=类型;
}
@凌驾
公共布尔等于(对象o){
if(o==null | |!(实体的o实例)){
返回false;
}
返回此.getId().equals(((实体)o).getId());
}
}
我有一个Java Spring端点,我在请求体中传递输入:

@RequestMapping(value=“api/entity”,method=RequestMethod.POST)
公共实体createEntity(@RequestBody final Entity in){
Set types=in.getTypes();
[...]
}
我希望:

Set types=in.getTypes()

只有两个条目的正确顺序。。。因为其中一个是基于id的副本。。。 相反,我在LinkedHashSet中得到了重复项(!)

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

这个问题的背景比其他问题更广泛
因为它通过Java Spring使用隐式Jackson序列化。

仅重写
equals
方法将不起作用,因为基于哈希的集合同时使用
equals
hashCode
方法来查看两个对象是否相同。您需要重写
Entity
类中的
hashCode()
方法,因为需要正确实现
hashCode()
equals()
方法才能使用基于哈希的集合

如果您的要求是,如果
实体
类的两个对象的部分或全部字段相同,那么这两个对象将被视为等效的,在这种情况下,您必须重写
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;

}
@Override
public int hashCode() {
    int h = 17;
    h = h * 31 + id == null ? 0 : id.hashCode();
    return h;
}
但除此之外,还需要重写
hashCode()
方法,以便在id具有相同值时生成相同的hashCode,可能类似于以下内容:

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

}
@Override
public int hashCode() {
    int h = 17;
    h = h * 31 + id == null ? 0 : id.hashCode();
    return h;
}
只有现在,它才能正确地处理基于散列的集合,因为这两种方法都用于唯一地标识对象


有关这方面的更多信息:


假设如果
实体
类的成员,即
id
类型
相同,则类
实体
的对象是相同的是完全错误的,除非并且直到您显式重写
hashcode()
equals()
函数


如果在
实体
类中不重写
hashCode()
equals()
函数,那么这两个对象将不同,即使它们的成员中有相同的数据。

在Java中,对象的相等性是通过重写
equals()
hashCode()
来确定的

对象中有
equals()
hashCode()
的默认实现。如果您不提供自己的实现,将使用这些实现。对于
equals()
,这意味着一个
==
比较:只有当对象是完全相同的对象时,它们才会相等

回答您的问题
LinkedHashSet
中的对象从
对象
类继承了
equals()
hashcode()
方法的默认行为。重写
实体的
equals()
hashcode()
类的
LinkedHashSet


有关
hashcode()
equals()

函数的默认行为,请参见下面的内容。它与
equals(Object)
一样是合同的一部分。谢谢!我似乎没有注意到这一点——让我补充一下,看看是否有works@GurwinderSingh成功了!!你可以把它添加为一个答案,如果你想要的话,我会接受它:)我可能忘记了<代码> HASCODE()/<代码>。我认为散列为基础的集合使用<代码>等式()/代码>来确定它是否是同一个对象。@ MICILIMAICILIDIS,你应该总是考虑重写<代码> HASCODE()/<代码>以及<代码>等式()。
而不仅仅是一个。我希望这能解决你的问题:)是的,我是根据古尔温德早些时候的回答想出来的:)Thanks@MichailMichailidis干杯!:)