I understand that java.lang.ClassLoader is generally the classloader I extend (when needed). Also, when I see the custom classloaders of tomcat, Jetty etc extend from java.lang.ClassLoader.
I'm curious to understand the purpose and usage of com.sun.org.apache.bcel.internal.util.ClassLoader.
Can someone help me understand it ?
com.sun.org.apache.bcel.internal is just a repackaging of Apache BCEL. In particular, the class we're interested in (ClassLoader) is documented here...
Drop in replacement for the standard class loader of the JVM. You can use it in conjunction with the JavaWrapper to dynamically modify/create classes as they're requested.
This class loader recognizes special requests in a distinct format, i.e., when the name of the requested class contains with "$$BCEL$$" it calls the createClass() method with that name (everything before the $$BCEL$$ is considered to be the package name. You can subclass the class loader and override that method. "Normal" classes class can be modified by overriding the modifyClass() method which is called just before defineClass().
judging by the "bcel" part of the package name that classloader doesnt just load classes, it alters the bytecode on the fly (see the bcel homepage).
edit: some more info on what they do with it can be found here : "BCEL is used internally by XSLTC to "compile" XSLT stylesheets into bytecodes for execution"
Related
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 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.
Does the Java Interpreter support an Autoloader-Function or a possibility to extend his "Looking for a class"-function?
In PHP there is a function called spl_autoload_register (see http://www.php.net/manual/en/function.spl-autoload-register.php for details ), which forces the interpreter to execute my own callback function when he is looking for a missing class. In my callback function I can include the file with the expected class.
The background-idea is that I'd like to switch dynamically between software-layers.
For example:
If class x_L2 exists in layer 2 then class x_L1 in the underlying layer 1 should be ignored. Actually I solved this issue with a general mirror class x, which have to inherit from the class in the highest available layer. But this way is error-prone when you have to maintain hundreds of classes.
Thanks in advance.
This can be done by using a different class loader such as URLClassLoader. Then, you would get your classes from this class loader with loadClass. Yes, it also supports local and remote resources.
You can write your own ClassLoader subclass, and use its loadClass() instead of the default one.
It seems you are trying to write a custom class loader ?
IBM has good documentation on that to help you on that.
Classes are identified by their package, as classes can be identified by namespaces in PHP.
In order to use a specific class, you can simply use a qualified name.
public mypackage.mysubpackage.Myclass myInstanceofMyClass;
Or you could import only the needed class :
import mypackage.mysubpackage.Myclass;
You cannot have a class having the same name as another class in the same package. That's a duplicate définition of a type. I am not aware of a callback function for inclusion.
I created a class "String" and placed that in package "java" [ actually i wanted to create java.lang to see which class is loaded by classLoader as
Once a class is loaded into a JVM, the
same class (I repeat, the same class)
will not be loaded again
quoted from oreilly ] . But that thing later, why on running this class i am getting
java.lang.SecurityException: Prohibited package name: java
For which security reason java is not allowing me to have a class in java package? What one could do if there will not be no such check?
User code is never allowed to put classes into one of the standard Java packages. That way, user code cannot access any package-private classes/methods/fields in the Java implementation. Some of those package-private objects allow access to JVM internals. (I'm thinking of SharedSecrets in particular.)
Firstly, these types of restrictions are in place to enforce the Java sandbox. That is, running untrusted code in a trusted environment. Such as running an applet from some site (that you don't necessarily trust), on your computer (the trusted environment) in your browser. The intent is to disallow untrusted code from gaining access to package-private stuff which could help it escape the sandbox.
Normally these restrictions are enforced by the SecurityManager, so they shouldn't happen when you run your own application on the command-line (unless you explicitly specify to use a SecurityManager). When you control the environment, you could just go and edit the String.class definition inside the rt.jar of your Java (and you can, technically anyway, not sure what licensing says). As I said the restrictions are normally in the SecurityManager, but this particular rule about java.* packages is in the ClassLoader class.
To answer your question: My guess is that java.* check is there because of
a) historic reasons
b) somewhere in the Java core there's a check on the name of the class, something like: All class that start with java.* get special treatment.
However, consider that even if you managed to create a class called java.lang.String, it would not be the same class as the java.lang.String defined by the Java core. It would just be a class with the exact same name. Class identity is more than just the name of the class, even though this can be tricky to perceive unless you really play with ClassLoaders.
So a class loaded by the application classloader in the package java.lang, would not have access to the core java.lang package-private stuff.
To illustrate this, try to create a class called javax.swing.JButton with a main method and execute it. You'll get a java.lang.NoSuchMethodError: main. That's because java finds the "real" JButton before your class, and the real JButton doesn't have a main method.
In a Java standalone application you might be able to go around this restriction by calling one of the private native defineClassx methods directly via use of reflection and setAccessible.
BTW: The core java.lang.String is guaranteed to be loaded before your code ever executes because it's referenced everywhere, you would not get there first with your user code. The JVM gets set up to a degree before ever even trying to load your class, let alone execute it.
You cannot have "java.*" package names. This is actually hard-coded in the Java core so you cannot even grant a security manager permission to work around it (cf. ClassLoader::preDefineClass(...))
java is a reserved package name. Only classes inside the JVM can reside in this package.
If anyone could write in the Java package, that could result in libraries arbitrarily replacing core Java classes by their own implementations. That could result in a lot of thinks, from breaking core Java features to execution of malicious code.
A program could bypass security measures if a program could override JVM core classes with trojan versions. For example, String is used practically everywhere.
From the ClassLoader.defineClass(..) javadoc:
...The specified class name cannot begin with " java. ", since all classes in the " java.* packages can only be defined by the bootstrap class loader
and
Throws: ... SecurityException - If an attempt is made to add this class to a package that contains classes that were signed by a different set of certificates than this class, or if the class name begins with " java. ".
Probably during refactoring/patch applying/etc. you have added to package name word 'java', which is usually a folder that contains packages.
So you could end with the structure:
src->main->java->java.com.yourpackage.name
It might also happens for test:
src->main->test->java->java.com.yourpackage.name
Verify it in your IDE and remove "java." part
An excerpt from java.lang.ClassLoader's preDefineClass method:
/* Determine protection domain, and check that:
- not define java.* class,
- signer of this class matches signers for the rest of the classes in
package.
*/
private ProtectionDomain preDefineClass(String name,
ProtectionDomain pd)
{
...
// Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
// relies on the fact that spoofing is impossible if a class has a name
// of the form "java.*"
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
name.substring(0, name.lastIndexOf('.')));
}
...
}
Please note that java.lang.ClassLoader is an abstract class, meaning that a subclass (say, SecureClassLoader) will actually implement it. However, the preDefineClass method is private, so it cannot be overridden by a subclass.
preDefineClass is called by the defineClass method, which is protected final. This means defineClass is accessible to subclasses and they can call it, but they won't be able to change its implementation.
It seems to be impossible to use javax.tools.ToolProvider from a custom classloader as required by Ant or Webstart: http://bugs.sun.com/view_bug.do?bug_id=6548428
javax.tools.ToolProvider.getSystemJavaCompiler() loads javax.tools.JavaCompiler into a URLClassLoader whose parent is the system classloader. The API does not seem to allow users to specify a parent classloader.
How can one use javax.tools.JavaCompiler from a custom classloader?
For example:
Ant loads MyParserTask
MyParserTask parses Java source-code
MyParserTask is loaded by AntClassLoader that delegates to the system classloader
javax.tools.JavaCompiler is loaded by URLClassLoader thast delegates to the system classloader
At a later point, MyParserTask invokes:
javax.tools.CompilationTask task = compiler.getTask(...);
com.sun.source.util.JavacTask javacTask = (com.sun.source.util.JavacTask) task;
javacTask.parse().next().accept(visitor, unused); // parsing happens here
Seeing how the two classes reside on separate classloaders, there doesn't seem to be a way for MyParserTask to interact with JavacTask without getting ClassCastException errors.
Any ideas?
I had exactly the same problem. I'm using a custom ant task to scan the AST for certain kinds of method invocations. My solution, which may not be appropriate for you, was to instantiate the compiler myself instead of using the ToolProvider.
I replaced
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
with
JavaCompiler compiler = (JavaCompiler)Class.forName("com.sun.tools.javac.api.JavacTool").newInstance();
This certainly isn't future proof or safe in all environments, but it is an option depending on your needs. If someone else has a better way around using ToolProvider in custom Ant tasks please share.
This problem frequently occurs with OSGi. Some people have come up with "bridge class loaders", see for example this article (which probably only bridges interfaces, not subclasses, so maybe you cannot use it directly).
If there are only a few methods you want to invoke on the "foreign" object, you can also get away with reflection:
javax.tools.CompilationTask task;
task.getClass().getMethod("someMethodInTheSubclassThatICannotSee").invoke("a");
Building on the reflection idea, maybe a scripting language is helpful, too (Groovy, Beanshell, JavaScript).
The simple answer is that the same class loaded by two different class loaders is a different type and never the twain shall be cross assignable. That's it. You have to have both classes use the same class loader to get the shared class.
This would usually be a result of violating the pre-emptive deferring of class loading to a ClassLoader's parent. Simply put, any class loader must first ask it's parent to load a class before it attempts to load it itself. Doing otherwise results in all sorts of "interesting" problems.
In your specific example, since A invoked B, it was B's class loader that failed to delegate to it's parent, since if A can see the target class, B's class loader did not need to load it, given that A invoked B and therefore A's class loader or some ancestor thereof loaded B.
I was having similar problems I had to load the tools.jar When I discovered that a sub class was not getting loaded. details in this link
https://stackoverflow.com/questions/14619179/webappclassloader-loadclass-cannot-find-class-at-runtime
As I mention this may not be a good solution as we are trying to tinker with the classloading through a program. found some notes here useful as well
http://easternlights-wisdomtree.blogspot.in/2013/02/classloading-blues-part1.html