How to fix LazyInitializationException with GWT?
-
23-01-2021 - |
Question
I have:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
This is my service:
@Service("empService")
public class EmpServiceImpl extends RemoteServiceServlet implements EmpService {
@Autowired
EmpHome empHome;
@Override
@Transactional
public Emp findById(short id) {
return empHome.findById(id);
}
Im trying to use my service in gwt:
EmpServiceAsync empServiceAsync = GWT.create(EmpService.class);
AsyncCallback<Emp> callback = new AsyncCallback<Emp>() {
@Override
public void onFailure(Throwable caught) {
Info.display("Failure", "что-то пошло не так");
}
@Override
public void onSuccess(Emp result) {
Info.display("Succes", result.getEname());
}
};
empServiceAsync.findById((short) 7844, callback);
Solution
I would highly discourage using Hibernate mapped object Emp
in GWT client side directly.
Your Hibernate session will only be available inside findById
as it is marked @Transactional
, however, GWT will need to traverse the entire Emp
object to serialize it for client. That will obviously happen outside findById
hence you will get LazyInitializationException
if Emp
contains any properties that require lazy loading (for example, association lists).
The solution is to use intermediate data transfer object, for example EmpDTO
and convert Emp
to EmpDTO
inside your service transactional block.
OTHER TIPS
I actually got around this issue by creating a CustomFieldSerializer for my domain objects.
Take a look at this file: https://github.com/dartmanx/mapmaker/blob/0.5.2/src/main/java/org/jason/mapmaker/shared/model/FeaturesMetadata_CustomFieldSerializer.java
I've commented out the relevant lines because I ended up not needing it, but here's the code:
public static void serialize(SerializationStreamWriter writer, FeaturesMetadata instance) throws SerializationException {
writer.writeInt(instance.getId());
writer.writeString(instance.getState());
writer.writeString(instance.getStateAbbr());
writer.writeString(instance.getUsgsDate());
writer.writeString(instance.getFilename());
writer.writeString(instance.getStateGeoId());
writer.writeString(instance.getCurrentStatus());
if (instance.getFeatureList().size() == 0) {
writer.writeObject(new ArrayList<Feature>());
} else {
writer.writeObject(new ArrayList<Feature>(instance.getFeatureList()));
}
}
The final line takes the takes an argument of the instance object's getFeatureList(), which is actually a Hibernate PersistentBag, and writes out an actual ArrayList with the contents of said PersistentBag.