0

I have two Java classes, Measure and Trade, Trade joins Measure as a property:

class Measure{
  @OneToOne(fetch = FetchType.LAZY)
  Private Trade trade;
}

Then I have a stored proc which, after running and working with Hibernate, somehow mysteriously (meaning I failed to follow the code routes) creates a collection of Measure objects (trades are supposedly enriched when they tag along, as Measures' properties).

Now it comes to this point that I found that trade of Measure instance is a HiberateProxy. According to what I read online, when the Fetch type is LAZY, Hibernate create a proxy for trade, but I thought it'd somehow be replaced by the Trade objects later, it's obviously not happening, and they remained as HiberateProxy.

So my question is, why the Trade failed to transition it from a Hibernate Proxy to a real object? And, if I remove the (fetch = FetchType.LAZY) part from the annotation above, can it be a workaround? I am reluctant to do so, though, because the above code is actually in Measure's parent class, it might have ripple effect on other code. (I moved the Trade property to Measure for simpler illustration).

J.E.Y
  • 1,173
  • 2
  • 15
  • 37

1 Answers1

0

You chose to load your Trade objects lazily.

In order to be able to access the Trade after you've retrieved the Measure you need to be in a transactional context (you need an open session)

When you call:

measureRepository.findAll();

internally a new session is created, the object is retrieved and as soon as the findAll method returns the session is closed.

What you should do is make sure you have an open session whenever you access the lazy collection in your Measure object.

The simplest way is to have you method annotated with @Transactional and make sure you call that method from another service because of the way spring AOP proxies are handled.

public class Measure {

    @OneToOne(fetch = FetchType.LAZY)
    Private Trade trade;

    public Trade getTrade() {
        return this.trade;
    }
}

@Service
public MeasureService {

    final MeasureRepository measureRepository;

    public MeasureService(MeasureRepository measureRepository) {
        this.measureRepository = measureRepository;
    }    

    @Transactional
    public List<Trade> getTrades(String... args) {
        return measureRepository.findAll().stream()
                .map(m -> m.getTrade())
                .collect(Collectors.toList);
    }   
}

And if Trade is also a proxy whenever you access it you should make sure you have an open session.