Подтвердить что ты не робот

Как вложенные объекты POST с помощью Spring Data REST

Я создаю приложение Data REST Spring, и у меня возникают некоторые проблемы, когда я пытаюсь выполнить POST. Основной объект имеет два других связанных объекта.

Существует "вопросный" объект, который имеет много ответов, и каждый из этих ответов имеет много ответов.

Я генерирую JSON, как это из переднего приложения, в POST-запрос:

{
    "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"
                }
            ]
        }
    ]
}

Но когда я пытаюсь опубликовать его, я получаю следующий ответ об ошибке:

{

    "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\"])"
}

Изменить:

Я также добавляю свой репозиторий:

@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:

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

Мой объект-ответ:

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


}

И это консоль ошибок:

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*
4b9b3361

Ответ 1

Попробуйте добавить @RestResource(exported = false) в поле answers в классе Questionary.

По мне, эта ошибка возникает из-за того, что десериализатор ожидает, что URI будут получать ответы от них вместо ответов, вложенных в JSON. Добавление аннотации говорит ему, чтобы он выглядел в JSON.

Ответ 2

Я все еще вижу эту ошибку с 2.3.0.M1, но я, наконец, нашел обходной путь.

Основная проблема заключается в следующем: если вы публикуете URL-адрес встроенного объекта в JSON, он работает. Если вы публикуете фактический внедренный объект JSON, это не так. Он пытается десериализовать объект JSON в URI, который, конечно, не работает.

Похоже, проблема связана с двумя объектами TypeConstrainedMappingJackson2HttpMessageConverter, которые создает резерв данных spring в своей конфигурации (в RepositoryRestMvcConfiguration.defaultMessageConverters()).

Я, наконец, обошел эту проблему, настроив поддерживаемые типы носителей messageConverters так, чтобы он пропускал эти два и удалял обычный MappingJackson2HttpMessageConverter, который отлично работает с вложенными объектами.

Например, если вы расширяете RepositoryRestMvcConfiguration и добавляете этот метод, то при отправке запроса с типом контента "application/json" он попадет в обычный MappingJackson2HttpMessageConverter вместо того, чтобы пытаться десериализовать в URI:

@Override
public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    ((MappingJackson2HttpMessageConverter) messageConverters.get(0))
            .setSupportedMediaTypes(asList(MediaTypes.HAL_JSON));
    ((MappingJackson2HttpMessageConverter) messageConverters.get(2))
            .setSupportedMediaTypes(asList(MediaType.APPLICATION_JSON));
}

Это настраивает конвертеры сообщений, созданные по умолчаниюMessageConverters() в RepositoryRestMvcConfiguration.

Имейте в виду, что простой objectMapper не может обрабатывать URI в JSON - вам все равно нужно ударить один из двух предварительно сконфигурированных конвертеров сообщений при передаче URI встроенных объектов.

Ответ 3

Одна проблема с вашим JSON заключается в том, что вы пытаетесь десериализовать строку как вопрос:

"question": "http://localhost:8080/question/6"

В вашем объекте Answer Джексон ожидает объект для вопроса. Похоже, что вы используете URL-адреса для идентификаторов, поэтому вместо строки вам нужно передать что-то вроде этого для вашего вопроса:

"question": {
    "id": "http://localhost:8080/question/6"
}

Ответ 4

Попробуйте обновить библиотеку Spring Boot Data REST Starter ". Работал для меня.