How to add a "book" to / shelves / 1 / books

I can't figure out how to do something that should be incredibly simple.

I have two objects: a shelf and a book. A shelf may have one or more books. Each of these objects has a corresponding JpaRepository open as a rest repository using Spring Data Rest. When I run the application, all the query endpoints work fine, but I can’t understand how I can add the book to the shelf.

First I add a shelf using POSTing {"name": "westerns"} to the shelves (works fine).

Method 1: I'm trying to add a POSTing {"name": "mybook"} book to / shelves / 1 / books, but I get 405 error "method not allowed". Can I publish a book only in the endpoint / books (without writing my own controller, I mean)? And if so, will I need to implement the shelf object to which the book belongs?

Method 2: If I try to add a book by doing PUT to / shelves / 1 using the content {"name": "westerns", "books": [{"name": "mybook"}]}, I get the following message about error:

Message: "Could not read JSON: the template should not be empty or empty! (Via the chain of links: org.demo.Shelf [" books "]); the nested exception is com.fasterxml.jackson.databind.JsonMappingException: The template should not be empty or empty! (via the link chain: org.demo.Shelf ["books"])

Statcktrace:

2014-11-06 06: 55: 18.864 ERROR 9888 --- [nio-8080-exec-5] sdrwAbstractRepositoryRestController: Failed to read JSON: The template must not be empty or empty! (via the link chai n: org.demo.Shelf ["books"]); nested exception com.fasterxml.jackson.databind.JsonMappingException: the template must not be empty or empty! (via the reference chain: org.demo.Shelf ["books"])

org.springframework.http.converter.HttpMessageNotReadableException: Failed to read JSON: the template must not be empty or empty! (via the reference chain: org.demo.Shelf ["books"]); com.fasterxml.jackson.databind.JsonMappingException exception exception: template must not be empty or empty! (via the chain of links: org.demo.Shelf ["books"]) in org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType (MappingJackson2HttpMessageConverter.java:228) in org.springframework.hsonspMttp.convertMonverter.jttpmconverter readInternal (MappingJackson2HttpMessageConverter.java:212) in org.springframework.http.converter.AbstractHttpMessageConverter.read (AbstractHttpMessageConverter.java:159) in org.springframework.data.rest.webmvc.config.PersistentEntityResourceHandlerMethodArgumentResolver.resolveArgument (PersistentEntityResourceHandlerMethodArgumentResolver.java:100) in org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument (HandlerMethodArgumentResolverComposite.java:79) in org.springframework.web.method.support.InvocableHandlerMethod.getMethodmentethodemethodmentethodemethodmentethodmodethetchgumentCommentodethethommentodment .method.support.InvocableHandlerMethod.invokeForReq uest (InvocableHandlerMethod.java:124) in org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle (ServletInvocableHandlerMethod.java:104) in org.springframework.mebem. invokeHandleMethod (RequestMappingHandlerAdapter.java:749) in org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal (RequestMappingHandlerAdapter.java:689) in org.springframework.web.servhandMbc.mehand AbstractHandlerMethodAdapter.java:83) in org.springframework.web.servlet.DispatcherServlet.doDispatch (DispatcherServlet.java:938) in org.springframework.web.servlet.DispatcherServlet.doService (DispatcherServlet.java:870fwork org .servlet.FrameworkServlet.processRequest (FrameworkServlet.java:961) in org.springframework.web.servlet.FrameworkServlet.doPut (FrameworkServlet.java:874) in javax.servlet.http.HttpServlet.s ervice (HttpServlet.java:649) in org.springframework.web.servlet.FrameworkServlet.service (FrameworkServlet.java:837) in javax.servlet.http.HttpServlet.service (HttpServlet.java:727) in org.apache.catalina .core.ApplicationFilterChain.internalDoFilter (ApplicationFilterChain.java:303) in org.apache.catalina.core.ApplicationFilterChain.doFilter (ApplicationFilterChain.java:208) in org.springframework.web.filter.HiddenHttpMethodFilter.ilterlterterterterterterterterterterterterterter ) in org.springframework.web.filter.OncePerRequestFilter.doFilter (OncePerRequestFilter.java:107) in org.apache.catalina.core.ApplicationFilterChain.internalDoFilter (ApplicationFilterChain.java:241) in org.apache.ppalal. doFilter (ApplicationFilterChain.java:208) in org.apache.catalina.core.StandardWrapperValve.invoke (StandardWrapperValve.java:220) in org.apache.catalina.core.StandardContextValve.invoke (StandardContextValve.java:122) .catalina.authenticator.Au thenticatorBase.invoke (AuthenticatorBase.javaPoint01) in org.apache.catalina.core.StandardHostValve.invoke (StandardHostValve.java:171) in org.apache.catalina.valves.ErrorReportValve.invoke (ErrorReportValve.java10 .apache.catalina.core.StandardEngineValve.invoke (StandardEngineValve.java:116) in org.apache.catalina.connector.CoyoteAdapter.service (CoyoteAdapter.java:408) in org.apache.coyote.http11.AbstractHttp11Processor Process Abstract .java: 1070) in org.apache.coyote.AbstractProtocol $ AbstractConnectionHandler.process (AbstractProtocol.java:611) in org.apache.tomcat.util.net.NioEndpoint $ SocketProcessor.doRun (NioEndpoint.java:1736) in org. apache.tomcat.util.net.NioEndpoint $ SocketProcessor.run (NioEndpoint.java:1695) in java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145) in java.util.concurrent.ThreadPoolExecutor $ Worker ThreadPoolExecutor.java:615) in org.apache.tomcat.util.threads.TaskThread $ WrappingRunnable.ru n (TaskThread.java:61) in java.lang.Thread.run (Thread.java: 745) Called: com.fasterxml.jackson.databind.JsonMappingException: the template must not be empty or empty! (via the link chain: org.demo.Shelf ["books"]) in com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath (JsonMappingException.java:232) in com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath (JsonMappingException. java: 197) in com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow (BeanDeserializerBase.java:1420) in com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize (BeanDeserializer.javaaster4) .jackson. .java: 2158) in org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType (MappingJackson2HttpMessageConverter.java:225) ... 38 common frames omitted Cause: java.lang.IllegalArguExi on: the template must not be null or empty! at org.springframework.util.Assert.hasText (Assert.java:162) at org.springframework.hateoas.UriTemplate. (UriTemplate.java:56) in org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module $ UriStringDeserializer.deserialize (PersistentEntityJackson2Module.javahaps80) in com.fasterxml.jackson.databinderializerizerizerizerizerizer .java: 227) in com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize (CollectionDeserializer.java:204) in com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize (CollectionDeserializer.java:23 ) in com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize (SettableBeanProperty.javahaps25) in com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet (MethodProperty.java:99) in com.fasterml. jackson.databind.deser.BeanDeserializer.vanillaDeserialize (BeanDeserializer.java:242) ... 42 common frames are omitted

