使用 Jackson 和 Spring 将 JavaScript 数组反序列化为 Java LinkedHashSet 不会删除重复项
Posted
技术标签:
【中文标题】使用 Jackson 和 Spring 将 JavaScript 数组反序列化为 Java LinkedHashSet 不会删除重复项【英文标题】:Deserialization of JavaScript array to Java LinkedHashSet using Jackson and Spring doesn't remove duplicates 【发布时间】:2017-05-15 08:53:09 【问题描述】:假设我有这个客户端 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 Spring 端点,我在 POST 请求的正文中传递输入:
@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 (!) 中得到了重复项
我从我的代码中认为删除重复项会自动工作,但显然不是。
这个问题的背景比 Why do I need to override the equals and hashCode methods in Java? 因为它通过 Java Spring 使用隐式 Jackson 序列化。
【问题讨论】:
你的hashCode()
函数在哪里?
和equals(Object)
一样是合同的一部分。
谢谢!看来我错过了 - 让我添加它,看看它是否有效
@GurwinderSingh 成功了!!您可以将其添加为答案,如果您愿意,我会接受:)
Why do I need to override the equals and hashCode methods in Java?的可能重复
【参考方案1】:
仅覆盖equals
方法将不起作用,因为基于散列的集合同时使用equals
和hashCode
方法来查看两个对象是否相同。您需要覆盖 Entity
类中的 hashCode()
方法,因为需要正确实现 hashCode()
和 equals()
方法才能使用基于哈希的集合。
如果您的要求是如果Entity
类的两个对象的部分或全部字段相同,那么这两个对象将被视为等效,在这种情况下,您必须同时覆盖@ 987654331@和hashCode()
方法。
例如- 如果仅需要 Entity 类中的 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;
但与此同时,hashCode()
方法需要被覆盖,以在 id 具有相同值的情况下生成相同的哈希码,可能是这样的:
@Override
public int hashCode()
int h = 17;
h = h * 31 + id == null ? 0 : id.hashCode();
return h;
只有现在它才能与基于哈希的集合一起正常工作,因为这两种方法都用于唯一地标识一个对象。
更多信息:
Relationship between hashCode and equals method in Java Why do I need to override the equals and hashCode methods in Java?【讨论】:
【参考方案2】:假设如果Entity
类的成员,即id
和type
相同,那么Entity
类的对象是完全错误的,除非您覆盖hashcode()
和equals()
明确地发挥作用。
如果您不覆盖 Entity
类中的 hashCode()
和 equals()
函数,那么这两个对象将不同,即使它们的成员中具有相同的数据。
【讨论】:
我忘了hashCode()
- 我认为基于哈希的集合使用equals()
来确定它是否是同一个对象..
@MichailMichailidis 您应该始终考虑覆盖hashCode()
和equals()
而不仅仅是一个。我希望这能解决你的问题:)
是的,我根据 Gurwinder 早些时候的回答弄明白了 :) 谢谢
@MichailMichailidis 干杯! :)【参考方案3】:
在 Java 中,对象相等性是通过覆盖 equals()
和 hashcode()
contract 来确定的。
Object中有equals()
和hashCode()
的默认实现。如果您不提供自己的实现,则将使用这些实现。对于equals()
,这意味着==
比较:只有当它们是完全相同的对象时,它们才会相等。
回答您的问题:LinkedHashSet
中的对象从 Object
类继承 equals()
和 hashcode()
方法的默认行为。覆盖Entity
的Entity
类的LinkedHashSet
的equals()
和hashcode()
请参阅下面的this,了解hashcode()
和equals()
的默认行为。
【讨论】:
以上是关于使用 Jackson 和 Spring 将 JavaScript 数组反序列化为 Java LinkedHashSet 不会删除重复项的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring 和 Jackson JSON 将 java.io.Serializable 实例序列化为 JSON [重复]
在 Spring MVC 中,无法使用 Jackson @JsonFormat 将输入绑定到日期字段
Spring Boot 自定义Jackson ObjectMapper
java 将Jackson与Spring Data MongoDB一起使用