web-dev-qa-db-ja.com

Spring Data REST-v.2.5.7以降、PUTリクエストが正しく機能しません

バージョン2.5.7以降Spring Data RESTは[ 〜#〜] put [〜#〜]リソースを更新するリクエスト関連するリソースがあります。PATCHリクエストとは異なり、期待どおりに動作します!

たとえば、PersonAddresと多対1の関連付けがあります。 SDR v.2.5.6(Spring Boot v.1.4.3)でPUTリクエストを実行すると、すべて正常に機能します。しかし、バージョン2.5.7(つまり、Spring Boot v.1.4.4)に切り替えると、エラーが発生します。

アドレスのインスタンスを構築できません:文字列値から逆シリアル化する文字列引数コンストラクタ/ファクトリメソッドがありません

同じことが他のタイプの関連付けでも発生します。たとえば、1対多(単方向および双方向)の場合です。myアプリケーション例コードとテスト。

この問題は、最新の安定した1.5.6バージョンと最新の2.0.0を含む1.4.4以降のSpring Bootのallバージョンに存在します。 -スナップショットバージョン!

この状況を回避するには、SDR v.2.5.6(Spring Boot v.1.4.3)に切り替えるだけです。

私はあなたが問題で遊ぶのを助けるためにPostmanリクエストのコレクションを用意しました: SDR PUT Issue

UPDATE 2017-08-14

エラーCan not construct instance of Address: no String-argument constructor/factory method to deserialize from String valueを回避する方法を見つけました。

このプロジェクトでは Lombok を使用しているので、 生成されたコンストラクター@ConstructorPropertiesアノテーションの使用を抑制するようにLombokに指示するだけで済みます。そこで、「lombok.config」ファイルにlombok.anyConstructor.suppressConstructorProperties=trueを設定すると、エラーはなくなりました。

残念ながら、新しい問題が見つかりました-PUTリクエストは関連するオブジェクトをまったく更新しません

以下の例はこれを示しています。住所をaddresses/1(初期値)からaddresses/2に変更してPersonを更新しようとすると、同じままになります:addresses/1!前の問題と同様に、これは1.4.4以降のSpring Bootのallバージョンに存在します(SDR-v.2.5.7以降)。

プロジェクトをデバッグしたところ、問題の理由がメソッドDomainObjectReader#mergeForPutに隠されていることがわかりました( そのソース を参照)-itnever関連するリソースを新しいリソースに置き換えます。

この問題を Spring JIRA に投稿する前に、プロジェクトでこの問題が発生した場合はここに報告してください -)。

私のテストを取得することができます ここ そしてあなたのプロジェクトでそれをチェックしてください-テストは「スタンドアロン」であり、他のクラス/モジュールに依存しません(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"
        }
    }
}

UPDATE 2017-08-24

Scott Cのおかげで answer 、SDRにはbugがあり、2つのチケットで説明されていることがわかりました:- DATAREST-1001 および DATAREST-1012

13
Cepr0

問題が発生したようです すでにバグとして報告されています :-確認してください。私が知る限り、これはあなたが上で報告している問題です。

以前の回答をこのバグレポートに修正していることに注意してください。

4
Scott C.

これはSpringData RESTのバグであり、報告する必要があることに同意します。

私のプロジェクトでも同じ問題があり、PATCHリクエストを介したエンティティの更新は正常に機能しますが、PUTリクエストは特定のエンティティのフィールドのみを更新し、関連するリソースは更新しません。

なぜこれをバグと見なすのですか?

  • 人々が正しく指摘しているように、PUTはリソース全体を置き換えるに使用する必要があります。これは、リソースのすべてのフィールドを指定した場合( POST request)。ただし、現在のSpring Data RESTバージョンでは、エンティティの単純なフィールドのみが更新され、関連するリソースはそのまま残り、PUTになります。 「部分的に機能している」だけを要求し、それは間違いなく期待される動作ではありません(RFCを満たしている場合でも)。
  • さらに、Spring Data RESTでは、部分的なPUTリクエストを実行することもできます。つまり、PUTを介して名前フィールドだけを更新することもできますが、住所では機能しません。
  • これは、Spring Data RESTがRFCで指定されているとおりに機能しないことを意味します(これは別の議論になる可能性があります)ただし、一方のフィールドの更新が機能し、もう一方のフィールドの更新がエラーの兆候なしでは機能しない場合は、一貫した使用法-も提供されません。

記録のために、私はSpring Data REST 2.6.3を使用しています。

3
Adam Kučera