2017-08-10 2 views
10

ので、正常に動作しません。期待どおりに動作するPATCHリクエストとは異なります!スプリングデータREST - PUT要求が<strong>2.5.7</strong>スプリングデータRESTが適切リソース</strong>が関連付けられている<strong>リソースを更新する<strong>PUT</strong>要求を行わないバージョンのでv.2.5.7

たとえば、Personは、Addresと多対1の関連性を持ちます。 SDR v.2.5.6(Spring Boot v.1.4.3)でPUTリクエストを実行すると、すべて正常に動作します。我々は、バージョン2.5.7(すなわち春ブートv.1.4.4へ)に切り替えた場合でも、我々は、エラーを取得:

Can not construct instance of Address: no String-argument constructor/factory method to deserialize from String value

同じことが一対多で例えば、団体の他のタイプで発生します(単方向および双方向) - 私のexample applicationのコードとテストを参照してください。

すべてバージョン1.4.4以降、最新の安定版1.5.6および最新の2.0.0-SNAPSHOTバージョンが含まれています。

この状況を回避するために、SDR v.2.5.6(Spring Boot v.1.4.3)に切り替えることができます。

私は、あなたが問題と遊ぶ支援するために要求のポストマンコレクションを用意しました:SDR PUT Issue

UPDATE 2017年8月14日

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

私はこのプロジェクトでLombokを使用しているので、それだけで generated constructors@ConstructorProperties注釈を使用して抑制するためにロンボクを伝えることが必要である 。 したがって、 'lombok.config'ファイルにlombok.anyConstructor.suppressConstructorProperties=trueを設定しましたが、エラーはなくなりました。

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

以下の例は、これを実証しています。アドレスをaddresses/1(初期値)からaddresses/2に変更してPersonを更新しようとすると、それは同じままです:addresses/1!以前の問題と同様に、これは、にあります。すべてのバージョンは、1.4.4(SDR - v.2.5.7から)以降のSpring Bootのバージョンです。

私は(its sourceを参照してください)私のプロジェクトをデバッグし、問題の原因は方法DomainObjectReader#mergeForPutに隠されていることが判明 - それは、決して新しいものに関連付けられたリソースを置き換えます。

この問題をSpring JIRAに投稿する前に、を報告してください。あなたのプロジェクトにこの問題がある場合は、についてどう思われますか?

あなたのプロジェクトで私のテストhereをチェックすることができます。テストは「スタンドアロン」で、他のクラス/モジュールに依存しません(H2のみを除きます)。

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" 
     } 
    } 
} 

- アドレスは更新されませんでしたが

@Entity 
public class Person { 

    private String name; 

    @ManyToOne 
    private Address address; 

    // other stuff 
} 

@Entity  
public class Address { 

    private String street; 

    // other stuff 
} 

は人を更新しようとすると:

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年8月24日

スコットC. answerのおかげで、それはSDRの2枚のチケットに記述されているバグ、持っていることが判明:DATAREST-1001DATAREST-1012を。

+0

リンクは、http:// localhost:8080/api/persons/1/address'(v.2.5.6)の対象は何ですか? – Andrew

+0

@AndrewTobilkoアドレス1: '{ "ストリート": "アドレス1"、 "_links":{ "自己":{ "HREF": "のhttp:// localhostを:8080/API /アドレス/ 1" } 、 " " href ":" http:// localhost:8080/api/addresses/1 " } } } – Cepr0

+0

なぜ最初のバージョンで動作するのか分かりませんでした。 'Address'インスタンスが単一の' String'から構築できないため、同じ例外がスローされているはずです。 'BaseEntity'とは何ですか? – Andrew

答えて

4

問題のようです。already been reported as a bug: - 確認してください。私が知る限りでは、これはあなたが上で報告している問題です。

このバグレポートは私の以前の回答を改訂しています。

+0

ありがとうございました!私はPUTとPATCHの違いを知っています。そしてあなたは本当に正しいと思っています.PUTは、エンティティを新しいもの、完全に、単純なフィールドと他のオブジェクトへの参照の両方で置き換える必要があります。 [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6)のように、**封入されたエンティティは、**変更されたものと見なすべきである(SHOULD)オリジンサーバー**に常駐しています。あなたが見ることができるように、 'Person'オブジェクトのフィールド 'name'は新しい 'person1u'値に置き換えられますが、' address'参照は置き換えられません。だから私は思う - これは実際にv。1.4.4からSBに登場したバグです – Cepr0

+2

これは質問への答えを提供しません。批評をしたり、著者の説明を求めるには、投稿の下にコメントを残してください。 - [レビューの投稿](レビュー/低品質の投稿/ 17106932) – Adonis

+0

ここと同じ問題であるかどうかはわかりません。はい、それは関連しているかもしれませんが、このバグはコレクション以外のリソースの関連付け(例えば@ManyToOneの関係)にも影響しますが、リンクしたバグはコレクションに関するものです。 –

3

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

私のプロジェクトでは、PATCHリクエストを使ってエンティティを更新することは問題ありませんが、PUTリクエストは、指定されたエンティティのフィールドのみを更新し、関連するリソースは更新しません。

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

  • 人々が正しく指摘したように、PUTはリソースを交換に使用する必要があり、全体としてあなたは、リソースのすべてのフィールドを提供する場合、それは、作業する必要があることを示唆している修正版、(のようにPOSTリクエストで)。しかし、現行のSpring Data RESTバージョンでは、エンティティの単純なフィールドのみが更新され、関連付けられたリソースはそのまま残されているため、PUTリクエストは「部分的にしか動作しません」のみになります(RFCを満たしていても) 。
  • また、Spring Data RESTでは、部分的にPUTリクエストを行うこともできます。つまり、PUTを介して名前フィールドだけを更新することができます。しかしそれはアドレスのために働かない。
  • それは春データRESTは、RFCがそれを指定する方法を正確に動作しないことを意味します(別の議論のためであり得るは、しかし、それはまた、一貫した使用を提供していません - 一つのフィールドの作品を​​更新し、他のDOEのを更新するときエラーの兆候がないわけではありません。

私はSpring Data REST 2.6.3を使用しています。

+0

ご意見ありがとうございます!私はすでにこの問題の客観性を疑うようになりました...)) – Cepr0

+0

このプレゼンテーション(https://speakerdeck.com/olivergierke/hypermedia-apis-with-spring-5?slide=20)で、Olver Gierkeは、 PUTを使用してリソースを更新/置換します。多分私たちは何かを知らないのでしょうか?)) – Cepr0

+0

[link](https://stackoverflow.com/questions/28459418/rest-api-put-vs-patch-with-real-life-examples)Scott Cさんが実際にPUTがPATCHが導入された後はそれほど役に立たない。唯一の妥当なユースケースは、要求が冪等である必要がある場合です。ですから、_common_更新のためにはPATCHが望ましいでしょう。 しかし、PUTは期待どおりに動作しないため、バグであるという事実は変わりません。 –

関連する問題