Does every "new" result in at least one Classloader.loadClass invocation - java

I noticed that we can set a Thread's context classloader at will. Does it mean that every new results in the context classloader's loadClass getting called?

No, loadClass() will only be invoked once, the first time the class is accessed. (This will not necessarily happen on new(), it may happen if you try to access a static member of the class.)
In every subsequent access of the class, loadClass() will not be invoked.
That's because every time the class is needed, the ClassLoader invokes findClass() internally, which tries to find an already loaded class, so if the class has already been loaded, the ClassLoader refrains from invoking loadClass() again.

Class loading by ClassLoaders 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 but you should be aware that the behavior might not exactly the same as new in some scenarios and might be the same in others. If Class is loaded before its actually being used it can sit inside before being initialized. this might vary from JVM to JVM, but its guaranteed by JLS that a class will be loaded when there is a need of static initialization.
as also explained in What does "new" do in Java w.r.t. class loader?:
Class loading is performed only once for a given namespace, unless the
Class in question has been previously unloaded. Therefore, the
equivalent expression A.class.getClassLoader().loadClass("B's
canonical name") will be executed only once in most scenarios. In
other words, if you have two expressions - new A(), the loadClass will
be performed only once.

Related

How to load a modified superclass in Java?

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.

JVM tries to load a class that isn't called

I am writing code that adds functions to a 'mod' if it exists in the classpath (referenced by pixelmonPresent)
PixelHammerTool extends ItemHammer
, ItemHammer only exists if pixelmon is present
The issue im having is, if i do this in the class (same package)
if(Basemod.pixelmonPresent) {
rubyHammer = new PixelHammerTool(Basemod.RUBY, "pixelutilitys:RubyHammer", "rubyHammer");
}
It will cause a class not found on PixelHammerTool,
Why is this being called if the if statement is false and what can i do about it ?
The why is simple and straightforward: because when a class is loaded, all the classes referenced by it are loaded too. (In fact they are loaded first.)
Avoiding it isn't too complicated either, although the code won't look nice: you need to load the class with reflection, using Class.forName(), find the constructor you want from the array returned by Class.getConstructors() and then create an instance using Constructor.newInstance().
Note that while if it only happens a few times in your code, this solution is fine, if you find yourself doing this a lot then you should probably look for a dependency injection framework that will do the heavy lifting for you.
Under the Linking section in the specs, we see this:
For example, a Java Virtual Machine implementation may choose to resolve each symbolic reference in a class or interface individually when it is used ("lazy" or "late" resolution), or to resolve them all at once when the class is being verified ("eager" or "static" resolution). This means that the resolution process may continue, in some implementations, after a class or interface has been initialized. Whichever strategy is followed, any error detected during resolution must be thrown at a point in the program that (directly or indirectly) uses a symbolic reference to the class or interface.
So when the constant has to be defined is implementation-dependent, based on the class loader. The behavior you're seeing is consistent with the "eager" resolution mentioned: when you reference PixelHammerTool in your code, even if it's for a runtime path that will never be hit, the class loader tries to link in its definition, which does not exist.
This strategy causes the JVM to start slower but execute faster at runtime, which is generally the strategy taken in all the implementations I'm familiar with. Indeed, the default class loader is given the name "bootstrap class loader" because it has this behavior - load classes at JVM bootstrap time.
You can either instantiate the class via reflection, as biziclop suggested (the easier route), which forces linking at runtime, or find or create a class loader that instantiates classes lazily.

Javassist: re-creating a class - delete first, or defrost() and modify?

I use Javassist to create a class. And in a test suite, when a second test tries to create the same class, it fails at pool.makeClass( ... ) because the class is frozen (i.e. already created via toClass().
What's the way to overcome this? Ideally, the first test should delete the class somehow - perhaps unload from the classloader - but as I read in JLS, the unload operation is not reliable.
So perhaps the workaround is to check in the class creating code whether it exists, and if it does, defrost() it, remove all members etc, and re-create it.
Any other ideas?
Or is there some reliable way to delete the class through Javassist?
You cannot unload a single class from a ClassLoader. A class may be unloaded if it and its ClassLoader became unreachable but since every class refers to its loader that implies that all classes loaded by this loader must have become unreachable too.
But you can (re-)create the class using a different ClassLoader. Well, formally it is a different class with the same name (and maybe the same byte code) then. If the code executed within the test case leaves no references in the heap, the ClassLoader and its classes might be collected after the test.
I get the same problem, i solved it this way, may be cannot apply for your test case:
Make CtClass a private static variable of your Class.
Create a method that check's if CtClass is already built.
If CtClass is not built, call the method that builds it, else, return that CtClass.
Make that all your test use the new method.
So, if you have N Test, just the first one will attempt to Built the CtClass, the rest of them will have the static CtClass Variable.

How to know if Static Block Initialization has been run?

I am trying to get rid of some memory leaks. I'd like to reset all the static variables of all the classes (not only mine) from a class loader. There is a classes attribute that lists all the classes known by the ClassLoader.
So I just want to loop over it and with reflection set the static variables to null.
The problem is that all those classes have not necessarily been initialized (the Static Block Initialization did not run). As the purpose is to reset the values and then unload the classes, there is no point initializing this classes. Moreover, when I reset a class ROOT that is used in the SBI of another class CHILD, running the SBI of CHILD can lead to unexpected behavior...
So the question is: Is there a way to know if the SBI has been run by the JVM or not.
Note:
to anybody proposing to use the findLoadedClass of the ClassLoader, there is in the specification this important sentence: *In this post, there is an important note: "loaded" doesn't mean "initialized". initialization only happens at precise moments defined by JLS3 $12.4.1 *
static block was initialized if class was loaded on JVM.
Is class loaded on JVM you can detect with ClassLoader

Java: Difference between Class.forName and ClassLoader.loadClass

What is the difference between Class.forName and ClassLoader.loadClass in the following codes:
Class theClass = Class.forName("SomeImpl");
SomeImpl impl = (SomeImpl)theClass.newInstance();
and
Class theClass = ClassLoader.loadClass("SomeImpl");
SomeImpl impl = (SomeImpl)theClass.newInstance();
Are they synonymous? Is one preferable to the other in certain circumstances? What are the do's and dont's when using these two methods?
Class.forName() will always use the ClassLoader of the caller, whereas ClassLoader.loadClass() can specify a different ClassLoader. I believe that Class.forName initializes the loaded class as well, whereas the ClassLoader.loadClass() approach doesn't do that right away (it's not initialized until it's used for the first time).
Just found this article when looking to confirm my summary of the initialization behavior. It looks like this has most of the information you're looking for:
http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html
This usage is pretty cool, though I've never used it before:
Class.forName(String, boolean, ClassLoader)
It allows you to specify a ClassLoader and the boolean parameter defines whether the class should be initialized when it's loaded or not.
Shaun's answer is more or less correct except few omissions/small errors:
Class.forName associates the class w/ the ClassLoader (regardless if any other parent loads it for real), hence ClassLoader.findLoadedClass is successful next time. That's a very, very important point, most ClassLoader would try Class c = findLoadedClass(name); if (c!=null) return c; as first statements bypassing the whole find/look up part. Calling ClassLoader.load directly will not add the class to the loaded ones.
The case has implications when loaded via graph alike structure of ClassLoader, i.e. not using parent only to lookup first.
Initialization of the class is performed in loadClass of the ClassLoader w/ code like that: if (resolve) resolveClass(c); and the ClassLoader can actually skip resolve it it feels like, unrecommended but possible.
What are the do's and dont's to using these two methods?
Unless you have very strong idea why you want ClassLoader.loadClass(String), do not use it directly. In all other case, always rely on Class.forName(name, true, classLoader).
Overall Class loading is next to an art and it cannot be covered in a simple answer (not joking about art part)
When use you use Class.forName("SomeImpl"), you're obtaining the class via the current classloader (i.e. the loader of the class that you're making the method call in). It will also initialize the class. It's effectively the same as calling Class.forName("SomeImpl", true, currentLoader) where currentLoader would be the caller's classloader. See the details here.
The second method requires a classloader to be chosen first. Don't write it like ClassLoader.loadClass("SomeImpl") since it is not a static method. You'd require something like
final ClassLoader cl = this.getClass().getClassLoader();
Class theClass = cl.loadClass("SomeImpl");
Mind that subclasses of ClassLoader should override the findClass method rather than loadClass. This is the same as calling the (protected) method loadClass("SomeImpl", false), where the second argument indicates whether linking should be done or not.
There are more subtle differences... The loadClass method expects a binary class name as specified by the Java Language Specification, while forName could also be used with Strings representing primitive types or array classes.
Overal, it's best to use Class.forName, if necessary specifying a specific classloader and whether it must be intialized or not, then let the implementation figure out the rest. Using classloaders directly is good for finding resources in a jar or on the classpath.
This line won't compile:
Class theClass = ClassLoader.loadClass("SomeImpl");
because loadClass is not a static method of ClassLoader.
To fix this problem, create a ClassLoader object as follows in one of 3 possible ways:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassLoader classLoader = Main.class.getClassLoader(); // Assuming in class Main
ClassLoader classLoader = getClass().getClassLoader(); // works in any class
then call:
Class theClass = classLoader.loadClass("SomeImpl");
-dbednar
The loadClass() method can't be called as a static one. Create sub class for ClassLoader and have some additional other methods to do operations. Can create your own class loader by extendingClassLoader class. In functional both ways are same.

Categories