Spring Data REST: "没有字符串参数的构造函数/工厂方法来反序列化字符串值"

7

在我的Spring Data REST应用程序中使用Lombok来定义复杂类型时:

@NoArgsConstructor
@AllArgsConstructor
@Data

@Entity
@Table(name = "BOOK")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false)
    private Long id;

    private String title;

    @ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH})
    private Person author;

    // ...
}

使用Spring Data REST控制器如下:

@RepositoryRestController
public class BookRepositoryRestController {

    private final BookRepository repository;

    @Autowired
    public BookRepositoryRestController(BookRepository repository) {
        this.repository = repository;
    }

    @RequestMapping(method = RequestMethod.POST,value = "/books")
    public @ResponseBody PersistentEntityResource post(
        @RequestBody Book book,
        PersistentEntityResourceAssembler assembler) {

        Book entity = processPost(book);

        return assembler.toResource(entity);
    }

    private Book processPost(Book book) {
        // ...
        return this.repository.save(book);
    }
}

我遇到了一个丑陋的错误:
no String-argument constructor/factory method to deserialize from String value

Spring Data REST使用Jackson处理Book POST请求的示例:

curl -X POST 
     -H 'content-type: application/json' 
     -d '{"title":"Skip Like a Pro", "author": "/people/123"}'
     http://localhost:8080/api/books/

当Jackson尝试解析应该解析为单个唯一的Person/people/123本地URI时,会发生反序列化错误。如果我删除@RepositoryRestController,一切都正常。您对我的REST控制器定义有什么想法吗?


嘿,Jan,为什么你在AllArgsConstructor中使用suppressConstructorProperties = true?Lombok文档说:“如果设置为true,则lombok将跳过向生成的构造函数添加@java.beans.ConstructorProperties。这在Android和GWT开发中非常有用,因为该注释通常不可用。”看起来你不属于推荐的情况。如果你删除这个配置会发生什么? - avi.elkharrat
请查看Lombock中的@Data注释。它会生成equals和hash code。 - avi.elkharrat
@avi613 -- 不幸的是,如果没有@AllArgsConstructor(suppressConstructorProperties = true),Jackson的反序列化会触发上述错误--这很可能是Lombok的一个bug。 - Jan Nielsen
1个回答

11
@RepositoryRestController 中,将 @RequestBody 参数的类型从 Book 更改为 Resource<Book>
import org.springframework.hateoas.Resource;

    // ...

    @RequestMapping(method = RequestMethod.POST,value = "/books")
    public @ResponseBody PersistentEntityResource post(
        @RequestBody Resource<Book> bookResource,             // Resource<Book>
        PersistentEntityResourceAssembler assembler) {

        Book book = bookResource.getContent()
        // ...
    }

Book 实体定义中,将 AllArgsConstructor 注解修改为: @AllArgsConstructor(suppressConstructorProperties = true)

更多信息,请参见 Spring Data REST #687


3
我用 @RepositoryRestResource 将我的仓库暴露为 spring-data-rest HATEOAS 资源,没有使用 RepositoryRestController,但我收到了相同的错误。如何解决这个问题? - Robert
@Robert -- 很可能是同样的根本问题:Jackson无法反序列化您的数据;但是,对于您的情况,解决方案将是不同的。我建议您打开一个新问题,并提供所有细节... - Jan Nielsen
2
@Robert -- 你也可以阅读Spring REST参考文档中的Domain Object Representations部分 - Jan Nielsen
@Robert,当你使用 @RepositoryRestResource 时,你找到解决方案了吗? - Michael J Lawley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接