IllegalAccessError:class <classname> cannot access its superinterface <interfacename>

Jayan picture Jayan · Sep 16, 2011 · Viewed 8.7k times · Source

I have class Assembly implementing IAssembly.

I see following error when starting the application

Caused by: java.lang.IllegalAccessError: class <Assembly > cannot access its superinterface <IAssembly>
        at java.lang.ClassLoader.defineClass1(Native Method)

Assembly code

class package.Assembly implements IAssembly {

}

IAssembly

interface IAssembly { //note -this is not public, so uses default protected

}

Assembly and IAssembly exists in two different jars. Both jars loaded by different classloaders. The Assembly class is loaded in child classloader, IAssembly is parent. Class loaders are using chaining.

In normal cases, this works. The error occurs when I run my application after instrumenting jars using cobertura. With out instrumentation all works fine. Could cobertura instrumentation cause such error? Or This is an error anyway waiting to be detected, but with cobertura the error is quickly exposed.

By making the interface 'public' the error goes away.

Answer

Byron Hawkins picture Byron Hawkins · Oct 8, 2011

It looks to me like package-protection fails with instrumentation and multiple classloaders, even if the loaders are chained. This javadoc on java.lang.instrument.Instrumentation isn't directly related to your scenario, but it does describe a similar scenario:

The agent should take care to ensure that the JAR does not contain any classes or resources other than those to be defined by the bootstrap class loader for the purpose of instrumentation. Failure to observe this warning could result in unexpected behaviour that is difficult to diagnose. For example, suppose there is a loader L, and L's parent for delegation is the bootstrap class loader. Furthermore, a method in class C, a class defined by L, makes reference to a non-public accessor class C$1. If the JAR file contains a class C$1 then the delegation to the bootstrap class loader will cause C$1 to be defined by the bootstrap class loader. In this example an IllegalAccessError will be thrown that may cause the application to fail. One approach to avoiding these types of issues, is to use a unique package name for the instrumentation classes.

The Java Virtual Machine Specification specifies that a subsequent attempt to resolve a symbolic reference that the Java virtual machine has previously unsuccessfully attempted to resolve always fails with the same error that was thrown as a result of the initial resolution attempt. Consequently, if the JAR file contains an entry that corresponds to a class for which the Java virtual machine has unsuccessfully attempted to resolve a reference, then subsequent attempts to resolve that reference will fail with the same error as the initial attempt.

Maybe check which loader is finding your instrumented classes, and see if there is a way to get both Assembly and IAssembly to load from that same classloader.