1

I'm having a lazy initialization exception using spring. I know this is a common error and I've been through several stack questions, but none of the answers really did it for me. Here's my scenario: I have two classes that relate like such:

public class Foo implements Serializable {
    @Id
    @EqualsAndHashCode.Include
    @Column(name = "uuid")
    private UUID uuid;

    @Column(name = “attribute”)
    private String attribute;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = “foo”)
    private Set<Bar> bar;
}

public class Bar implements Serializable {

    @Id
    @Column(name = "uuid")
    private UUID uuid;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = “foo_uuid")
    private Foo foo;
}

I have a rest endpoint that lists all Bar objects. In that specific endpoint, I need to return attribute, which is a Foo attribute. Since that is not required inside the application business logic, it seemed unnecessary to add attribute to Bar as well. So I have a BarWrapper class, which is a custom format of Bar, to be returned by the endpoint:

@Getter
@Setter
@NoArgsConstructor
public class BarWrapper {
    …
    private String attribute;

    public BarWrapper(final Bar bar) {
        //The next line throws lazy initialization exception.
        this.attribute = bar.getFoo().getAttribute()

}

I have tried @Transactional on all classes, and didn't work. I tried to add cascade = CascadeType.ALL, which did work, but is not a good practice. I have also tried creating a custom function just for this, but didn't help either:

@Transactional
    private String extractAttribute(final Bar bar){
        final Foo foo = bar.getFoo();
        return foo.getAttribute();
    }

How can I overcome this Lazy initialization exception?

EDIT:

This is how I'm calling the BarWrapper constructor:

@AllArgsConstructor
@Service
@Slf4j
public class BarApplicationServices {


private final FooService fooService;
private final BarService barService;


public BarWrapper createBar(final CreateBarRequestBody requestBody) {
    final Foo foo = fooService.findFooToBeSettled(requestBody.getFooUuid());
    final Bar createdBar = barService
            .createBar(new Bar(foo));
    return new BarWrapper(createdBar);
}


}
Pelicer
  • 1,348
  • 4
  • 23
  • 54
  • How you call the constructor of `BarWrapper`? Show us the code there, it should be inside a Service method in which you load the `Bar` entity from database in order to make sure that calling `bar.getFoo()` will be in the same transaction. – pleft Nov 03 '21 at 10:55
  • Why do you lazy initialise Foo object in Bar class? – memoricab Nov 03 '21 at 11:00
  • @memoricab it is a rather large object that I don't actually use often. – Pelicer Nov 03 '21 at 11:01
  • @pleft added the code as requested. – Pelicer Nov 03 '21 at 11:02
  • But if you lazy fetch that object, you don't see the content of it right? So is not it normal it throws an exception when you try to access which is not fetched yet? – memoricab Nov 03 '21 at 11:03
  • Exactly. However, I cannot just change it to EAGER, since that could cause performance issues. I need to have a hibernate session opened in the moment I perform .getFoo() in order for it to be fetched. The problem is: @Transactional didn't work at all – Pelicer Nov 03 '21 at 11:06
  • @Transactional does not work if you annotate a private method. https://stackoverflow.com/questions/4396284/does-spring-transactional-attribute-work-on-a-private-method – Rohit Nov 03 '21 at 12:28
  • @Pelicer try annotating @Transactional your `public BarWrapper createBar(...)` method, however the last line of this method seems completely irrelevant: `return new SettlementWrapper(createdSettlement);` – pleft Nov 03 '21 at 12:29
  • @pleft I edited the question with the correct code. Also tried your solution and nothing changed. – Pelicer Nov 03 '21 at 14:02
  • @Pelicer you have to make sure that you call `createBar` from outside `BarApplicationServices`, from another Spring bean, it that the case? – pleft Nov 03 '21 at 14:51

1 Answers1

0

Your @Transactional method is private which does not work. Make it public.

If this does not work, try the following link

Arthur Klezovich
  • 2,595
  • 1
  • 13
  • 17
  • Hi, Arthur. Changing the visibility to public did not help. I will look further into the link you've sent. – Pelicer Nov 03 '21 at 14:02