NPE In lazy initialization

Hi everyone, I have a very strange and random behaviour in my code.

I am using Hibernate 5.5.3.Final

This is the exception I have:

java.lang.NullPointerException
	at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:284)
	at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:162)
	at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:168)
	at lt.json.model.DeviceJson.<init>(DeviceJson.java:62)
	at jdk.internal.reflect.GeneratedConstructorAccessor133.newInstance(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at lt.cm.util.Reflection.getNewInstance(Reflection.java:106)
	at lt.cm.json.LTJsonParse.toJson(LTJsonParse.java:55)
	at lt.json.LTJsonModel.toJson(LTJsonModel.java:91)
	at lt.model.Device.toJson(Device.java:404)
	at lt.websocket.ModelObj.getJson(ModelObj.java:44)
	at lt.websocket.LTWSMessage.create(LTWSMessage.java:112)
	at lt.websocket.LTWSManager.lambda$publish$0(LTWSManager.java:74)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1603)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:408)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
	at lt.websocket.LTWSManager.publish(LTWSManager.java:54)
	at lt.websocket.LTWSWrapper.lambda$newEvent$0(LTWSWrapper.java:37)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at lt.websocket.LTWSWrapper.newEvent(LTWSWrapper.java:36)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)

This is the declaration of the class (only relevant part)

	
	@OneToMany(fetch = FetchType.LAZY)
	@JoinColumn(name = "deviceID")
	@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
	@LTEhcache(template = CacheTemplate.ONE_DAY, heap = @Heap(size = 10000), offHeap = @OffHeap(size = 30))
	private Set<DeviceData> devicedata = new HashSet<>();

This is the part of the code raising the exception:

			try {
				if (device.getDevicedata() != null && device.getDevicedata().size() != 0) {
					data = LTJsonModel.getEntities(DeviceDataJson.class, device.getDevicedata(),
							device.getDeployment());
				}
			} catch (LazyInitializationException e) {
				data = null;
			}  catch (Exception e) {
				System.out.println(">>>>>>>>>>>  ERROR GETTING DEVICE DATA !!!!!! device " + device.getName() + ", Exception " + e);
				e.printStackTrace();
				data = new HashSet<>();
			}

The exception occurs at line 62 where there is

if (device.getDevicedata() != null && device.getDevicedata().size() != 0) {

It seems to me that device.getDeviceData() is not null, but when getting size() (which returns int) it returns a NullPointerException.

The same issue was also with previous version of Hibernate

Any suggestion?
Thanks you in advance.

You seem to be using a parallel stream in LTWSManager, you can’t do that since the Hibernate session (or the objects associated with that session) are not thread-safe

Hi, thanks a lot for the quick answer.

You are right, I was using parallel stream. Now I switched to “stream” but I have almost the same issue.

Same row in code (even if now is 61, but because I deleted a line above).

java.lang.reflect.InvocationTargetException
	at jdk.internal.reflect.GeneratedConstructorAccessor243.newInstance(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at lt.cm.util.Reflection.getNewInstance(Reflection.java:106)
	at lt.cm.json.LTJsonParse.toJson(LTJsonParse.java:55)
	at lt.json.LTJsonModel.toJson(LTJsonModel.java:91)
	at lt.model.Device.toJson(Device.java:404)
	at lt.websocket.ModelObj.getJson(ModelObj.java:44)
	at lt.websocket.LTWSMessage.create(LTWSMessage.java:112)
	at lt.websocket.LTWSManager.lambda$publish$0(LTWSManager.java:74)
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1603)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
	at lt.websocket.LTWSManager.publish(LTWSManager.java:54)
	at lt.websocket.LTWSWrapper.lambda$newEvent$0(LTWSWrapper.java:37)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at lt.websocket.LTWSWrapper.newEvent(LTWSWrapper.java:36)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException
	at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:284)
	at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:162)
	at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:168)
	at lt.json.model.DeviceJson.<init>(DeviceJson.java:61)

How do you “publish” this Device from one thread to another? You have to close the session or detach the object from the session that loaded the instance before you publish it to this other thread. Otherwise concurrency issues can occur.

Thanks @beikov I will close the session after catching the PostInsert/Update and before sending the message through the websocket.

Thanks @belkov. It works, I call session.close() before sending message to the websocket. It works also with parallelStream