Поскольку версия 2.5.7 Spring Data REST неправильно выполняет запрос PUT для обновления ресурса, который имеет связанные ресурсы. В отличие от запроса PATCH, который работает как ожидалось!
Например, Person
имеет многозначную связь с Addres
. Если мы выполняем запрос PUT с SDR v.2.5.6 (Spring Boot v.1.4.3), тогда все работает нормально. Но если мы перейдем к версии 2.5.7 (т.е. К Spring Boot v.1.4.4), мы получим ошибку:
Невозможно создать экземпляр Address: no Конструктор конструкторов / factory для десериализации из значения String
То же самое происходит с другими типами ассоциаций, например с одним-ко-многим (одно- и двунаправленным) - см. пример приложения и тесты.
Эта проблема присутствует в всех версиях Spring Boot начиная с версии 1.4.4, включая последнюю стабильную версию 1.5.6, а также новейшую версию 2.0.0-SNAPSHOT!
Чтобы обойти эту ситуацию, мы можем просто переключиться на SDR v.2.5.6 (Spring Boot v.1.4.3).
Я подготовил коллекцию запросов Postman, чтобы помочь вам справиться с проблемой: SDR PUT Issue
ОБНОВЛЕНИЕ 2017-08-14
Я нашел, как избежать ошибки Can not construct instance of Address: no String-argument constructor/factory method to deserialize from String value
.
Поскольку я использую Lombok в этом проекте,
необходимо просто сказать Ломбоку подавить с помощью аннотации @ConstructorProperties
в
сгенерированные конструкторы.
Поэтому я установил lombok.anyConstructor.suppressConstructorProperties=true
в файл 'lombok.config', и ошибка исчезла.
К сожалению, была найдена новая проблема - Запрос PUT не обновляет связанные объекты вообще!
Пример ниже демонстрирует это. Когда мы пытаемся обновить Person, изменив его адрес от addresses/1
(начальное значение) до addresses/2
- тогда он останется тем же: addresses/1
! Как и предыдущая проблема, эта версия присутствует в всех версиях Spring Boot начиная с 1.4.4 (SDR - от версии 2.5.7).
Я отлаживал свой проект и выяснил, что причина проблемы скрыта в методе DomainObjectReader#mergeForPut
(см. его источник) - он никогда заменяет связанные ресурсы новыми.
Прежде чем опубликовать этот вопрос в Spring JIRA, пожалуйста, сообщите здесь, если у вас есть эта проблема в ваших проектах и что вы думаете об этом.
Вы можете получить мой тест здесь и проверить его в своих проектах - тест является "автономным" и не зависит от других классов /modules (на мой взгляд, исключить только H2).
@Entity
public class Person {
private String name;
@ManyToOne
private Address address;
// other stuff
}
@Entity
public class Address {
private String street;
// other stuff
}
Попытка обновить Person:
PUT http://localhost:8080/api/persons/1
{
"name": "person1u",
"address": "http://localhost:8080/api/addresses/2"
}
Получение правильного ответа:
{
"name": "person1u",
"_links": {
"self": {
"href": "http://localhost:8080/api/persons/1"
},
"person": {
"href": "http://localhost:8080/api/persons/1"
},
"address": {
"href": "http://localhost:8080/api/persons/1/address"
}
}
}
Затем проверка нового адреса "Адрес человека" не была обновлена:
GET http://localhost:8080/api/persons/1/address
{
"street": "address1",
"_links": {
"self": {
"href": "http://localhost:8080/api/addresses/1"
},
"address": {
"href": "http://localhost:8080/api/addresses/1"
}
}
}
ОБНОВЛЕНИЕ 2017-08-24
Благодаря ответу Скотту С. выяснилось, что SDR имеет ошибку, которая описана в двух билетах: DATAREST-1001 и DATAREST-1012.