使用Jackson和Spring将JavaScript数组反序列化为Java LinkedHashSet';不要删除重复项
假设我有这个客户端JSON输入:使用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
{
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干杯!:)