I create my custom class loader :
new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
where urls is a new Url("java.util.TimeZone")
After that I load class by name :
Class<?> newTimeZoneClass = loader.loadClass("java.util.TimeZone");
and newTimeZoneClass==TimeZone.class returns true.
The main reason of that my class loader load class from parent loader.
How to fix it?
You cannot do this. The Java security model prevents any class loader creating a class in the "java.*" hierarchy. This is hard-coded in the native code of the JVM, so there is no workaround.
Additionally, the standard class loaders follow the delegation model of asking the parent class loader to load the class before they try to, so you always get the same class instance. Special class loaders are used by application containers to invert this delegation for application specific classes.
There are a few ways to do this anyway.
First, TimeZone is an abstract class and the actual implementation is normally sun.util.calendar.ZoneInfo. As this is not in the "java.*" hierarchy, you can create multiple copies in your class loaders.
Second, you can sub-class TimeZone, and delegate all methods to a JVM provided instance, adding your own functionality as you do so. I've used this to make TimeZone instances singletons in some of my applications.
Third, as the JDK is open source, you can copy the all the code for TimeZone and its sub-classes into your own application, and then you can have as many versions of the class as you like.
If you want to change the TimeZone instances returned by the static methods in TimeZone, these delegate to ZoneInfo and you will have to either use reflection to change the outcome. If you know Aspect-J or equivalent, you could also intercept the call.
As it is mentioned in Java Doc of public URLClassLoader(URL[] urls, ClassLoader parent):
Constructs a new URLClassLoader for the given URLs. The URLs will be
searched in the order specified for classes and resources after first
searching in the specified parent class loader.
I assume you should create a CustomClassLoader ccl = new CustomClassLoader(); or use another constructor by passing an AccessControlContext object - URLClassLoader(URL[] urls, ClassLoader parent, AccessControlContext acc)
or URLClassLoader(URL[] urls, AccessControlContext acc).
There are some articles on creating new class loaders:
https://www.baeldung.com/java-classloaders
https://www.javaworld.com/article/2077260/learn-java-the-basics-of-java-
https://www.oodlestechnologies.com/blogs/Creating-Custom-Class-Loader-In-JAVA/class-loaders.html
Related
I'm using Byte Buddy in a scenario in which I could potentially need to create several dozen thousand classes with it. These are independent classes implementing interfaces, not proxies.
Right now I'm loading my DynamicType.Unloaded<?> instances into class loaders by wrapping one of my application's class loaders:
final Class<?> myClass =
unloadedType
.load(someAppClassLoader, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
This wrapping strategy is right for me, but I have the issue that every time I execute the code above a new, sealed ClassLoader is created containing only the new class. I know I can "include" auxiliary types... but these are not auxiliary types, but fully independent classes.
As I have to create many thousands, I'm left with a huge amount of class loaders I don't really need, because I want to isolate bytebuddy-created classes from the rest, but not one from the other, nor have any need to have a new class loader created for each one. And my profiling shows quite a huge memory overhead from the large amount of class loaders (which in this case are quite heavy).
From my tests it seems I could use a wrapping strategy for the first one:
final Class<?> myClass =
type
.load(someAppClassLoader, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
...then retrieve the new class loader:
final ClassLoader bbClassLoader = myClass.getClassLoader();
...and then use this class loader in subsequent creations, by switching strategy to injection:
final Class<?> myOtherClass =
otherUnloadedType
.load(bbClassLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
But this does not look like a clean strategy to me given it seems to be injecting via introspection in order to circumvent the fact that the class loader is sealed. So I wonder whether there is a better mechanism for doing this in Byte Buddy.
Note that in order to have a properly sealed class loader I could turn all my many thousands of DynamicType.Unloaded objects into Class<?> ones at once into a single class loader instance (and seal it). I can initialise all my classes at application bootstrap in a batch and then leave the class loader alone without further dynamic class creation.
What would be the proper strategy for a scenario like mine?
The class loader that is created when using a WRAPPER strategy allows for loading classes later in the class loader's life-cycle. For security reasons, this needs to be enabled by calling opened() on the strategy.
You can then cast the first class loader to InjectionClassLoader which allows for using InjectionClassLoader.Strategy.INSTANCE where additional classes can be injected without any unsafe API.
You can also combine multiple DynamicType instance by calling include and then load all classes using WRAPPER in one wash.
I know there is a "bootstrap classloader" loading all the classes from the jre/lib (rt.jar, etc). Is it possible to get my hands on this "bootstrap classloader" in order to load an additional class from another non-java package?
I'm talking about the bootstrap classpath, which is very different than the regular classpath described on this answer: How should I load Jars dynamically at runtime?
The bootstrap class loader is represented as null, e.g. when calling Class.getClassLoader(). This can be fed directly to Class.forName(String,boolean,ClassLoader):
If the parameter loader is null, the class is loaded through the bootstrap class loader.
So, you can try to load a class explicitly through the bootstrap loader using Class.forName(className,true,null) or resolve a class relative to another class’ context using Class.forName(className,true,context.getClassLoader()) without having to special-case the bootstrap loader.
If you want to define a runtime class as-if being loaded by the bootstrap loader, there is no standard solution. There is the method sun.misc.Unsafe.defineClass(String, byte, int, int, ClassLoader, ProtectionDomain) that allows to define a class within a particular class loader, which is a proprietary API that is likely to disappear in the future.
Starting with Java 9, there is java.lang.invoke.MethodHandles.Lookup.defineClass(byte[]), a standard method define a class within another class’ context, but it requires non-standard ways, e.g. Reflection with access override to get a Lookup object with the appropriate access right to a bootstrap loaded class, e.g. java.lang.Object. There are already existing Q&A about creating such a Lookup object for other purposes, e.g. this one. Such Reflection hacks are not guaranteed to work in future versions though.
For a Java Agent, there’s also the option to dump the class file(s) into a temporary Jar file and add it to the bootstrap class path programmatically, if it doesn’t mind that this involves I/O.
There is another catch to be aware of. When you want other bootstrap loaded classes to find your class, you have to add it before the first attempt to access that class, as the JVM’s resolver will remember the result, even if it is to fail with an error.
A somewhat roundabout way to load classes via the bootstrap class loader is to define your own class loader like so:
ClassLoader bootClassLoader = new ClassLoader(null){};
This class loader has no parent and thus the only place it will load classes from is the inherent bootstrap class loader.
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.
I have to dynamically load a class with the same name from some JAR, but different implementation, multiple times.
I'm creating an evaluator backend and I have to dynamically load classes and test them.
The tests are JUnit classes that instantiate the classes which should be tested, this is a simple example:
package evaluator.tests;
import static org.junit.Assert.*;
import org.junit.*;
import evaluator.tested.*;
public class KTest {
private K tested;
#Before
public void setup() {
tested = new K();
}
#Test
public void returnsTrueTest() {
assertTrue(tested.returnsTrue());
}
}
The rest of my application would need to receive JAR files from users which would contain implementations of the K class which is being tested above. Then, KTest would have to run on their K classes, not the ones in the application.
I know how to dynamically load a class, but I don't know how to make a test work with it, and not the one which I made.
One of the solutions I came up with was to isolate testing in a completely new class, e.g. Evaluation, create a new class loader in that class, and make it load all referenced classes. After creating the class loader, it would load the K class from the JAR file.
This would mean that each time a user submits his JAR, a separate Evaluation would be instantiated, it would create its own class loader and start the JUnit test. When that happens, the test would use the user's implementation of K, and not the default one.
Is this possible, and how can it be done?
I read that class loaders always ask their parent whether a class is already loaded. This would mean that I would have to somehow "flush" all the classes that I loaded dynamically from the JAR file in Evaluation, so that they would be unloaded and then loaded again in another Evaluation.
Load class K, test class K, unload class K, repeat with different K.
Yes you can do this.
If you for example use java.net.URLClassLoader with null as parent: new URLClassLoader( urlArray , null ). Then the bootstrap ClassLoader will be used as parent for your ClassLoader.
Here is an example Class which simply uses a new classloader two reload a class.
package com.anarsoft.agent.regression;
import java.net.URL;
import java.net.URLClassLoader;
public class TestClassLoading {
public static boolean field = false;
public static void main(String[] args) throws Exception
{
URL[] urlArray = new URL[] { TestClassLoading.class.getProtectionDomain().getCodeSource().getLocation().toURI().toURL() };
URLClassLoader firstClassloader = new URLClassLoader( urlArray , null );
Class firstClass = firstClassloader.loadClass("com.anarsoft.agent.regression.TestClassLoading");
firstClass.getField("field").setBoolean(null,true);
System.out.println(firstClass.getField("field").getBoolean(null)); // true
URLClassLoader secondClassloader = new URLClassLoader( urlArray , null );
Class secondClass = secondClassloader.loadClass("com.anarsoft.agent.regression.TestClassLoading");
System.out.println(secondClass.getField("field").getBoolean(null)); // false
// the static field is false since its a new loaded class
}
}
I've made a blog post on this subject, in which the problematics is explained a bit further.
After some research I think I've found a way to accomplish exactly what I want. I haven't implemented this system yet (will edit the answer once I do), so I'd like some feedback from people who are more experienced in this regard.
This is how I understand URLClassLoaders (and classloaders in general) work:
URLClassLoader.loadClass() gets automatically called if it’s the current classloader (for the method/class executing). The call is first delegated to its parent classloader, and if nothing is found it uses its own custom findClass() to load it off one of the URLs it has. loadClass() here (and the classloading logic) is just inherited from the regular ClassLoader.
The default behavior of this method (loadClass()) is to first delegate the search to the parent, and if parent cannot find the class, only then to call its own findClass(). This method (findClass()) is, by default (in ClassLoader), left unimplemented, and you are supposed to implement it yourself, by essentially getting the bytecodes of the class from somewhere (e.g. a file or a network) and calling defineClass() on them.
Once you call defineClass() on some class, and only then, are you registered as the classloader of this class. In all other cases classloading is either delegated to your parent (and you are not the classloader of the class you are loading, paradoxically), or you throw a ClassNotFoundException. You cannot change the classloader of some class at runtime, it is set once it is loaded, and constant.
All of my test classes will try to getClass().getClassLoader().loadClass() all of the classes that they reference - including my custom test classes (this is the regular behavior of all classes, not just my tests, to be clear). As long as they’re using standard classes, and other classes from my application that are not to-be-tested classes, this classloading method should be delegated further on to the application classloader. However, as soon as they try to load a to-be-tested class, they need to get their own, specifically loaded, custom version of it.
The use case of my application is that a user submits a JAR with some class, then a test that expects this class to have certain methods is ran on the class from that JAR (using JUnit), and then the results are sent back to the user.
The solution is as follows:
Implement basic versions of the to-be-tested classes so that the tests would compile and run without any submitted JARs. This could (more likely, should) be done by leveraging polymorphism, but is not planned at the moment (this means that the user should most likely extend the “basic” version of the class himself, locally, before sending the class to be tested).
Extend URLClassLoader and re-work the classloading logic.
Do the necessary checks (is the class already loaded) that exist in the default implementation.
Try to findClass yourself, if it’s not in your URLs, throw a ClassNotFoundException.
If the class has already been loaded, or if has been loaded just now from some URL, return the class.
If the class has neither been loaded before (by this classloader), nor is it in one of the URLs, delegate the search to your parent.
If the parent returns the class, return the class, if not, throw ClassNotFoundException (it will actually be thrown by the parent).
For each JAR file with a class that is sent:
Instantiate the custom URLClassLoader
Add the JAR to it and the specific test class as well
Ask it to load the test class. At this point my custom classloading logic kicks in, and it loads my test straight from the disk - anew, without delegating to its parent classloader. Why? It calls defineClass() on my test class, which sets this custom URLClassLoader as the parent of the test class
Give the test class to JUnit, which then instantiates it and begins testing
Once one of my tests are running, each time they reference any class, they will call their own custom classloader’s loadClass(). First they will search the URLs - so in case they’re referencing a to-be-tested class, it will be loaded from there. In case they are referencing some other application class, or a system class, the custom classloading logic will just delegate this call and an already-loaded (presumably) class would be returned.
As I’ve said - I haven’t implemented this yet, and I would really like if you’d point out my mistakes in the comments.
Resources from which I've gathered this information:
http://www.onjava.com/pub/a/onjava/2003/11/12/classloader.html
http://www.devx.com/Java/Article/31614
http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.html
http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass%28java.lang.String,%20boolean%29
You need to make sure that jar you are loading classes from is unknown to JVM system class loader (not on the classpath). Then system class loader will not be loading classes from the jar thus making your custom class loader to load from this jar.
You can fool it.
Cass that you want to reset should not be in the classpath
Can implement a interface or extend a class that is in the classpath (useful to type cast or need to use reflection to 'discover' and call methods, OR the calling class calls another method that has the code the calls the class(es) under test
every time you want to test, rename the jar, load from the jar, using a URL class loader sub class. On init of your loader null is fine.
So if you load a1.jar first time, load from a2.jar next time and make sure a1.jar is moved to another folder
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.