Подтвердить что ты не робот

Spring Запрос данных REST-PUT не работает должным образом, поскольку v.2.5.7

Поскольку версия 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.

4b9b3361

Ответ 1

Похоже, что проблема уже сообщалась как ошибка: - пожалуйста, проверьте. Насколько я могу судить, это проблема, о которой вы сообщаете выше.

Примечание. Я пересматриваю свой предыдущий ответ, чтобы быть этим сообщением об ошибке.

Ответ 2

Я согласен с вами в том, что это ошибка в Spring Data REST, и об этом сообщается.

У меня такая же проблема в моем проекте, где обновление объекта через запрос PATCH работает нормально, но запрос PUT обновляет только поля данного объекта, но не связанные с ним ресурсы.

Почему я считаю эту ошибку?

  • Как правильно указали люди, PUT следует использовать для замены ресурса в целом модифицированной версией, которая предполагает, что она должна работать, если вы предоставите все поля для ресурса ( как в запросе POST). Однако в текущей версии Spring Data REST обновляются только простые поля объекта, а связанные ресурсы остаются нетронутыми, что делает запрос PUT только "частично работающим", и это, безусловно, не является ожидаемым поведением (даже если оно выполняет RFC).
  • Кроме того, Spring Data REST даже позволяет вам выполнять частичный запрос PUT, то есть обновлять только ваше поле имени через PUT. Однако он не работает для адреса.
  • Это означает, что Spring Data REST не работает точно так, как RFC указывает его (что может быть для других обсуждений), однако он также не обеспечивает последовательное использование - при обновлении одного поля работает и обновляет другие, не имеет никаких признаков ошибки.

Для записи я использую Spring Data REST 2.6.3.