Конечно, я собираюсь опубликовать это здесь.
сии2.5.7 Spring Data REST неправильно выполняетСТАВИТЬ запрос на обновление ресурса, которыйимеет связанные ресурсы, В отличие от запроса 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: нет конструктора аргумента String / метода фабрики для десериализации из значения String
То же самое происходит с другими типами ассоциаций, например, с одним ко многим (однонаправленным и двунаправленным) - см. Мойпример приложения код и тесты.
Эта проблема присутствует ввсе версии Spring Boot начиная с 1.4.4, включая последнюю стабильную версию 1.5.6, а также новейшую версию 2.0.0-SNAPSHOT!
Чтобы обойти эту ситуацию, мы можем просто переключиться на SDR v.2.5.6 (Spring Boot v.1.4.3).
Я подготовилПочтальон коллекция запросов чтобы помочь вам поиграть с проблемой:SDR PUT Issue
ОБНОВЛЕНИЕ 2017-08-14
Я нашел, как избежать ошибкиCan not construct instance of Address: no String-argument constructor/factory method to deserialize from String value
.
Так как я используюЛомбок в этом проекте необходимо просто сказать Ломбоку, чтобы он подавлял использование@ConstructorProperties
аннотация всгенерированные конструкторы, Итак, я установилlombok.anyConstructor.suppressConstructorProperties=true
в файле 'lombok.config' и ошибка исчезла.
К сожалениюновая проблема был найден -Запрос PUT вообще не обновляет связанные объекты!
Пример ниже демонстрирует это. Когда мы пытаемся обновить Персона, изменив его адрес сaddresses/1
(начальное значение) доaddresses/2
- тогда оно остается прежним:addresses/1
! Как и предыдущая проблема, эта проблема присутствует ввсе версии Spring Boot начиная с 1.4.4 (SDR - от v.2.5.7).
Я отладил свой проект и обнаружил, что причина проблемы скрыта в методеDomainObjectReader#mergeForPut
(видетьего источник) - Этоникогда заменяет связанные ресурсы новыми.
Прежде чем я опубликую этот вопрос наВесенняя ЮРА, пожалуйстасообщите здесь, если у вас есть эта проблема в ваших проектах и что вы думаете об этом.
Вы можете пройти мой тестВот и проверьте его в своих проектах - тест является «автономным» и не зависит от других классов / модулей (я надеюсь, исключая только 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.