У меня есть список из примерно 40 000 объектов в среднем (максимально до 80 КБ), завернутый весной Page
Page<People> people = //loaded data using PeopleRepository of "People" entity
Затем создается карта для экспорта записей в файл Excel
List<Map<String, String>> excelData = Streams.batches(people, 500)
.parallel()
.map(PageImple::new) //Converting each chunk in a page
.map(this::buildDTO) // Creating DTO objects from people entities
.map(Slice::getContent)
.flatMap(Collection::stream)
.map(this::buildExportData)
.collect( <----
Collectors.toList()
);
Над фрагментом кода время от времени выкидывается следующий NPE. Это выброшено из основной библиотеки Java. Кто-нибудь может дать намек, что может быть причиной проблемы? Это связано с параллельным потоком? Нужен ли какой-либо другой механизм для параллельной потоковой передачи?
Исключение
java.lang.NullPointerException: null
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(DelegatingAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ReduceOps$ReduceOp.evaluateParallel(ReduceOps.java:714)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
В другом, но похожем сценарии я также наблюдал следующее исключение:
org.hiberate.AssertionFailure: bug adding collection twice
at org.hibernate.engine.internal.StatefulPersistenceContext.addCollection(StatefulPersistenceContext.java:851)
at org.hibernate.engine.internal.StatefulPersistenceContext.addInitializedConnection(StatefulPersistenceContext.java:890)
// -- Will add remaiing part of the stack trace if required.
Edit 2 (последние новости!) Мы обнаружили такое же поведение в двух местах. У них обоих есть одна общая линия, загружающая отношения от использования Ленивой выборки. Подтверждение сущности выглядит следующим образом:
@ManyToMany(fetch=Fetch.Lazy)
@JoinTable(.. ... ...)
private Set<Classification> classifications
Что-то идет не так, если используется параллельный поток с отложенной выборкой?
Редактировать 1 После еще одного расследования, если я посмотрюна java.util.concurrent.ForkJointTask line#291
код выглядит следующим образом:
try {
completed = exec();
} catch(Throwable rex) {
return setExceptionalCompletion(rex);
}
Похоже, это означает, что он не смог выполнить один из блоков карты. Поэтому, как @Eugene спросил в комментарии, является ли это единственной трассировкой стека, ответ - нет. Существует раздел «Вызвано» . Вот оно,
Caused By: java.lang.NullPointerException: null
at org.hibernate.engine.loading.internal.LoadContexts.cleanup(LoadContexts.java:81)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:202)
at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:249)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:212)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:123)
at org.hibernate.loader.plan.exec.process.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)
at org.hibernate.loader.plan.exec.process.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
...
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2004)
...
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)