0

I am facing lazy inizialization issue when I added Lombok project into my hibernate project and used its @Getter and @Setter on the entity class. Entity classes are annotated with @Entity of Javax.persistence as I am using hibernate 5.

Issue stacktrace :-

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:146)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:259)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
    at com.capehenry.domain.user.User_$$_jvst52e_9.getId(User_$$_jvst52e_9.java)
    at com.capehenry.business.rs.course.SeatRequestResource.validateSeatRequestCancel(SeatRequestResource.java:338)
    at com.capehenry.business.rs.course.SeatRequestResource.cancel(SeatRequestResource.java:220)

Everything was working fine with below code

@Entity
@Audited
@Table(name = "seat_request")
public class SeatRequest extends BaseEntity {

    private CourseSchedule courseSchedule;

@ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "courseScheduleId", nullable = false)
public CourseSchedule getCourseSchedule() {
    return courseSchedule;
}

public void setCourseSchedule(CourseSchedule courseSchedule) {
    this.courseSchedule = courseSchedule;
}

When I do searRequest.getCourseSchedule().getId() it works at rest layer means outside the transaction.

As soon as I change the code to below (add lombok), searRequest.getCourseSchedule().getId() at rest layer starts throwing lazyInitializationException :-

@Entity
@Audited
@Table(name = "seat_request")
@Setter
public class SeatRequest extends BaseEntity {

    @ManyToOne(fetch = FetchType.LAZY, optional=false)
    @JoinColumn(name = "courseScheduleId", nullable = false)
    private CourseSchedule courseSchedule;

NOTE :- 1) I have to compulsory use Lombok project
2) I have to use searRequest.getCourseSchedule().getId() outside Sevrice and trasaction

Please suggest the solution, Thanks in advance!!

Swati Joshi
  • 105
  • 3
  • 14
  • So why not just EAGER fetch the ID? Lazy fetching is generally a good strategy for things you do not necessarily need all the time, an ID field is important enough to just fetch eagerly. – Gimby May 02 '18 at 08:53

2 Answers2

2

I have to use searRequest.getCourseSchedule().getId() outside Service and transaction

I have noticed this just now... If you are outside the service and transaction you will always have that exception. Try to use FetchType.EAGER and it should work.

When you are out of transaction your entities are detached, this means that all collections that you marked as lazy won't be loaded. So you have two options: the first is to perform all calls to collections getters inside the transaction, the second one is to mark as eager your collection, so when Hibernate loads the entity it will also load referenced collection immediately. Alternatively you could map to a DTO your Entity inside your transaction. As long as you are in the transaction the getters of lazy loaded field will always work, so a mapper to the DTO would access all informations. Once that the DTO is out of the transaction you will have access to all fields you have mapped, and than do whatever you want.

Lorelorelore
  • 3,335
  • 8
  • 29
  • 40
  • Thanks fro your quick reply.. I have already used FethcType.LAZY. And my concern is that it was working previously.. I added my old code as I missed in that I was having annotations on getter method instead of on field level while it was working outside transaction. – Swati Joshi May 02 '18 at 09:17
  • Have you tried using annotation on fields with no lombok? – Lorelorelore May 02 '18 at 09:25
  • no.. I was about to do that.. but meanwhile find this link https://stackoverflow.com/questions/2593722/hibernate-one-to-one-getid-without-fetching-entire-object?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa So now trying to have access type = property – Swati Joshi May 02 '18 at 09:31
  • Let us know if that helps – Lorelorelore May 02 '18 at 09:34
  • 1
    I have found the solution.. will put as an answer to this question.. Thank you for your help @Lore – Swati Joshi May 02 '18 at 11:11
  • I have noticed that I made a mistake: I meant EAGER and not LAZY when annotating the FetchType. However, how did you solve it? – Lorelorelore May 02 '18 at 18:31
  • 1
    I have added the solution as an answer to this question – Swati Joshi May 03 '18 at 11:57
1

Here is how I solved the issue finally!
I thought the issue started after integration with Lombok project but the issue started when the annotations were moved to field level from method (property) level.
Bear with me for the long answer. Here foreign is refering to the database level foreign tables.
To access any column from foreign table's outside the transaction you need to either use FetchType.Eager (which is default in hibernate for any foreign object) or need to join/subquery that table.

But if you just want to fetch the foreign key(column) with which 2 tables are joined (in our case the ID) and want to keep FetchType.LAZY then you can do it in 2 ways :-

1) Keep annotations (manyToOne, JoinColumn etc) on getter methods

2) If annotations has to be kept on field level then write one more annotation on foreign key field in parent table which is - @Access(AccessType.PROPERTY) So in above code to solve I added this annotation on id field of course Schedule

@Entity
@Audited
@Table(name = "course_schedule")
@Getter
@Setter
public class CourseSchedule{
@Id
@GenericGenerator(name = "autoincr", strategy = "native")
@GeneratedValue(generator = "autoincr")
@Column(name = "id", unique = true, nullable = false)
@Access(AccessType.PROPERTY)
protected Long id;
..........
}

So no change was required in Seat Request.

Swati Joshi
  • 105
  • 3
  • 14