Spring Data REST: "no String-argument constructor/factory method to deserialize from String value"

18,510

In the @RepositoryRestController, change the type of the @RequestBody argument from Book to 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()
        // ...
    }

and in the Book entity definition modify the AllArgsConstructor annotation to be: @AllArgsConstructor(suppressConstructorProperties = true).

See Spring Data REST #687 for more information.

Share:
18,510
Jan Nielsen
Author by

Jan Nielsen

Technologist, programmer, entrepreneur.

Updated on June 15, 2022

Comments

  • Jan Nielsen
    Jan Nielsen almost 2 years

    When I use Lombok in my Spring Data REST application to define complex types like:

    @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;
    
        // ...
    }
    

    with a Spring Data REST controllers like:

    @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);
        }
    }
    

    I get an ugly error:

    no String-argument constructor/factory method to deserialize from String value
    

    from Spring Data REST's use of Jackson with a Book POST like:

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

    The de-serialization error happens when Jackson tries to resolve the /people/123 local URI which should resolve to a single, unique Person. If I remove my @RepositoryRestController, everything works fine. Any idea what's wrong with my REST controller definition?

  • Robert
    Robert over 7 years
    I am exposing my Repositores with @RepositoryRestResource (as spring-data-rest HATEOAS Resources) I do not have any RepositoryRestController. But I get the same error. How can I work around it?
  • Jan Nielsen
    Jan Nielsen over 7 years
    @Robert -- it is likely the same fundamental problem: Jackson cannot de-serialize your data; but, the solution will be different for your case. I suggest you open a new question with all the details...
  • Jan Nielsen
    Jan Nielsen over 7 years
  • Michael J Lawley
    Michael J Lawley almost 3 years
    @Robert did you ever find a solution to this when using \@RepositoryRestResource ?