[
https://issues.apache.org/jira/browse/IO-895?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Jeroen Peschier updated IO-895:
-------------------------------
Description:
When migrating a project to Java 25 with modularization, I ran into an issue
where Commons IO 2.22.0 throws an Error when invoking
BufferedFileChannelInputStream::close with Commons IO JAR on the module path
while having "requires org.apache.commons.io;" in the module-info:
{noformat}
Exception in thread "main" java.lang.ExceptionInInitializerError
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.cleanDirectBuffer(BufferedFileChannelInputStream.java:230)
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.clean(BufferedFileChannelInputStream.java:217)
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.close(BufferedFileChannelInputStream.java:240)
... snip private code
Caused by: java.lang.IllegalStateException: Failed to initialize a Cleaner.
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:102)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.<clinit>(ByteBufferCleaner.java:79)
... 6 more
Caused by: java.lang.ClassNotFoundException: sun.misc.Cleaner
at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at java.base/java.lang.Class.forName(Class.java:458)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:47)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:41)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:97)
... 7 more{noformat}
Code that reproduces the above stacktrace:
{code:java}
var input = new BufferedFileChannelInputStream.Builder()
.setPath("some-existing-file")
.get();
input.close();{code}
I noticed that the current HEAD
([f9de7a4|https://github.com/apache/commons-io/commit/f9de7a458b9ff70151994bbbacae3088047b8338])
has an extra setter "setClean" for the builder that aims to skip the cleanup:
{code:java}
var input = new BufferedFileChannelInputStream.Builder()
.setPath("some-existing-file")
.setClean(false)
.get();
input.close();{code}
However running with a snapshot of
([f9de7a4|https://github.com/apache/commons-io/commit/f9de7a458b9ff70151994bbbacae3088047b8338])
and using "setClean(false)" I am seeing the same exception:
{noformat}
Exception in thread "main" java.lang.ExceptionInInitializerError
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.cleanBuffer(BufferedFileChannelInputStream.java:252)
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.close(BufferedFileChannelInputStream.java:261)
... snip private code
Caused by: java.lang.IllegalStateException: Failed to initialize a direct
ByteBuffer Cleaner.
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:116)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.<clinit>(ByteBufferCleaner.java:82)
... 3 more
Caused by: java.lang.ClassNotFoundException: sun.misc.Cleaner
at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at java.base/java.lang.Class.forName(Class.java:458)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:50)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:44)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:111)
... 4 more{noformat}
So both 2.22.0 and 2.23.0-SNAPSHOT fails on construction of
ByteBufferCleaner.Java8Cleaner when executed from the module path. Note that
the stacktrace is misleading: it appears to fail on the Java8Cleaner (it does),
but it actually also attempts to create a Java9Cleaner and when that fails it
prints the stacktrace of the Java8Cleaner failure hiding that the creation of
the Java9Cleaner also failed.
The Common IO unit tests seem to run on the classpath so they don't highlight
this issue, although there are warnings when running with the classpath as well:
{noformat}
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::invokeCleaner has been called by
org.apache.commons.io.input.ByteBufferCleaner$Java9Cleaner
(file:/REDACTED/.m2/repository/commons-io/commons-io/2.22.0/commons-io-2.22.0.jar)
WARNING: Please consider reporting this to the maintainers of class
org.apache.commons.io.input.ByteBufferCleaner$Java9Cleaner WARNING:
sun.misc.Unsafe::invokeCleaner will be removed in a future release{noformat}
An obvious workaround is to put the Commons IO jar on the classpath. Beside
negating the benefits of Java modules, this is not an (easy) option for
application distributions that no longer have a classpath.
Ideas on how to fix this:
- Maybe ByteBufferCleaner needs a Java8 and Java9+ version in a multi-release
JAR? That way the ExceptionInInitializerError could be prevented altogether.
- Since Java 9, the replacement for sun.misc.Cleaner is
jdk.internal.ref.Cleaner. Still internal to the JDK though.
was:
When migrating a project to Java 25 with modularization, I ran into an issue
where Commons IO 2.22.0 throws an Error when invoking
BufferedFileChannelInputStream::close with Commons IO JAR on the module path
while having "requires org.apache.commons.io;" in the module-info:
{noformat}
Exception in thread "main" java.lang.ExceptionInInitializerError
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.cleanDirectBuffer(BufferedFileChannelInputStream.java:230)
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.clean(BufferedFileChannelInputStream.java:217)
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.close(BufferedFileChannelInputStream.java:240)
... snip private code
Caused by: java.lang.IllegalStateException: Failed to initialize a Cleaner.
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:102)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.<clinit>(ByteBufferCleaner.java:79)
... 6 more
Caused by: java.lang.ClassNotFoundException: sun.misc.Cleaner
at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at java.base/java.lang.Class.forName(Class.java:458)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:47)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:41)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:97)
... 7 more{noformat}
Code that reproduces the above stacktrace:
{code:java}
var input = new BufferedFileChannelInputStream.Builder()
.setPath("some-existing-file")
.get();
input.close();{code}
I noticed that the current HEAD
([f9de7a4|https://github.com/apache/commons-io/commit/f9de7a458b9ff70151994bbbacae3088047b8338])
has an extra setter "setClean" for the builder that aims to skip the cleanup:
{code:java}
var input = new BufferedFileChannelInputStream.Builder()
.setPath("some-existing-file")
.setClean(false)
.get();
input.close();{code}
However running with a snapshot of
([f9de7a4|https://github.com/apache/commons-io/commit/f9de7a458b9ff70151994bbbacae3088047b8338])
and using "setClean(false)" I am seeing the same exception:
{noformat}
Exception in thread "main" java.lang.ExceptionInInitializerError
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.cleanBuffer(BufferedFileChannelInputStream.java:252)
at
[email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.close(BufferedFileChannelInputStream.java:261)
... snip private code
Caused by: java.lang.IllegalStateException: Failed to initialize a direct
ByteBuffer Cleaner.
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:116)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.<clinit>(ByteBufferCleaner.java:82)
... 3 more
Caused by: java.lang.ClassNotFoundException: sun.misc.Cleaner
at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at java.base/java.lang.Class.forName(Class.java:458)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:50)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:44)
at
[email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:111)
... 4 more{noformat}
So both 2.22.0 and 2.23.0-SNAPSHOT fails on construction of
ByteBufferCleaner.Java8Cleaner when executed from the module path. Note that
the stacktrace is misleading: it appears to fail on the Java8Cleaner (it does),
but it actually also attempts to create a Java9Cleaner and when that fails it
prints the stacktrace ofthe Java8Cleaner failure hiding that the creation of
the Java9Cleaner also failed.
The Common IO unit tests seem to run on the classpath so they don't highlight
this issue, although there are warnings when running with the classpath as well:
{noformat}
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::invokeCleaner has been called by
org.apache.commons.io.input.ByteBufferCleaner$Java9Cleaner
(file:/REDACTED/.m2/repository/commons-io/commons-io/2.22.0/commons-io-2.22.0.jar)
WARNING: Please consider reporting this to the maintainers of class
org.apache.commons.io.input.ByteBufferCleaner$Java9Cleaner WARNING:
sun.misc.Unsafe::invokeCleaner will be removed in a future release{noformat}
An obvious workaround is to put the Commons IO jar on the classpath. Beside
negating the benefits of Java modules, this is not an (easy) option for
application distributions that no longer have a classpath.
Ideas on how to fix this:
- Maybe ByteBufferCleaner needs a Java8 and Java9+ version in a multi-release
JAR? That way the ExceptionInInitializerError could be prevented altogether.
- Since Java 9, the replacement for sun.misc.Cleaner is
jdk.internal.ref.Cleaner. Still internal to the JDK though.
> ExceptionInInitializerError when using Commons IO on the module path
> --------------------------------------------------------------------
>
> Key: IO-895
> URL: https://issues.apache.org/jira/browse/IO-895
> Project: Commons IO
> Issue Type: Bug
> Affects Versions: 2.22.0
> Environment: Java 25, Linux
> Reporter: Jeroen Peschier
> Priority: Blocker
>
> When migrating a project to Java 25 with modularization, I ran into an issue
> where Commons IO 2.22.0 throws an Error when invoking
> BufferedFileChannelInputStream::close with Commons IO JAR on the module path
> while having "requires org.apache.commons.io;" in the module-info:
> {noformat}
> Exception in thread "main" java.lang.ExceptionInInitializerError
> at
> [email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.cleanDirectBuffer(BufferedFileChannelInputStream.java:230)
> at
> [email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.clean(BufferedFileChannelInputStream.java:217)
> at
> [email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.close(BufferedFileChannelInputStream.java:240)
> ... snip private code
> Caused by: java.lang.IllegalStateException: Failed to initialize a Cleaner.
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:102)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner.<clinit>(ByteBufferCleaner.java:79)
> ... 6 more
> Caused by: java.lang.ClassNotFoundException: sun.misc.Cleaner
> at
> java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
> at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
> at java.base/java.lang.Class.forName0(Native Method)
> at java.base/java.lang.Class.forName(Class.java:467)
> at java.base/java.lang.Class.forName(Class.java:458)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:47)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:41)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:97)
> ... 7 more{noformat}
> Code that reproduces the above stacktrace:
> {code:java}
> var input = new BufferedFileChannelInputStream.Builder()
> .setPath("some-existing-file")
> .get();
> input.close();{code}
> I noticed that the current HEAD
> ([f9de7a4|https://github.com/apache/commons-io/commit/f9de7a458b9ff70151994bbbacae3088047b8338])
> has an extra setter "setClean" for the builder that aims to skip the
> cleanup:
> {code:java}
> var input = new BufferedFileChannelInputStream.Builder()
> .setPath("some-existing-file")
> .setClean(false)
> .get();
> input.close();{code}
> However running with a snapshot of
> ([f9de7a4|https://github.com/apache/commons-io/commit/f9de7a458b9ff70151994bbbacae3088047b8338])
> and using "setClean(false)" I am seeing the same exception:
> {noformat}
> Exception in thread "main" java.lang.ExceptionInInitializerError
> at
> [email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.cleanBuffer(BufferedFileChannelInputStream.java:252)
> at
> [email protected]/org.apache.commons.io.input.BufferedFileChannelInputStream.close(BufferedFileChannelInputStream.java:261)
> ... snip private code
> Caused by: java.lang.IllegalStateException: Failed to initialize a direct
> ByteBuffer Cleaner.
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:116)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner.<clinit>(ByteBufferCleaner.java:82)
> ... 3 more
> Caused by: java.lang.ClassNotFoundException: sun.misc.Cleaner
> at
> java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
> at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
> at java.base/java.lang.Class.forName0(Native Method)
> at java.base/java.lang.Class.forName(Class.java:467)
> at java.base/java.lang.Class.forName(Class.java:458)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:50)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner$Java8Cleaner.<init>(ByteBufferCleaner.java:44)
> at
> [email protected]/org.apache.commons.io.input.ByteBufferCleaner.getCleaner(ByteBufferCleaner.java:111)
> ... 4 more{noformat}
> So both 2.22.0 and 2.23.0-SNAPSHOT fails on construction of
> ByteBufferCleaner.Java8Cleaner when executed from the module path. Note that
> the stacktrace is misleading: it appears to fail on the Java8Cleaner (it
> does), but it actually also attempts to create a Java9Cleaner and when that
> fails it prints the stacktrace of the Java8Cleaner failure hiding that the
> creation of the Java9Cleaner also failed.
> The Common IO unit tests seem to run on the classpath so they don't highlight
> this issue, although there are warnings when running with the classpath as
> well:
> {noformat}
> WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
> WARNING: sun.misc.Unsafe::invokeCleaner has been called by
> org.apache.commons.io.input.ByteBufferCleaner$Java9Cleaner
> (file:/REDACTED/.m2/repository/commons-io/commons-io/2.22.0/commons-io-2.22.0.jar)
> WARNING: Please consider reporting this to the maintainers of class
> org.apache.commons.io.input.ByteBufferCleaner$Java9Cleaner WARNING:
> sun.misc.Unsafe::invokeCleaner will be removed in a future release{noformat}
> An obvious workaround is to put the Commons IO jar on the classpath. Beside
> negating the benefits of Java modules, this is not an (easy) option for
> application distributions that no longer have a classpath.
> Ideas on how to fix this:
> - Maybe ByteBufferCleaner needs a Java8 and Java9+ version in a
> multi-release JAR? That way the ExceptionInInitializerError could be
> prevented altogether.
> - Since Java 9, the replacement for sun.misc.Cleaner is
> jdk.internal.ref.Cleaner. Still internal to the JDK though.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)