14

java.lang.IllegalAccessError: tried to access field ConcreteEntity.instance from class Entity

Ok so here is the deal. I am trying to access ConcreteEntity.instance which is a field with the access type default that exists inside the default ClassLoader and the Entity.getInstance is a method that exist in a child ClassLoader.

Now keep in mind they're both in the same package, however an IllegalAccessError is being thrown. Is there a solution to this problem that doesn't involve me actually loading the Entity class inside the same ClassLoader as ConcreteEntity?

0 new #14 <Entity>
 3 dup
 4 aload_0
 5 invokevirtual #18 <Adapter.getInstance>
 8 checkcast #20 <sl>
11 getfield #24 <sl.d>
14 invokespecial #25 <Entity.<init>>
17 areturn

The bytecode retrieved via jclasslib at were the exception is generated "After being compiled".

Thank you Gamb for cleaning up the post.

Justin
  • 436
  • 1
  • 3
  • 9

2 Answers2

31

See my answer to a similar question, except in your case it is clear that you are dealing with multiple classloaders:

The jvm considers classes loaded from different classloaders to be in different "runtime packages", even if they have the same package name. Quoting from the jvm spceification, section 5.3:

At run time, a class or interface is determined not by its name alone, but by a pair: its fully qualified name and its defining class loader. Each such class or interface belongs to a single runtime package. The runtime package of a class or interface is determined by the package name and defining class loader of the class or interface.

And in section 5.4.4:

A field or method R is accessible to a class or interface D if and only if any of the following conditions is true:

...

R is either protected or package private (that is, neither public nor protected nor private), and is declared by a class in the same runtime package as D.

Community
  • 1
  • 1
Jörn Horstmann
  • 33,639
  • 11
  • 75
  • 118
  • Very interesting indeed. So know of any work around off the top of your head? If not I either A) need to change my implementation "Sadly bring it in to a single classloader" or B) do some more research in JVMSpec classloading – Justin Dec 28 '12 at 14:27
  • You could make the field public, if `Entity` was a subclass of `ConcreteEntity` then protected should also work. I don't think there is a workaround since the concept of runtime packages is there for security reasons. – Jörn Horstmann Dec 28 '12 at 14:37
  • I appreciate your answer. It shed light on what is happening. It has been marked as accepted. – Justin Dec 28 '12 at 14:40
  • 1
    @JörnHorstmann Much appreciated, got this today. I have classes created on runtime that sub-class (and make concrete) abstract classes. Accessing the package visible fields of the abstract class by the generated concrete class causes an IllegalAccessError. Changing the field visibility to protected resolves the issue (so, your answer is indeed what is happening). For reference, Geronimo 2.4, Websphere 8.5 are fine with it, Geronimo 3 is not (at least with the default classloading settings). – dkateros Jul 24 '13 at 14:09
  • Your answer was very helpful to me. I too was loading classes manually, and I just searched in the same folder for compiled class files with the same name plus a dollar-sign and anything else before ".class" and loaded them with the same classloader for good measure and voila - the problem is solved. Excellent! – GlenPeterson Oct 31 '13 at 22:52
  • Thanks a thousand times! You just saved my day after hours of debugging tomcat for an obscure IllegalAccessError.... Just because some thridparty software added some dynamic library with the same class, without me noticing.... – Falco Jul 02 '15 at 08:11
  • 1
    Whatever you are building with this, it is suspiciously similar to what I am attempting to accomplish right down to "entity" and "concrete". Seems this could be a very common issue. Are you synthetically generating concrete data (POJO) classes that conform to companion interfaces, and trying to limit mutable scope? – Coder Guy Nov 23 '15 at 08:52
1

Javadoc: Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.

As I think that some difficult class manipulation is attempted, maybe class loading, invest some time in how both classes are loaded. (In rare cases an explicit serialVersionId might help.)

If the classes are related (super / subclass), then try to remove that relation using an interface. Possibly use injection. That is not refer/load a class twice.

Sorry a concrete answer I cannot give.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Yeah that's the problem with low level engineering I suppose. But if I'm not mistaken it should have no problem referencing this field under normal situations? Sadly I may have to find a different route with how my obfuscator works inside a testing environment. – Justin Dec 28 '12 at 14:08