As the title suggests, what is the classpath of classes compiled with Javassist?
My scenario is: Class A is compiled with Javassist. Class B is compiled with Java Compiler API and references Class A. The problem is that Class A is not visible to Class B...
Any ideas?
The "classpath" of class B does not depends on how the class is compiled (e.g. the class file is created), but how the class is loaded.
Java uses the class loader of a class to look up also all classes which are referenced by this class.
Each class loader can have a parent class loader, and normally loader.loadClass first asks its parent class loader about any classes, and in case of failure tries to load the class itself.
Thus, simply make sure the A class is visible to the class loader of class B, meaning that the class loader of A must be a parent (or parent of parent, or ...) of the class loader of class B.
Related
In org.springframework.core.SerializableTypeWrapper (version 5.2.3), there is the following code at line 112:
if (GraalDetector.inImageCode() || !Serializable.class.isAssignableFrom(Class.class)) {
// Let's skip any wrapping attempts if types are generally not serializable in
// the current runtime environment (even java.lang.Class itself, e.g. on Graal)
return providedType;
}
I'm curious about the second check (!Serializable.class.isAssignableFrom(Class.class)): is it possible for it to evaluate to true (that is, for Serialazable.class to be not assignable from Class.class)?
Here is what Class#isAssignableFrom() javadoc says:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.
Looking at the code of Class, I see the following:
public final class Class<T> implements java.io.Serializable
So Serializable is a superinterface of Class and should always be assignable from Class. But the check in the Spring code suggests that sometimes it's not.
How come? In what situations can this happen and why don't they violate the Java Language Specification?
A custom class loader is a possible (if unlikely) mechanism for the expression to return false. Custom class loaders can do some crazy things, including loading their own versions of standard Java classes. Some things to know about class loaders:
Custom class loaders can be configured to load any class, even including Java standard library classes (it's discouraged of course, but still possible)
Custom class loaders will typically be configured to delegate to the system class loader for classes that they don't know how to load.
When class A has a reference to class B, the reference will be resolved using whichever class loader was used to load class A
More than one class loader can be configured to handle the same class, which can lead to multiple versions of a class getting loaded into the JVM, with the actual implementation you get depending on which class loader you ask
Suppose there is a custom class loader that, for whatever reason, is configured to load java.io.Serializable by itself, but delegates to the system class loader for loading other classes, including java.lang.Class.
Now suppose this custom class loader is used to load SerializableTypeWrapper. This means it will also be used to resolve the reference to java.io.Serializable in SerializableTypeWrapper. With the reference to java.lang.Class, the custom class loader will delegate this to the system class loader. The system class loader will be used to load java.lang.Class, but it will also be used to load the reference to java.io.Serializable from within java.lang.Class.
So now we can ask the question - is java.io.Serializable [custom] assignable from java.lang.Class [standard]? And the answer is no - java.lang.Class does implement java.io.Serializable [standard], but it does not implement java.io.Serializable [custom].
I have this code
MyClassloader loader = new MyClassloader();
Class c = loader.loadClass(classToLoad);
Thread.currentThread().setContextClassLoader(loader);
MyClass myClass = (MyClass) c.newInstance();
And classloader code is
public MyClassloader) throws IOException {
super(Thread.currentThread().getContextClassLoader());
}
The class loading works fine the problem is that static variables are not isolated, so if inside the MyClass a static variable is set all other MyClass instances get the same value.
In what can a static variable be isolated?
You delegate to the same class loader. So you will see no difference.
What should yo do? Implement class loading in your class loader, don't just delegate. For instance, inherit your class loader from URLClassLoader, initialize it properly (it means, provide a valid class path to your class loader to initialize it). Then you will see, that classes loaded by you class loader are not euqal to the classes loaded by the standard class loader, and as a consequence, their static members will be different.
Often the context class loader is inherited from URLClassLoader and thus you don't have to spend much time configuring class path for it. Instead, to initialize you class loader you can just reuse the URLs of the context class loader, as follows:
public class MyIndependentClassLoader extends URLClassLoader {
public MyIndependentClassLoader(){
super(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs());
}
}
Now you can use your class loader and check static members.
What is the difference between this approach and the original approach?
You know that classes are also objects (of special type): they have their own member variables, name, serialVersionUID, annotationData, etc., and their own methods, newInstance(), getFields(), getMethods(), etc. When you call
Class c = loader.loadClass("com.my.package.MyClassX");
you get c, this is an object that describes the loaded class "some class name". This c not only allows to create instances, but holds also all static members.
In your code: Your class loader does not load class directly. Instead, it delegates to the context class loader. That's why if you compare two loaded classes
Class c = loader.loadClass("com.my.package.MyClassX");
Class ct = Thread.currentThread().getContextClassLoader().loadClass("com.my.package.MyClassX");
you will see, that c and ct is the same object. If you call c.equals(ct), it will give you true. And if you call c == ct, it will also give you true. It means, this is the same class instance. That's why - naturally - if you check static variables, they will be the same. If you change static variable in one class, it will also be changed in another class, and vice versa.
In my code: The essential difference is, that the class loader loads classes itself. It does not delegate it to other class loader. I suggested to extend it from URLClassLoader to simplify our implementation (otherwise you would have implement from scratch dealing with class path, directories, jars, visibility, caching, etc.). And to avoid adding each class path element step by step I suggested to use the same class path (the same list of directories, jars, etc.) as the context class loader. So our class loader will be able to find the same classes as the context class loader.
Now check the class that this class loader loads. Let's call it ci:
Class ci = new MyIndependentClassLoader().loadClass("com.my.package.MyClassX");
If you compare these classes, you will see that c.equals(ci) gives false. Means, they are different. That's why they have also independent static members. If you change static member in one class, ct, it will not change in the other, ci, and vice versa.
I was studying the Java architecture and in between, I found a concept of class loader and it was also referenced as a primordial class loader. I want to know that what is the function of this class loader, why we use this? I also want to know that what was the basic need so that we are using this.
In Java every class has to be loaded by some class loader.
How is the first class loaded? It has to be loaded through some class loader (which is just another class), so without some special code this would lead to infinity recursion.
The class loader that loads the first classes (java.lang.Object, java.lang.Class, java.lang.String, java.lang.ClassLoader and others) can therefore not be a 'normal' class loader.
It is this class loader that is referenced as the primordial class loader (primordial: from latin, meaning "the first", "the origin(al)")
For further study see the Java Security Aritecture and Securing Java
Primordial class loader the first class loader responsible to load class loader like "BootStrap class loader" which is part of JVM and written in native language.
I'm trying to understand why the JVM decides to load certain classes when it doesn't appear it needs to. Consider the following example code:
public class Foo {
public void foo() {
}
static class Bar {
}
public Bar bar() {
return new Bar();
}
}
When calling new Foo().foo(), Bar is not loaded by the classloader since it's not needed. But, if we change the example to have bar return an instance of a sub-class:
public class Foo {
public void foo() {
}
static class Bar {
}
static class BigBar extends Bar {
}
public Bar bar() {
return new BigBar();
}
}
Calling new Foo().foo() causes the classloader to load both the Bar and BigBar classes even though neither of them are needed. Why?
Aside from this specific scenario, is there a way to learn why the JVM decides it needs to load a class, in general?
Here is a good read from Internals of Java Class Loading
Whenever a new JVM is started by typing java MyMainClass, the
"bootstrap class loader" is responsible for loading key Java classes
like java.lang.Object and other runtime code into memory first. The
runtime classes are packaged inside of the JRE\lib\rt.jar file. We
cannot find the details of the bootstrap class loader in the Java
documentation, since this is a native implementation. For the same
reason, the behavior of the bootstrap class loader will also differ
across JVMs.
In a related note, we will get null if we try to get the class loader
of a core Java runtime class, like this:
log(java.lang.String.class.getClassLoader());
Next comes the Java extension class loader. We can store extension
libraries, those that provide features that go beyond the core Java
runtime code, in the path given by the java.ext.dirs property. The
ExtClassLoader is responsible for loading all .jar files kept in the
java.ext.dirs path. A developer can add his or her own application
.jar files or whatever libraries he or she might need to add to the
classpath to this extension directory so that they will be loaded by
the extension class loader.
The third and most important class loader from the developer
perspective is the AppClassLoader. The application class loader is
responsible for loading all of the classes kept in the path
corresponding to the java.class.path system property.
well explained http://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html
When Class is loaded in Java
Class loading is done by ClassLoaders in Java which can be implemented to eagerly load a class as soon as another class references it or lazy load the class until a need of class initialization occurs. If Class is loaded before its actually being used it can sit inside before being initialized. I believe this may vary from JVM to JVM. While its guaranteed by JLS that a class will be loaded when there is a need of static initialization.
When a Class is initialized in Java
1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class is assigned.
4) an static field of class is used which is not a constant variable.
5) if Class is a top level class and an assert statement lexically nested within class is executed.
I have a class A extends B.
I've created a CustomClassLoader extends ClassLoader to use defineClass(className, byte[], offset, length).
I've instanciate a new CustomClassLoader(Thread.currentThread().getContextClassLoader()).
So the parent of my CustomClassLoader is the ClassLoader from the current thread.
I've modified B class using ASM framework. I've write my modified class in a .class file and use a decompiler to be sure it works. And it works.
I've added modified B class to my CustomClassLoader
I've set the Thread.currentThread().setContextClassLoader() with my CustomClassLoader.
I've load A using Class.forName(String, true, the CustomClassLoader).
But the loaded B class seems to be the orginal class.
What did I wrong ?
If you need more info, a detailed topic is on my GitHub.
Java classloaders first search the parent classloader before looking in the child.
The loadClass method in ClassLoader performs these tasks, in order,
when called to load a class:
If a class has already been loaded, it returns it.
Otherwise, it delegates the search for the new class to the parent class loader.
If the parent class loader does not find the class, loadClass calls the method findClass to find and load the class.
(Understanding Extension Class Loading - Oracle)
If you want to change that order, you need to override the loadClass method as well but there are many caveats and it's not advisable unless you understand classloading very well.
The easier option is to make sure that the parent class loader cannot find the original class B.
There are several things to know:
For most things, dealing with the thread’s context class loader is obsolete, as it has no impact. It’s more like a convention; setting it has an impact if there’s some other code querying and using it. For the standard class loading process, it doesn’t have any meaning. It’s unfortunate that the documentation doesn’t mention that and make it look like a relevant thing. Perhaps, it was intended to have more meaning when it was added.
As pointed out by Erwin Bolwidt, when loading A via your custom loader, it will delegate to its parent loader, returning a class A loaded by the parent.
When resolving class references, the JVM will always use the defining loader of the referrer. So when the reference from A to B is resolved, the JVM will always use the parent loader which defined the class A
The last point implies that even if you modify your custom class loader to look up its own classes first instead of following the standard model of querying the parent first, it doesn’t solve the issue if it has no own A, as then, it still returns the parent’s A whose references will be resolved using the parent. Since you are invoking defineClass before asking for A, the lookup order doesn’t matter at all, as your custom loader has an already defined B that it returned if anyone ever asked it for B…
So you could let your custom loader also load and define A. Or you use Reflection with access override to defineClass on the system ClassLoader before it loads B. The cleanest solution is to implement the class modification logic as a Java Agent which can use the Instrumentation API to intercept and change the definition of B right at its loading time.