Дессериализация массива JavaScript в Java LinkedHashSet с использованием Jackson и Spring не удаляет дубликаты
Скажем, у меня есть этот клиентский вход 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();
иметь только две записи в правильном порядке... так как один из них является дубликатом на основе идентификатора...
Вместо этого я получаю дубликаты в LinkedHashSet (!)
Я думал, что из кода, который у меня есть, удаление дубликатов будет работать автоматически, но, видимо, это не так.
Этот вопрос имеет более широкий контекст, чем Почему мне нужно переопределить методы equals и hashCode в Java?
поскольку он использует неявную сериализацию Джексона через Java Spring.
Ответы
Ответ 1
Только переопределение метода equals
не будет работать, потому что коллекции на основе хэш-функции используют метод equals
и hashCode
, чтобы увидеть, совпадают ли два объекта. Вам нужно переопределить метод hashCode()
в классе Entity
, поскольку для работы с коллекциями на основе Hash требуется как метод hashCode()
, так и equals()
.
Если ваше требование состоит в том, что если некоторые или все поля из двух объектов класса Entity
одинаковы, то два объекта должны считаться эквивалентными, в этом случае вам придется переопределить оба equals()
и 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;
}
Только теперь он будет корректно работать с коллекциями на основе Hash, поскольку оба эти метода используются для однозначного определения объекта.
Подробнее об этом:
Ответ 2
Предполагая, что если члены класса Entity
, то есть id
и type
, являются одинаковыми, то объект класса Entity
является таким же, что и полностью, если только вы не переопределите hashcode()
и equals()
функция явно.
Если вы не переопределите функцию hashcode()
и equals()
в классе Entity
, тогда два объекта будут отличаться, хотя они имеют одинаковые данные в своих членах.
Ответ 3
В Java, равенство объектов определяется переопределением контракта equals()
и hashcode()
.
В Object имеются реализации по умолчанию equals()
и hashcode()
в Object. Если вы не предоставите свою собственную реализацию, они будут использованы. Для equals()
это означает сравнение ==
: объекты будут равны, если они являются точно одним и тем же объектом.
Отвечайте на свой вопрос. Объекты в LinkedHashSet
наследуют поведение по умолчанию методов eqauls()
и hashcode()
из класса Object
. Переопределить eqauls()
и hashcode()
класса Entity
LinkedHashSet
См. ниже this для поведения по умолчанию hashcode()
и equals()
.