How to POST nested entities with Spring Data REST
jackson, post, rest, spring
Solution
Try adding `@RestResource(exported = false)` on field `answers` in class `Questionary`.
According to me, this error occurs because the deserializer expects URIs to fetch the answers from, instead of having the answers nested in the JSON. Adding the annotation tells it to look in JSON instead.
Problem
I'm building a Spring Data REST application and I'm having some problems when I try to POST it. The main entity has other two related entities nested. There is a "questionary" object which has many answers and each one of these answers have many replies. I generate a JSON like this from the front application to POST the questionary: ``` { "user": "http://localhost:8080/users/1", "status": 1, "answers": [ { "img": "urlOfImg", "question": "http://localhost:8080/question/6", "replies": [ { "literal": "http://localhost:8080/literal/1", "result": "6" }, { "literal": "http://localhost:8080/literal/1", "result": "6" } ] }, { "img": "urlOfImg", "question": "http://localhost:8080/question/6", "replies": [ { "literal": "http://localhost:8080/literal/3", "result": "10" } ] } ] } ``` But when I try to post it, I get the follow error response: ``` { "cause" : { "cause" : { "cause" : null, "message" : "Template must not be null or empty!" }, "message" : "Template must not be null or empty! (through reference chain: project.models.Questionary[\"answers\"])" }, "message" : "Could not read JSON: Template must not be null or empty! (through reference chain: project.models.Questionary[\"answers\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Template must not be null or empty! (through reference chain: project.models.Questionary[\"answers\"])" } ``` Edit: I also add my repository: ``` @RepositoryRestResource(collectionResourceRel = "questionaries", path = "questionaries") public interface InspeccionRepository extends JpaRepository<Inspeccion, Integer> { @RestResource(rel="byUser", path="byUser") public List<Questionary> findByUser (@Param("user") User user); } ``` My Entity Questionary class is : ``` @Entity @Table(name="QUESTIONARY", schema="enco" ) public class Questionary implements Serializable { private static final long serialVersionUID = 1L; //---------------------------------------------------------------------- // ENTITY PRIMARY KEY ( BASED ON A SINGLE FIELD ) //---------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEC_QUESTIONARY") @SequenceGenerator(name = "SEC_QUESTIONARY", sequenceName = "ENCO.SEC_QUESTIONARY", allocationSize = 1) @Column(name="IDQUES", nullable=false) private Integer idques ; //---------------------------------------------------------------------- // ENTITY DATA FIELDS //---------------------------------------------------------------------- @Column(name="ESTATUS") private Integer estatus ; //---------------------------------------------------------------------- // ENTITY LINKS ( RELATIONSHIP ) //---------------------------------------------------------------------- @ManyToOne @JoinColumn(name="IDUSER", referencedColumnName="IDUSER") private User user; @OneToMany(mappedBy="questionary", targetEntity=Answer.class) private List<Answer> answers; //---------------------------------------------------------------------- // CONSTRUCTOR(S) //---------------------------------------------------------------------- public Questionary() { super(); } //---------------------------------------------------------------------- // GETTERS & SETTERS FOR FIELDS //---------------------------------------------------------------------- //--- DATABASE MAPPING : IDNSE ( NUMBER ) public void setIdnse( Integer idnse ) { this.idnse = idnse; } public Integer getIdnse() { return this.idnse; } //--- DATABASE MAPPING : ESTADO ( NUMBER ) public void setEstatus Integer estatus ) { this.estatus = estatus; } public Integer getEstatus() { return this.estatus; } //---------------------------------------------------------------------- // GETTERS & SETTERS FOR LINKS //---------------------------------------------------------------------- public void setUser( Usuario user ) { this.user = user; } public User getUser() { return this.user; } public void setAnswers( List<Respuesta> answers ) { this.answers = answer; } public List<Answer> getAnswers() { return this.answers; } // Get Complete Object method public List<Answer> getAnswerComplete() { List<Answer> answers = this.answers; return answers; } } ``` My Answer Entity: ``` @Entity @Table(name="ANSWER", schema="enco" ) public class Answer implements Serializable { private static final long serialVersionUID = 1L; //---------------------------------------------------------------------- // ENTITY PRIMARY KEY ( BASED ON A SINGLE FIELD ) //---------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEC_ANSWER") @SequenceGenerator(name = "SEC_ANSWER", sequenceName = "ENCOADMIN.SEC_ANSWER", allocationSize = 1) @Column(name="IDANS", nullable=false) private Integer idans ; //---------------------------------------------------------------------- // ENTITY DATA FIELDS //---------------------------------------------------------------------- @Column(name="IMG", length=100) private String img ; //---------------------------------------------------------------------- // ENTITY LINKS ( RELATIONSHIP ) //---------------------------------------------------------------------- @ManyToOne @JoinColumn(name="IDQUES", referencedColumnName="IDQUES") private Questionary questionary ; @OneToMany(mappedBy="answer", targetEntity=Reply.class) private List<Reply> replies; @ManyToOne @JoinColumn(name="IDQUE", referencedColumnName="IDQUE") private Question Question ; //---------------------------------------------------------------------- // CONSTRUCTOR(S) //---------------------------------------------------------------------- public Answer() { super(); } //---------------------------------------------------------------------- // GETTER & SETTER FOR THE KEY FIELD //---------------------------------------------------------------------- public void setIdans( Integer idans ) { this.idans = idans ; } public Integer getIdans() { return this.idans; } //---------------------------------------------------------------------- // GETTERS & SETTERS FOR FIELDS //---------------------------------------------------------------------- //--- DATABASE MAPPING : IMAGEN ( VARCHAR2 ) public void setImg( String img ) { this.img = img; } public String getImg() { return this.img; } //---------------------------------------------------------------------- // GETTERS & SETTERS FOR LINKS //---------------------------------------------------------------------- public void setQuestionary( Questionary questionary ) { this.questionary = questionary; } public Questionary getQuestionary() { return this.questionary; } public void setReplies( List<Reply> contestaciones ) { this.replies = replies; } public List<Reply> getReplies() { return this.replies; } public void setQuestion( Question question ) { this.question = question; } public Question getQuestion() { return this.question; } } ``` And this is the error console: ``` Caused by: com.fasterxml.jackson.databind.JsonMappingException: Template must not be null or empty! (through reference chain: project.models.Questionary["answers"]) at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232) ~[jackson-databind-2.3.3.jar:2.3.3] at *snip* ```