All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.Loader Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.3.0
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Vector;

/**
 * The class loader for Javassist.
 *
 * 

* This is a sample class loader using ClassPool. * Unlike a regular class loader, this class loader obtains bytecode * from a ClassPool. * *

* Note that Javassist can be used without this class loader; programmers * can define their own versions of class loader. They can run * a program even without any user-defined class loader if that program * is statically translated with Javassist. * This class loader is just provided as a utility class. * *

* Suppose that an instance of MyTranslator implementing * the interface Translator is responsible for modifying * class files. * The startup program of an application using MyTranslator * should be something like this: * *

 * import javassist.*;
 *
 * public class Main{
 * 
 *     public static void main(String[] args) throws Throwable{
 *         MyTranslator myTrans = new MyTranslator();
 *         ClassPool cp = ClassPool.getDefault();
 *         Loader cl = new Loader(cp);
 *         cl.addTranslator(cp, myTrans);
 *         cl.run("MyApp", args);
 *     }
 * }
 * 
* *

* Class MyApp is the main program of the application. * *

* This program should be executed as follows: * *

 * % java Main arg1 arg2...
 * 
* *

* It modifies the class MyApp with a MyTranslator * object before the JVM loads it. * Then it calls main() in MyApp with arguments * arg1, arg2, ... * *

* This program execution is equivalent to: * *

 * % java MyApp arg1 arg2...
 * 
* *

* except that classes are translated by MyTranslator * at load time. * *

* If only a particular class must be modified when it is loaded, * the startup program can be simpler; MyTranslator is * unnecessary. For example, if only a class test.Rectangle * is modified, the main() method above will be the following: * *

 * ClassPool cp = ClassPool.getDefault();
 * Loader cl = new Loader(cp);
 * CtClass ct = cp.get("test.Rectangle");
 * ct.setSuperclass(cp.get("test.Point"));
 * cl.run("MyApp", args);
 * 
* *

* This program changes the super class of the test.Rectangle * class. * *

* Note 1: * *

* This class loader does not allow the users to intercept the loading * of java.* and javax.* classes (and * sun.*, org.xml.*, ...) unless * Loader.doDelegation is false. This is because * the JVM prohibits a user class loader from loading a system class. * Also see Note 2. * If this behavior is not appropriate, a subclass of Loader * must be defined and loadClassByDelegation() must be overridden. * *

* Note 2: * *

* If classes are loaded with different class loaders, they belong to * separate name spaces. If class C is loaded by a class * loader CL, all classes that the class C * refers to are also loaded by CL. However, if CL * delegates the loading of the class C to CL', * then those classes that the class C refers to * are loaded by a parent class loader CL' * instead of CL. * *

* If an object of class C is assigned * to a variable of class C belonging to a different name * space, then a ClassCastException is thrown. * *

* Because of the fact above, this loader delegates only the loading of * javassist.Loader * and classes included in package java.* and * javax.* to the parent class * loader. Other classes are directly loaded by this loader. * *

* For example, suppose that java.lang.String would be loaded * by this loader while java.io.File is loaded by the parent * class loader. If the constructor of java.io.File is called * with an instance of java.lang.String, then it may throw * an exception since it accepts an instance of only the * java.lang.String loaded by the parent class loader. * * @see com.feilong.lib.javassist.ClassPool * @see com.feilong.lib.javassist.Translator */ public class Loader extends ClassLoader{ /** * A simpler class loader. * This is a class loader that exposes the protected {@code defineClass()} method * declared in {@code java.lang.ClassLoader}. It provides a method similar to * {@code CtClass#toClass()}. * *

* When loading a class, this class loader delegates the work to the * parent class loader unless the loaded classes are explicitly given * by {@link #invokeDefineClass(CtClass)}. * Note that a class {@code Foo} loaded by this class loader is * different from the class with the same name {@code Foo} but loaded by * another class loader. This is Java's naming rule. *

* * @since 3.24 */ public static class Simple extends ClassLoader{ /** * Constructs a class loader. */ public Simple(){ } /** * Constructs a class loader. * * @param parent * the parent class loader. */ public Simple(ClassLoader parent){ super(parent); } /** * Invokes the protected {@code defineClass()} in {@code ClassLoader}. * It converts the given {@link CtClass} object into a {@code java.lang.Class} object. */ public Class invokeDefineClass(CtClass cc) throws IOException,CannotCompileException{ byte[] code = cc.toBytecode(); return defineClass(cc.getName(), code, 0, code.length); } } private HashMap notDefinedHere; // must be atomic. private Vector notDefinedPackages; // must be atomic. private ClassPool source; private Translator translator; private ProtectionDomain domain; /** * Specifies the algorithm of class loading. * *

* This class loader uses the parent class loader for * java.* and javax.* classes. * If this variable doDelegation * is false, this class loader does not delegate those * classes to the parent class loader. * *

* The default value is true. */ public boolean doDelegation = true; /** * Creates a new class loader. */ public Loader(){ this(null); } /** * Creates a new class loader. * * @param cp * the source of class files. */ public Loader(ClassPool cp){ init(cp); } /** * Creates a new class loader * using the specified parent class loader for delegation. * * @param parent * the parent class loader. * @param cp * the source of class files. */ public Loader(ClassLoader parent, ClassPool cp){ super(parent); init(cp); } private void init(ClassPool cp){ notDefinedHere = new HashMap<>(); notDefinedPackages = new Vector<>(); source = cp; translator = null; domain = null; delegateLoadingOf(com.feilong.lib.javassist.Loader.class.getName()); } /** * Records a class so that the loading of that class is delegated * to the parent class loader. * *

* If the given class name ends with . (dot), then * that name is interpreted as a package name. All the classes * in that package and the sub packages are delegated. */ public void delegateLoadingOf(String classname){ if (classname.endsWith(".")){ notDefinedPackages.addElement(classname); }else{ notDefinedHere.put(classname, this); } } /** * Sets the protection domain for the classes handled by this class * loader. Without registering an appropriate protection domain, * the program loaded by this loader will not work with a security * manager or a signed jar file. */ public void setDomain(ProtectionDomain d){ domain = d; } /** * Sets the soruce ClassPool. */ public void setClassPool(ClassPool cp){ source = cp; } /** * Adds a translator, which is called whenever a class is loaded. * * @param cp * the ClassPool object for obtaining * a class file. * @param t * a translator. * @throws NotFoundException * if t.start() throws an exception. * @throws CannotCompileException * if t.start() throws an exception. */ public void addTranslator(ClassPool cp,Translator t) throws NotFoundException,CannotCompileException{ source = cp; translator = t; t.start(cp); } /** * Loads a class and calls main() in that class. * * @param args * command line parameters. * *
*   {@code args[0]} is the class name to be loaded. *
*   {@code args[1..n]} are parameters passed * to the target {@code main()}. */ public void run(String[] args) throws Throwable{ if (args.length >= 1){ run(args[0], Arrays.copyOfRange(args, 1, args.length)); } } /** * Loads a class and calls main() in that class. * * @param classname * the loaded class. * @param args * parameters passed to main(). */ public void run(String classname,String[] args) throws Throwable{ Class c = loadClass(classname); try{ c.getDeclaredMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { args }); }catch (InvocationTargetException e){ throw e.getTargetException(); } } /** * Requests the class loader to load a class. */ @Override protected Class loadClass(String name,boolean resolve) throws ClassFormatError,ClassNotFoundException{ name = name.intern(); synchronized (name){ Class c = findLoadedClass(name); if (c == null){ c = loadClassByDelegation(name); } if (c == null){ c = findClass(name); } if (c == null){ c = delegateToParent(name); } if (resolve){ resolveClass(c); } return c; } } /** * Finds the specified class using ClassPath. * If the source throws an exception, this returns null. * *

* This method can be overridden by a subclass of * Loader. Note that the overridden method must not throw * an exception when it just fails to find a class file. * * @return null if the specified class could not be found. * @throws ClassNotFoundException * if an exception is thrown while * obtaining a class file. */ @Override protected Class findClass(String name) throws ClassNotFoundException{ byte[] classfile; try{ if (source != null){ if (translator != null){ translator.onLoad(source, name); } try{ classfile = source.get(name).toBytecode(); }catch (NotFoundException e){ return null; } }else{ String jarname = "/" + name.replace('.', '/') + ".class"; InputStream in = this.getClass().getResourceAsStream(jarname); if (in == null){ return null; } classfile = ClassPoolTail.readStream(in); } }catch (Exception e){ throw new ClassNotFoundException("caught an exception while obtaining a class file for " + name, e); } int i = name.lastIndexOf('.'); if (i != -1){ String pname = name.substring(0, i); if (isDefinedPackage(pname)){ try{ definePackage(pname, null, null, null, null, null, null, null); }catch (IllegalArgumentException e){ // ignore. maybe the package object for the same // name has been created just right away. } } } if (domain == null){ return defineClass(name, classfile, 0, classfile.length); } return defineClass(name, classfile, 0, classfile.length, domain); } private boolean isDefinedPackage(String name){ return getPackage(name) == null; } protected Class loadClassByDelegation(String name) throws ClassNotFoundException{ /* * The swing components must be loaded by a system * class loader. * javax.swing.UIManager loads a (concrete) subclass * of LookAndFeel by a system class loader and cast * an instance of the class to LookAndFeel for * (maybe) a security reason. To avoid failure of * type conversion, LookAndFeel must not be loaded * by this class loader. */ Class c = null; if (doDelegation){ if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("sun.") || name.startsWith("com.sun.") || name.startsWith("org.w3c.") || name.startsWith("org.xml.") || notDelegated(name)){ c = delegateToParent(name); } } return c; } private boolean notDelegated(String name){ if (notDefinedHere.containsKey(name)){ return true; } for (String pack : notDefinedPackages){ if (name.startsWith(pack)){ return true; } } return false; } protected Class delegateToParent(String classname) throws ClassNotFoundException{ ClassLoader cl = getParent(); if (cl != null){ return cl.loadClass(classname); } return findSystemClass(classname); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy