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.
Related
Oracle JavaDocs explains that IllegalAccessError is
"Thrown if an application attempts to access or modify a field, or to
call a method that it does not have access to."
I try to load a class dynamically and I get this exception.
if I understand correctly when you use a classloader to load a class with a private package dynamically IllegalAccessError happens
the class I am trying to load is using
org.xml.sax.helpers.SecuritySupport
which also states in their description in the following url
http://grepcode.com/file/repository.springsource.com/org.apache.xmlcommons/com.springsource.org.apache.xmlcommons/1.3.4/org/xml/sax/helpers/SecuritySupport.java
that
Unfortunately, we can't load the class using reflection
* because the class is package private. And the class has
* to be package private so the APIs aren't exposed to other
* code that could use them to circumvent security. Thus,
* we accept the risk that the direct reference might fail
* on some JDK 1.1 JVMs, even though we would never execute
* this code in such a case. Sigh...
how can I dynamically load it anyway? I have to get it to work.
also if I get an error when I use a classloader, I cannot recover from that, so how can I know in advance that I cannot load this class?
thanks in advance to anyone who helps
The statement “we can't load the class using reflection because the class is package private” doesn’t make any sense, as can be shown easily:
package somepackage;
class BaseClass {
public static void main(String[] args) throws ReflectiveOperationException {
BaseClass obj=(BaseClass)
Class.forName("somepackage.SubClass").newInstance();
obj.aMethod();
}
void aMethod() {
System.out.println("base class");
}
}
class SubClass extends BaseClass {
#Override
void aMethod() {
System.out.println("method overridden by subclass");
}
}
This works flawlessly, printing method overridden by subclass replicated the actual use case of that SecuritySupport class.
However, since that class obviously serves the purpose of allowing a transition between Java 1.1 and Java 1.2, it might be possible that there were such restrictions twenty years ago, when this transition happened.
Your use case, however, is entirely different. You say that you are trying to load a class which “is using org.xml.sax.helpers.SecuritySupport”, which doesn’t imply that it is using said class via Reflection, but as shown above, that doesn’t matter anyway. It either case, it would only work, if the class is in the same package, whether you load the class “dynamically” or not.
There are only two possible scenarios.
If the class is truly within the same package, which at runtime implies that it also has been loaded by the same class loader, which would require that is also part of the JRE, if the JRE’s org.xml.sax.helpers package defines a SecuritySupport class, then the class can access the class within the same package.
If you are trying to load a class via a different ClassLoader from a different code source, it will not be of that package, even if you’d give it a qualified name of the org.xml.sax.helpers.SomeClass form. If the JRE’s org.xml.sax.helpers package happens to define a SecuritySupport class, all non-JRE classes would be in a different package. When it tries to access that class, which is not part of the official API, it doesn’t work.
Note that all standard class loaders follow a delegation model trying to resolve a name through their parent class loader first, which is the reason why they all would prefer the JRE’s org.xml.sax.helpers.SecuritySupport class, if there is one. With non-standard class loaders, you could have different, unrelated classes with that qualified name, being in different runtime packages.
In that second scenario, the question arises, why your class is using that class. In 2017, there’s rarely a need to differentiate between Java 1.1 and Java 1.2 and the functionality offered by that class is also only relevant for a class within the privileged code source of the JRE (or different code sources with different privileges in general).
From this question, I found that it is not possible to look up a class from a sun.misc.DelegatingClassLoader, i.e. looking up a class on its own class loader like
Class<?> accessor = ...
accessor.getClassLoader().findClass(accessor.getName());
throws a ClassNotFoundException. The delegating class loader is used for loading runtime-generated accessor classes for converting Java's reflective JNI calls into Java invocations.
For some strange reason, I am not able to find the source of the DelegatingClassLoader anywhere in the JDK sources even though it is clearly available in my build where it seems to be an empty implementation of a subclass of the standard ClassLoader from looking at the class's byte code.
If the DelegatingClassLoader is however really only a simple subclass, I do not understand why it is not possible to look up a class by its name. Is there some VM magic involved? It seems like the
private native final Class<?> findLoadedClass0(String name);
method does not return the loaded class for a DelegatingClassLoader. The private classes field does however include the loaded class.
I was not able to find any information on how these class loaders are supposed to be different from any other class loaders. I am looking for an explanation why the above lookup does not work but throws an exception.
The source for DelegatingClassLoader is for whatever reason located in ClassDefiner.java. Interestingly, this code has a comment that references bug 4474172, which suggests that this class loader is known to the JVM and has special behavior:
The second solution is to make the virtual machine "magically"
delegate class loading for these newly-fabricated class loaders to
their parent loaders, without making an upcall to Java. The
disadvantage is that this is another hack in the JVM [...]. This
option has been chosen.
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
This question already has answers here:
Difference between Loading a class using ClassLoader and Class.forName
(9 answers)
Closed 5 years ago.
When dynamically loading a class, when is it appropriate to use
Class.forName("SomeClass");
and when should I use
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
Or, are they two ways of doing the same thing?
They are quite different!
As stated in the documentation for Class.forName(String),
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to: Class.forName(className, true, currentLoader)
(true here refers to do you want to initialize the class?)
On the other hand, ClassLoader.loadClass(String):
Invoking this method is equivalent to invoking loadClass(name, false).
(here, the boolean has nothing to do with initialization; but if you check loadClass(String, boolean) documentation, you will see that all it does is load the class, not initialize it).
The first one (Class.forName("SomeClass");) will:
use the class loader that loaded the class which calls this code
initialize the class (that is, all static initializers will be run)
The other (ClassLoader.getSystemClassLoader().loadClass("SomeClass");) will:
use the "system" class loader (which is overridable)
not initialize the class (say, if you use it to load a JDBC driver, it won't get registered, and you won't be able to use JDBC!)
Suppose you are coding a web application that will be executed on a container such as Tomcat. What Tomcat does is create a class loader for each web application (so that it can unload the webapps later and release memory -- you need a dedicated class loader for this to work!). In this situation, you can see that both calls will yield quite different results!
For more detailed (and authoritative) information on class loading and initialization, check sections 12.2 and 12.4 of the latest (3rd) edition of the Java Language Specification.
Class.forName() uses the caller's classloader and initializes the class (runs static intitializers, etc.)
loadClass is a ClassLoader method, so it uses an explicitly-provided loader, and initializes the class lazily (on first use).
Note that there's a Class.forName() that also takes a ClassLoader.
Class.forName() load and initialize the class. In class loader subsystem it executes all the three phases i.e. load, link, and initialize phases.
ClassLoader.loadClass() behavior, which delays initialization until the class is used for the first time. In class loader subsystem it executes only two phases i.e. load and link phases.
For example:
class MyClass {
static {
System.out.println("static block in MyClass");
}
}
public class TestCase1 {
public static void main(String... args) throws Throwable {
Class.forName("A");
}
} //The above TestCase1 produce output: static block in MyClass
public class TestCase2 {
public static void main(String... args) throws Throwable {
ClassLoader.getSystemClassLoader().loadClass("MyClass");
}
} //The above TestCase2 not produce any output
They are basically doing the same thing. The ClassLoader used may be different though. Class.forName uses the ClassLoader you get from this.getClass().getClassLoader() whereas your other code specifies to use the system class loader.
In most applications this will be the same class loader but in more complicated environments such as a J2EE app or an applet this may not be the case.
ClassLoader is an abstract class, however your application is always loaded by a classloader, there could be custom class loaders such as network classloader or any other source.
On the other hand Class in itself represents classes and interfaces and the class Class has a forName function that uses the current class loader in which your application is running by default to load the class.
Here is the source for the Class.forName which in turn invokes the calling classloader.
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#forName(java.lang.String)
Hint: Primordial class loader
http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html
I love Class loading in java...
It really depends on what context the application is being run in. You will get different results if you are using it from a web context as opposed to just a command line program.
I've also run into problems depending on what your ClassPath looks like and what I was expecting to happen.
This JavaWorld article explains a good deal about it.
We are extending our java application to support plugins. Part of that includes keeping plugins isolated from our own classes, thus each plugin will live in it's own class loader.
We also plan on giving the plugins a java framework to work with, thus it'll have to be exposed to the plugins. This java framework also contains classes that will need to be accessible from our own java code, therefore it will have to also be accessible to our own java code.
The problem is that if the java framework lives in the system class loader (where our own java code lives), we can't give plugins the isolation we want. If we choose to separate the java framework to a different class loader and use that one as the parent of the plugins class loader, the java framework won't be visible to our own classes.
The current solution I had in mind was to implement a filtering class loader. The java framework will live in the system class loader, but this class loader will filter everything from the system class loader, except for the java framework and I'll use this class loader as the parent class loader of the plugins.
Here's a rough implementation of it:
public class FilteringClassLoader extends ClassLoader {
private URLClassLoader _internalLoader;
public FilteringClassLoader(ClassLoader parent) {
super(parent);
// load our java framework to this class loader
_internalLoader = new URLClassLoader(...)
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
// first, try to load from our internal class loader
// that only sees the java framework if that works, load the class
// from the system class loader and return that. otherwise, the class
// should be filtered out and the call to loadClass will throw as expected
_internalLoader.loadClass(name);
Class<?> retClazz = super.loadClass(name);
return retClazz;
}
}
However this has several problems the way I see it:
Using a separate URLClassLoader only to see if the class should be filtered feels like a hack to me.
When a plugin loads a class, that class parent class loader will be the system class loader, which obviously defeats the whole purpose of what I'm trying to achieve.
How do you solve this kind of problem?
How do you solve this kind of problem?
The OSGi Alliance already did. The Wikipedia article on the OSGi framework might give you some ideas.
You might want to look at the source code of Eclipse, and see how they implemented plug in loading.
If we choose to separate the java framework to a different class loader and use that one as the parent of the plugins class loader, the java framework won't be visible to our own classes.
Put your code in a class loader that is a peer of the plugin class loader, both with the interface code class loader as parent.