-
Bug
-
Resolution: Fixed
-
P3
-
7u5
-
b26
-
generic
-
generic
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8011818 | 8 | Karen Kinnear | P3 | Closed | Fixed | b85 |
When producing a LinkageError due to a ClassLoader constraint violation during method resolution, I get the following error message:
Exception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "B.m()LFoo;" the class loader (instance of PreemptingClassLoader) of the current class, Task, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, B, have different Class objects for the type sun/misc/Launcher$AppClassLoader used in the signature
at Task.run(Task.java:8)
at Test.main(Test.java:7)
Two problems:
1) sun/misc/Launcher$AppClassLoader is _not_ the ClassLoader of B. It is the ClassLoader of the resolved method's class, A (which is a supertype of B).
2) "the type sun/misc/Launcher$AppClassLoader used in the signature" should read "the type Foo used in the signature"
Sources to reproduce follow.
----------
public class Foo {}
----------
public class A {
public Foo m() { return null; }
}
----------
public class B extends A {}
----------
public class Task implements Runnable { public void run() {
Class<?> c = Foo.class;
B b = new B(); b.m();
}}
----------
public class Test { public static void main(String... args) throws Exception {
Class<?> c = Foo.class;
ClassLoader l = new PreemptingClassLoader("B", "Foo", "Task");
Runnable r = (Runnable) l.loadClass("Task").newInstance();
r.run();
}}
----------
import java.util.*;
import java.io.*;
public class PreemptingClassLoader extends ClassLoader {
private final Set<String> names = new HashSet<>();
public PreemptingClassLoader(String... names) {
for (String n : names) this.names.add(n);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (!names.contains(name)) return super.loadClass(name, resolve);
Class<?> result = findLoadedClass(name);
if (result == null) {
String filename = name.replace('.', '/') + ".class";
try (InputStream data = getResourceAsStream(filename)) {
if (data == null) throw new ClassNotFoundException();
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
int b;
do {
b = data.read();
if (b >= 0) buffer.write(b);
} while (b >= 0);
byte[] bytes = buffer.toByteArray();
result = defineClass(name, bytes, 0, bytes.length);
}
}
catch (IOException e) {
throw new ClassNotFoundException("Error reading class file", e);
}
}
if (resolve) resolveClass(result);
return result;
}
}
----------
Exception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "B.m()LFoo;" the class loader (instance of PreemptingClassLoader) of the current class, Task, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, B, have different Class objects for the type sun/misc/Launcher$AppClassLoader used in the signature
at Task.run(Task.java:8)
at Test.main(Test.java:7)
Two problems:
1) sun/misc/Launcher$AppClassLoader is _not_ the ClassLoader of B. It is the ClassLoader of the resolved method's class, A (which is a supertype of B).
2) "the type sun/misc/Launcher$AppClassLoader used in the signature" should read "the type Foo used in the signature"
Sources to reproduce follow.
----------
public class Foo {}
----------
public class A {
public Foo m() { return null; }
}
----------
public class B extends A {}
----------
public class Task implements Runnable { public void run() {
Class<?> c = Foo.class;
B b = new B(); b.m();
}}
----------
public class Test { public static void main(String... args) throws Exception {
Class<?> c = Foo.class;
ClassLoader l = new PreemptingClassLoader("B", "Foo", "Task");
Runnable r = (Runnable) l.loadClass("Task").newInstance();
r.run();
}}
----------
import java.util.*;
import java.io.*;
public class PreemptingClassLoader extends ClassLoader {
private final Set<String> names = new HashSet<>();
public PreemptingClassLoader(String... names) {
for (String n : names) this.names.add(n);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (!names.contains(name)) return super.loadClass(name, resolve);
Class<?> result = findLoadedClass(name);
if (result == null) {
String filename = name.replace('.', '/') + ".class";
try (InputStream data = getResourceAsStream(filename)) {
if (data == null) throw new ClassNotFoundException();
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
int b;
do {
b = data.read();
if (b >= 0) buffer.write(b);
} while (b >= 0);
byte[] bytes = buffer.toByteArray();
result = defineClass(name, bytes, 0, bytes.length);
}
}
catch (IOException e) {
throw new ClassNotFoundException("Error reading class file", e);
}
}
if (resolve) resolveClass(result);
return result;
}
}
----------
- backported by
-
JDK-8011818 Confusing error message for loader constraint violation
-
- Closed
-