2

I am using JPA with hibernate in my spring boot application. Whenever I try to fetch the enities using jpa methods, its returning the entity plus all the association present inside it. I wanted to fetch the associated entities on demand(lazy loading), so I have provided fetch=FetchType.LAZY in my domain class. But still its returning all the entries.

Below is the code: Case.java

    @Entity
    @Table(name="smss_case")
    public class Case implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -2608745044895898119L;

    @Id
    @Column(name = "case_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer caseId;

    @Column( name="case_title" )
    private String caseTitle;

    @JsonManagedReference
    @OneToMany(mappedBy="smmsCase", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    private Set<Task> tasks;

    }

}

Task.java

@Entity
@Table(name="task_prop")
public class Task implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -483515808714392369L;

    @Id
    @Column(name = "task_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer taskId;

    @Column(name="task_title")
    private String taskTitle;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn( name="case_id", nullable=false)
    private Case smmsCase;
// getters and setters
}

Service.java

public Case getCases(Integer id) {
        return dao.findById(1).get();
}

Dao.java

public interface ServiceDao extends JpaRepository<Case, Integer>{

}

{
"caseId":1, "caseTitle":"ergonomics", "tasks":[
{
"taskId":1, "taskTitle":"ca" }, {
"taskId":2, "taskTitle":"hazards" }, {
"taskId":3, "taskTitle":"remedy" } ] }

Any help will be highly appreciated!

Thanks!

6
  • What makes you think lazy loading doesn't work? My guess: you're serializing a Case to JSON, and you see its tasks in the JSON. Lazy loading doesn't mean "no loading". It means that when something (like the JSON serializer) calls a method of the set of tasks (to serialize them), then, and only then, JPA executes the query to load the tasks. Lazy loading is working fine. You just don"t understand what it means. Setting fetch=LAZY on a OneToMany is useless, BTW, since that's the default value. Commented Nov 25, 2018 at 8:29
  • @ JB Nizet, Thanks for your response. I still have a confusion. No where in my service I am calling any methods of set of tasks. Still the getCases() method inside my Service is loading all the associated tasks. Please let me know whats going wrong here. Thanks! Commented Nov 25, 2018 at 9:34
  • "when something (like the JSON serializer) calls a method of the set of tasks (to serialize them)". JSON serialization doesn't happen by magic. The JSON serializer goes through all the properties of your object to get their value and transform them to JSON. If they're a collection (like your set of tasks), it iterates through the collection, using their iterator() method. So that triggers the lazy loading. Commented Nov 25, 2018 at 9:37
  • Can you share your controller code? Do you return your entity directly or some dto which represents it? It might be happened because of you return entity itself and the serializer calls related models while serialization. Commented Nov 25, 2018 at 9:43
  • @ JB Nizet, thank you so much!! You were right. Lazy loading is actually working but when I try to return the object from my API, it was calling the associated entities. @ Emre Savcı, Thanks for your response, I got it working. As mentioned, when the controller is returning the entity, object to json serialization is triggering the associations. To do this, I have configured MappingJackson2HttpMessageConverter. (reference: stackoverflow.com/questions/21708339/…) Commented Nov 25, 2018 at 12:54

1 Answer 1

2

Was tricky to investigate but I had this issue as I was using mapstruct and it happens to do deep/ nested mapping and in the process, it calls getter of the lazy loaded property. The issue was resolved when I used mapstrct @BeforeMapping.

@Mapper
public interface HibernateAwareMapper {
    @BeforeMapping
    default <T> Set<T> fixLazyLoadingSet(Collection<?> c, @TargetType Class<?> targetType) {
        if (!Util.wasInitialized(c)) {
            return Collections.emptySet();
        }
        return null;
    }

    @BeforeMapping
    default <T> List<T> fixLazyLoadingList(Collection<?> c, @TargetType Class<?> targetType) {
        if (!Util.wasInitialized(c)) {
            return Collections.emptyList();
        }
        return null;
    }

   class Util {
       static boolean wasInitialized(Object c) {
           if (!(c instanceof PersistentCollection)) {
               return true;
           }

           PersistentCollection pc = (PersistentCollection) c;
           return pc.wasInitialized();
       }
   }
}

Ref. by kokorin

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.