Java 11 upgrade from 8 parallel streams throws ClassNotFoundException

Viewed 1035

I upgraded my spring boot application from Java 8 and tomcat 8 to java 11 and tomcat 9. Everything seems to work fine except the part that I use parallel streams on lists.

list.addAll(items
                .parallelStream()
                .filter(item -> !SomeFilter.isOk(item.getId()))
                .map(logic::getSubItem)
                .collect(Collectors.toList()));

The previous part of code used to work fine with Java 8 and Tomcat 8 but after Java 9 changes on how the classes are loaded with Fork/Join common pool threads return the system class loader as their thread context class loader.

I know that under the hood parallel streams use ForkJoinPool and I created a custom bean class but still, it is not used by the app. Most probably due to the fact that maybe they are created before this bean.

@Bean
public ForkJoinPool myForkJoinPool() {
    return new ForkJoinPool(threadPoolSize, makeFactory("APP"), null, false);
}

private ForkJoinPool.ForkJoinWorkerThreadFactory makeFactory(String prefix) {
    return pool -> {
        final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
        worker.setName(prefix + worker.getPoolIndex());
        worker.setContextClassLoader(Application.class.getClassLoader());
        return worker;
    };
}

Lastly, I also tried to wrap it around an instance of my ForkJoinPool but it is done asynchronously and I do not want to. I also do not want to use the submit and get because that means that I have to wrap up all the parallel stream that I have on the application with try/catch and the code will be nasty to read.

forkJoinPool.execute(() -> 
  list.addAll(items
                .parallelStream()
                .filter(item -> !SomeFilter.isOk(item.getId()))
                .map(logic::getSubItem)
                .collect(Collectors.toList())));

Ideally, I would like all my parallel streams that are used in the application to use the class loader from the application and not the system one.

Any idea?

1 Answers

If using a third-party is an option, you could use the Parallel Collectors library:

list.addAll(items
            .stream()
            .filter(item -> !SomeFilter.isOk(item.getId()))
            .collect(parallel(logic::getSubItem, Collectors.toList(), forkJoinPool)
            .join());
Related