We have a java applet which is working OK in most client environments, primarily Windows 7, but recently we have been asked to support Ubuntu clients as well.
The problem is that when the applet is fired up on the Ubuntu client (running Firefox and the natively installed "IcedTEA" Java VM 1.7.0_75) we get this exception:
java.lang.VerifyError: Cannot inherit from final class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at net.sourceforge.jnlp.runtime.JNLPClassLoader.access$1701(JNLPClassLoader.java:103)
at net.sourceforge.jnlp.runtime.JNLPClassLoader$5.run(JNLPClassLoader.java:1636)
at net.sourceforge.jnlp.runtime.JNLPClassLoader$5.run(JNLPClassLoader.java:1634)
at java.security.AccessController.doPrivileged(Native Method)
at net.sourceforge.jnlp.runtime.JNLPClassLoader.findClass(JNLPClassLoader.java:1633)
at net.sourceforge.jnlp.runtime.JNLPClassLoader.loadClassExt(JNLPClassLoader.java:1670)
at net.sourceforge.jnlp.runtime.JNLPClassLoader.loadClass(JNLPClassLoader.java:1471)
at com.renosci.Nlx.chartapplet.NlxBrowserJsEngine.<init>(NlxBrowserJsEngine.java:46)
at com.renosci.Nlx.chartapplet.UtilityApplet.init(UtilityApplet.java:87)
at sun.applet.AppletPanel.run(AppletPanel.java:436)
at java.lang.Thread.run(Thread.java:745)
We don't get this exception under Windows (admittedly, different JVM builds and of on Windows we are using the Oracle supplied VMs instead of this IcedTea version).
I understand the meaning of the exception - and have a quick google search revealed multiple SO questions that mainly boiled down to the the suggestion that the build path is not the same as the class path, such that at compile time a base class was not final, but at runtime the classloader is finding it final.
However, I don't understand how that can be the case:
The class which is throwing the error is extending from an abstract base class that is part of our codebase, and according to our version control system has never been final
There is no possibility of there being any other versions of this class on the target machine that I am testing with - in fact I created a fresh VM for this test and got the problem straight away
I am assuming that the class it is complaining about NlxBrowserJsEngine, running immediately before the call to loadClass - is that correct? And that the base class of this class is the one which it thinks is final?
For completeness - here is the declaration of the class (which is the line 46 that the exception complains about) and the declaration of the only two fields it has:
public class NlxBrowserJsEngine extends NlxJsEngine { /* Line 46 */
private JSObject windowObj;
static private Object evalLock = new Object();
JSObject is netscape.javascript.JSObject, provided by the Java browser plugin.
Here is the declaration of the base class:
public abstract class NlxJsEngine {
Thanks for any insights!
I eventually tracked down the cause of this.
As indicated by @immibis's comments, the exception was during class initialization, rather during construction of an instance.
One of the methods of class NlxBrowserJsEngine calls a static method of another class - and this class extends from netscape.javascript.JSObject.
In the oracle implementation this JSObject class is not declared final, so extending it works fine.
In the IcedTea implementation, JSObject is final. Therefore when loading this class in the IcedTea JVM Plugin, an exception is thrown.
I'm not sure if this incompatibility was an oversight on behalf of the IcedTea implementors, or perhaps done deliberately (due to security perhaps?). Either way it caused big problems for us.
Through extensive refactoring it would have been possible to overcome this, however in our case this was not considered worthwhile so we have decided to require our users to install the Oracle JVM.