I'm trying to create an encrypted 7z archive. Everything works fine with the build from me IDE (eclipse). However, when I build a jar, with sevenzipjbinding incluced, I get the following error:
FATAL ERROR: Class net/sf/sevenzipjbinding/IInStream not found
Crash jvm to get a stack trace
I'm using a RandomAccessFileInStream for reading the files from the filesystem and put them in the archive.
When I run the jar with -verbose, I see that it is sucessfully loading other classes from the same jar: [Loaded net.sf.sevenzipjbinding.IOutItemBase from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.impl.OutItemFactory from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.IOutItem7z from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.IOutItemZip from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.IOutItemBZip2 from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.IOutItemGZip from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.IOutItemTar from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.IOutItemAllFormats from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.impl.OutItem from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.impl.OutItemFactory$1 from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/] [Loaded net.sf.sevenzipjbinding.impl.RandomAccessFileInStream from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
From my own code, I can load the IInStream.class sucessfully.
So I wonder what is happening, and how I can investigate this furter?
Kind Regards,
Silas
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The difference in execution environments is that from eclipse, the complete list of jar-dependencies is in the classpath, whereas when executing the bundled jar, it only has that in the classpath. How can I make it find the IInStream in that case?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
you are right. This looks like classloader issue to me. From JNI specification:
Since Java 2 SDK release 1.2, when FindClass is called through the Invocation Interface, there is no current native method or its associated class loader. In that case, the result of ClassLoader.getSystemClassLoader is used. This is the class loader the virtual machine creates for applications, and is able to locate classes listed in the java.class.path property.
So, if you can't load a class through "ClassLoader.getSystemClassLoader()" classloader you can't load it from native close. At least, you can't do it using FindClass().
I suppose, I could build a more sophisticated initialization routine awared of advanced classloading.
Is this workaround ok for you?
Kind regards,
Boris
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for your response.
This workaround is kind of ok, but would it be possible to give a more
sensible error or exception?
Currently, this issue crashes the JVM, and I saw in your source code that
you do that to get a stacktrace from the jvm? However, here it only crashes
with that text "Crash jvm to get a stack trace" and then the process exits.
Would be nice to have an exception, or initialization check, or callback to
handle this properly from the java side?
you are right. This looks like classloader issue to me. From JNI
specification:
Since Java 2 SDK release 1.2, when FindClass is called through the
Invocation Interface, there is no current native method or its associated
class loader. In that case, the result of ClassLoader.getSystemClassLoader
is used. This is the class loader the virtual machine creates for
applications, and is able to locate classes listed in the java.class.path
property.
So, if you can't load a class through "ClassLoader.getSystemClassLoader()"
classloader you can't load it from native close. At least, you can't do it
using FindClass().
I suppose, I could build a more sophisticated initialization routine
awared of advanced classloading.
you are right. A better error message is needed here. Although there are also other reasons possible.
If no classes can be found, not crashing JVM and returning control to the java code can be very tricky. I could add an simple class loading test in the initialization routine, where detecting such errors is easier.
Any idea how I could test it in a simple way and without using spring?
(I could implement my own classloader, but may be you are aware of some existing simple implementations)
Thank you!
Kind regards,
Boris
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I think you can just use an URLClassloader (to load the sevenzip jars), set
it as the context classloader from the current thread and then let it load
SevenZip things from another class afterwards?
Just make sure your classes are not on the system classloader classpath?
That should trigger the crash without spring? If you want, I can try to
come up with something as well.
A check in the init routines would definitely be a good start to prevent
the jvm crashing afterwards.
Can the 'no class found' maybe trigger an exception instead?
-> Let the user set (or initialize from the initialization routines) a
custom classloader.
Getting the classloader from the current (Java) thread would not be
possible I suppose.
This is of course a lot of work from your side. Strange thing is that this
is not supported by JNI out of the box ;-)
you are right. A better error message is needed here. Although there are
also other reasons possible.
If no classes can be found, not crashing JVM and returning control to the
java code can be very tricky. I could add an simple class loading test in
the initialization routine, where detecting such errors is easier.
Any idea how I could test it in a simple way and without using spring?
(I could implement my own classloader, but may be you are aware of some
existing simple implementations)
Hello,
I'm trying to create an encrypted 7z archive. Everything works fine with the build from me IDE (eclipse). However, when I build a jar, with sevenzipjbinding incluced, I get the following error:
FATAL ERROR: Class net/sf/sevenzipjbinding/IInStream not found
Crash jvm to get a stack trace
I'm using a RandomAccessFileInStream for reading the files from the filesystem and put them in the archive.
When I run the jar with -verbose, I see that it is sucessfully loading other classes from the same jar:
[Loaded net.sf.sevenzipjbinding.IOutItemBase from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.impl.OutItemFactory from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.IOutItem7z from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.IOutItemZip from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.IOutItemBZip2 from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.IOutItemGZip from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.IOutItemTar from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.IOutItemAllFormats from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.impl.OutItem from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.impl.OutItemFactory$1 from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
[Loaded net.sf.sevenzipjbinding.impl.RandomAccessFileInStream from jar:file:/D:/Devel/bsaf/bsaf-process/build/libs/process-0.0.4-SNAPSHOT.jar!/BOOT-INF/lib/sevenzipjbinding-16.02-2.01.jar!/]
From my own code, I can load the IInStream.class sucessfully.
So I wonder what is happening, and how I can investigate this furter?
Kind Regards,
Silas
The difference in execution environments is that from eclipse, the complete list of jar-dependencies is in the classpath, whereas when executing the bundled jar, it only has that in the classpath. How can I make it find the IInStream in that case?
Hello Silas,
how are you creating your JAR file?
This is a fat jar, right?
Kind regards,
Boris
Hello,
It's a spring boot jar, built with gradle.
I managed to work around it by specifying the sevenzip jars in the classpath
java -cp
process-0.0.4-SNAPSHOT.jar;sevenzipjbinding-16.02-2.01.jar;sevenzipjbinding-all-platforms-16.02-2.01.jar
-Dloader.main=be.fed.minfin.bsaf.ProcessApplication
org.springframework.boot.loader.PropertiesLauncher
Is it possible that the classes loaded from your cpp binding code are not
using the same classloader as the java side?
If you need further info, or if I need to test some things, I'm happy to
help.
Kind regards,
Silas
Op wo 22 apr. 2020 om 14:39 schreef Boris Brodski boris_brodski@users.sourceforge.net:
Hello,
you are right. This looks like classloader issue to me. From JNI specification:
(https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#FindClass)
So, if you can't load a class through "ClassLoader.getSystemClassLoader()" classloader you can't load it from native close. At least, you can't do it using FindClass().
I suppose, I could build a more sophisticated initialization routine awared of advanced classloading.
Is this workaround ok for you?
Kind regards,
Boris
Hello Boris,
Thanks for your response.
This workaround is kind of ok, but would it be possible to give a more
sensible error or exception?
Currently, this issue crashes the JVM, and I saw in your source code that
you do that to get a stacktrace from the jvm? However, here it only crashes
with that text "Crash jvm to get a stack trace" and then the process exits.
Would be nice to have an exception, or initialization check, or callback to
handle this properly from the java side?
Kind regards,
Silas
Op do 23 apr. 2020 om 09:41 schreef Boris Brodski boris_brodski@users.sourceforge.net:
Hello,
you are right. A better error message is needed here. Although there are also other reasons possible.
If no classes can be found, not crashing JVM and returning control to the java code can be very tricky. I could add an simple class loading test in the initialization routine, where detecting such errors is easier.
Any idea how I could test it in a simple way and without using spring?
(I could implement my own classloader, but may be you are aware of some existing simple implementations)
Thank you!
Kind regards,
Boris
Hello Boris,
I think you can just use an URLClassloader (to load the sevenzip jars), set
it as the context classloader from the current thread and then let it load
SevenZip things from another class afterwards?
Just make sure your classes are not on the system classloader classpath?
That should trigger the crash without spring? If you want, I can try to
come up with something as well.
A check in the init routines would definitely be a good start to prevent
the jvm crashing afterwards.
Can the 'no class found' maybe trigger an exception instead?
The better solution would be something like this:
https://stackoverflow.com/questions/13263340/findclass-from-any-thread-in-android-jni
-> Let the user set (or initialize from the initialization routines) a
custom classloader.
Getting the classloader from the current (Java) thread would not be
possible I suppose.
This is of course a lot of work from your side. Strange thing is that this
is not supported by JNI out of the box ;-)
Kind regards,
Silas
Op ma 27 apr. 2020 om 10:07 schreef Boris Brodski boris_brodski@users.sourceforge.net: