0

I try to use FetchType.LAZY with Spring Boot. But, why the FK column not show in the JSON even the query that executed is select the FK column? Here is my model, controller, repository and executed query that printed in the console, and also the JSON result in the postman

// AnswerModel
@Entity
@Table(name = "answers")
public class Answer implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private String text;
    private Question question;
    private Date createdAt;
    private Date updatedAt;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "question_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JsonIgnore
    public Question getQuestion() {
        return question;
    }

    public void setQuestion(Question question) {
        this.question = question;
    }

// others getter and setter
}

// QuestionModel
@Entity
@Table(name = "questions")
public class Question implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private String title;
    private String description;
    private Date createdAt;
    private Date updatedAt;

    // getters and setters
}

// AnswerController
@GetMapping("/answers")
    public List<Answer> getAllAnswer(){
        return answerRepository.findAll();
    }

// AnswerRepository
@Repository
@Transactional
public interface AnswerRepository extends JpaRepository<Answer, Long> {
}

// Query that executed when API hit in the postman
select
        answer0_.id as id1_0_,
        answer0_.created_at as created_2_0_,
        answer0_.question_id as question5_0_,
        answer0_.text as text3_0_,
        answer0_.updated_at as updated_4_0_ 
    from
        answers answer0_

// output JSON in postman (it did not show the question id, but the query did select the question_id column)
[
    {
        "id": 1,
        "text": "Please look into this github",
        "createdAt": "2018-11-22T03:55:48.865+0000",
        "updatedAt": "2018-11-22T03:55:48.865+0000"
    },
    {
        "id": 2,
        "text": "Please watch my youtube channel",
        "createdAt": "2018-11-22T03:55:57.642+0000",
        "updatedAt": "2018-11-22T03:55:57.642+0000"
    }
]

So, whats going wrong here? How to show the question_id? Is this answer really recommended? Hibernate - Foreign keys instead of Entities

UPDATED

Here is the latest code, but according to @Markoorn answer, I still could not figure out where I have to call the answer.getQuestion();

// AnswerModel
@Entity
@Table(name = "answers")
public class Answer implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private String text;
    private Question question;
    private Date createdAt;
    private Date updatedAt;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "question_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    public Question getQuestion() {
        return question;
    }

    public void setQuestion(Question question) {
        this.question = question;
    }

// others getter and setter
}

// QuestionModel
@Entity
@Table(name = "questions")
public class Question implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private String title;
    private String description;
    private Date createdAt;
    private Date updatedAt;

    // getters and setters
}

// AnswerController
@Transactional
@GetMapping("/answers")
    public List<Answer> getAllAnswer(){
        return answerRepository.findAll();
    }

// AnswerRepository
@Repository
@Transactional
public interface AnswerRepository extends JpaRepository<Answer, Long> {
}

// Query executed
Hibernate: 
    select
        answer0_.id as id1_0_,
        answer0_.created_at as created_2_0_,
        answer0_.question_id as question5_0_,
        answer0_.text as text3_0_,
        answer0_.updated_at as updated_4_0_ 
    from
        answers answer0_
Hibernate: 
    select
        question0_.id as id1_1_0_,
        question0_.created_at as created_2_1_0_,
        question0_.description as descript3_1_0_,
        question0_.title as title4_1_0_,
        question0_.updated_at as updated_5_1_0_ 
    from
        questions question0_ 
    where
        question0_.id=?

// Error

2018-11-22 13:07:42.037 ERROR 5692 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.example.postgresdemo.model.Answer["question"]->com.example.postgresdemo.model.Question$HibernateProxy$DzJlWmh6["hibernateLazyInitializer"])] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.example.postgresdemo.model.Answer["question"]->com.example.postgresdemo.model.Question$HibernateProxy$DzJlWmh6["hibernateLazyInitializer"])
Akza
  • 1,033
  • 3
  • 19
  • 37

1 Answers1

1

You have your question annotated with @JsonIgnore which tells Jackson NOT to serialize that value which is why it's missing.

The reason you are getting an error when you don't have @JsonIgnore there is because the serialization to JSON happens OUTSIDE of a transaction which will throw an exception. Either marking the question relationship as FetchType.EAGER or calling answer.getQuestion() inside a transaction before serializing so that the question is fetched instead of being a proxy.

You could also annotate your controller as @Transactional so the serialization happens inside a transaction.

Markoorn
  • 2,477
  • 1
  • 16
  • 31
  • Thank you @Markoorn for your answer. Sorry but I dont get what you mean by calling answer.getQuestion() inside a transaction? Where actually I have to call it? in the controller? or where? Thank you – Akza Nov 22 '18 at 07:15
  • To test it out you can do it in the controller. Just loop through the list of answers and call getQuestion() there to force hibernate to fetch the lazy entity and then return that list – Markoorn Nov 22 '18 at 14:33
  • Dear @Markoorn, sorry, I still dont get what u mean. Sorry, I just start learning java. What I've done so far is get rid of JsonIgnore anotation as u said. Then modify my controller into: GetMapping("/answers") Transactional public List getAllAnswer(){ List answers = answerRepository.findAll(); for (Answer answer : answers) { answer.getQuestion(); answers.add(answer); } return answers; } But it turns error "java.util.ConcurrentModificationException: null". Then, what its suppose to? Big thanks if u could help me. – Akza Nov 25 '18 at 09:17