Spring数据REST - PUT请求自v.2.5.7

时间:2017-08-10 17:37:04

标签: java rest spring-boot spring-data-rest put

由于版本 2.5.7 ,因此Spring Data REST无法正确执行 PUT 请求以更新具有关联资源的资源。与按预期工作的PATCH请求不同!

例如,PersonAddres具有多对一关联。如果我们使用SDR v.2.5.6(Spring Boot v.1.4.3)执行PUT请求,那么一切正常。但是如果我们切换到2.5.7版(即Spring Boot v.1.4.4),那么我们会收到一个错误:

  

无法构造Address的实例:no String-argument构造函数/工厂方法从String值反序列化

其他类型的关联也是如此,例如一对多(单向和双向) - 请参阅我的 example application 代码和测试。

此问题出现在自1.4.4以来的Spring引导的所有版本中,包括最新的稳定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, 有必要告诉Lombok禁止使用@ConstructorProperties注释 generated constructors。 所以我在'lombok.config'文件中设置了lombok.anyConstructor.suppressConstructorProperties=true,错误就消失了。

不幸的是发现新问题 - PUT请求根本不更新关联对象

以下示例说明了这一点。当我们尝试通过将他的地址从addresses/1(初始值)更改为addresses/2来更新人员时,它仍保持不变:addresses/1!与上一个问题一样,这个问题出现在自1.4.4以来的Spring引导的所有版本中(SDR - 来自v.2.5.7)。

我调试了我的项目,发现问题的原因隐藏在方法DomainObjectReader#mergeForPut中(请参阅its source) - 从不用新的替换相关资源

在我Spring JIRA发布此问题之前,如果您的项目中存在此问题,请在此报告,您对此有何看法

你可以得到我的测试here并在你的项目中检查它 - 测试是'独立的'并且不依赖于其他类/模块(我希望只排除H2)。

@Entity
public class Person {

    private String name;

    @ManyToOne
    private Address address;

    // other stuff
}

@Entity    
public class Address {

    private String street;

    // other stuff
}

尝试更新人员:

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

感谢Scott C. answer,结果发现SDR有一个错误,在两张门票中有描述:DATAREST-1001DATAREST-1012。< / p>

2 个答案:

答案 0 :(得分:4)

问题似乎有already been reported as a bug: - 请验证。尽我所知,这是您在上面报告的问题。

注意,我正在修改我以前的答案是这个错误报告。

答案 1 :(得分:3)

我同意你的意见,这是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。