Here is all the relevant code (of course, each class is in its own file).

@Entity public class Shelf { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String name; @OneToMany private List<Book> books; public List<Book> getBooks() { return books; } public void setBooks(List<Book> books) { this.books = books; } public String getName() { return name; } public void setName(String name) { this.name = name; } } @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } @RepositoryRestResource public interface BookRepository extends JpaRepository<Book, Long>{ } @RepositoryRestResource public interface ShelfRepository extends JpaRepository<Shelf, Long>{ } 

I am using Spring Boot 1.1.8.RELEASE

+3
spring-boot spring-data-rest
source share
2 answers

Book objects have their own REST endpoint and create one to which you must connect to that endpoint.

To place a book on a shelf, you must send the URI of this book to the association URI ( /shelves/{id}/books ). Surprisingly, the documentation is erroneous, and adding items is not done through POST, but PATCH:

 PATCH http://localhost:8080/shelves/1/books Content-Type: text/uri-list http://localhost:8080//books/1 

You can add multiple books at a time, one URI per line. If you do not want to add books, but rather replace all books on the shelf with new ones, i.e. Replace the entire collection, you can use PUT.

+3
source share

I think I found the easiest way to do this (I made a bidirectional Book-Shelf ratio).

  • Create a shelf to hold the book by placing the {"name:" westerns "} to / shelves
  • Place a new book with the parent shelf URI by placing {"name": "mybook", "shelf": "localhost: 8080 / shelves / 1"} to / books

It works great. Well, sort of. The book was created with the correct reference to the parent, but now I have a problem with the parent not showing the book under / shelves / 1 / books. I wrote a new question for here .

0
source share

All Articles