aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/Loader.java
diff options
context:
space:
mode:
authorpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-04-22 13:47:06 +0000
committerpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-04-22 13:47:06 +0000
commit069bceaf72fd0d6ffad14ce4e3e00ca91a280bde (patch)
treeb8230a15d3061c64d5a64bf9efa654d0d6311ff2 /src/main/javassist/Loader.java
parentf610083ba0adbcb3fe92a504015fb26fb5a42530 (diff)
downloadjavassist-069bceaf72fd0d6ffad14ce4e3e00ca91a280bde.tar.gz
javassist-069bceaf72fd0d6ffad14ce4e3e00ca91a280bde.zip
This commit was generated by cvs2svn to compensate for changes in r2, which
included commits to RCS files with non-trunk default branches. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@6 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/Loader.java')
-rw-r--r--src/main/javassist/Loader.java340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/main/javassist/Loader.java b/src/main/javassist/Loader.java
new file mode 100644
index 00000000..948d3de9
--- /dev/null
+++ b/src/main/javassist/Loader.java
@@ -0,0 +1,340 @@
+/*
+ * This file is part of the Javassist toolkit.
+ *
+ * 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. You may obtain a copy of the License at
+ * either http://www.mozilla.org/MPL/.
+ *
+ * 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.
+ *
+ * The Original Code is Javassist.
+ *
+ * The Initial Developer of the Original Code is Shigeru Chiba. Portions
+ * created by Shigeru Chiba are Copyright (C) 1999-2003 Shigeru Chiba.
+ * All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * The development of this software is supported in part by the PRESTO
+ * program (Sakigake Kenkyu 21) of Japan Science and Technology Corporation.
+ */
+
+package javassist;
+
+import java.io.*;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * The class loader for Javassist (JDK 1.2 or later only).
+ *
+ * <p>This is a sample class loader using <code>ClassPool</code>.
+ * Unlike a regular class loader, this class loader obtains bytecode
+ * from a <code>ClassPool</code>.
+ *
+ * <p>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.
+ *
+ * <p>Suppose that an instance of <code>MyTranslator</code> implementing
+ * the interface <code>Translator</code> is responsible for modifying
+ * class files.
+ * The startup program of an application using <code>MyTranslator</code>
+ * should be something like this:
+ *
+ * <ul><pre>
+ * import javassist.*;
+ *
+ * public class Main {
+ * public static void main(String[] args) throws Throwable {
+ * MyTranslator myTrans = new MyTranslator();
+ * ClassPool cp = ClassPool.getDefault(myTrans);
+ * Loader cl = new Loader(cp);
+ * cl.run("MyApp", args);
+ * }
+ * }
+ * </pre></ul>
+ *
+ * <p>Class <code>MyApp</code> is the main program of the application.
+ *
+ * <p>This program should be executed as follows:
+ *
+ * <ul><pre>
+ * % java Main <i>arg1</i> <i>arg2</i>...
+ * </pre></ul>
+ *
+ * <p>It modifies the class <code>MyApp</code> with a <code>MyTranslator</code>
+ * object before loading it into the JVM.
+ * Then it calls <code>main()</code> in <code>MyApp</code> with arguments
+ * <i>arg1</i>, <i>arg2</i>, ...
+ *
+ * <p>This program execution is equivalent to:
+ *
+ * <ul><pre>
+ * % java MyApp <i>arg1</i> <i>arg2</i>...
+ * </pre></ul>
+ *
+ * <p>except that classes are translated by <code>MyTranslator</code>
+ * at load time.
+ *
+ * <p>If only a particular class is modified when it is loaded,
+ * a program like the following can be used:
+ *
+ * <ul><pre>ClassPool cp = ClassPool.getDefault();
+ * Loader cl = new Loader(cp);
+ *
+ * CtClass ct = cp.get("test.Rectangle");
+ * ct.setSuperclass(loader.get("test.Point"));
+ *
+ * Class c = cl.loadClass("test.Rectangle");
+ * Object rect = c.newInstance();</pre></ul>
+ *
+ * <p>This program modifies the super class of the <code>Rectangle</code>
+ * class and loads it into the JVM with a class loader <code>cl</code>.
+ *
+ * <p><b>Note 1:</b>
+ *
+ * <p>This class loader does not allow the users to intercept the loading
+ * of <code>java.*</code> and <code>javax.*</code> classes unless
+ * <code>Loader.doDelegation</code> is <code>false</code>. Also see
+ * Note 2.
+ *
+ * <p><b>Note 2:</b>
+ *
+ * <p>If classes are loaded with different class loaders, they belong to
+ * separate name spaces. If class <code>C</code> is loaded by a class
+ * loader <code>CL</code>, all classes that the class <code>C</code>
+ * refers to are also loaded by <code>CL</code>. However, if <code>CL</code>
+ * delegates the loading of the class <code>C</code> to <code>CL'</code>,
+ * then those classes that the class <code>C</code> refers to
+ * are loaded by a parent class loader <code>CL'</code>
+ * instead of <code>CL</code>.
+ *
+ * <p>If an object of class <code>C</code> is assigned
+ * to a variable of class <code>C</code> belonging to a different name
+ * space, then a <code>ClassCastException</code> is thrown.
+ *
+ * <p>Because of the fact above, this loader delegates only the loading of
+ * <code>javassist.Loader</code>
+ * and classes included in package <code>java.*</code> and
+ * <code>javax.*</code> to the parent class
+ * loader. Other classes are directly loaded by this loader.
+ *
+ * <p>For example, suppose that <code>java.lang.String</code> would be loaded
+ * by this loader while <code>java.io.File</code> is loaded by the parent
+ * class loader. If the constructor of <code>java.io.File</code> is called
+ * with an instance of <code>java.lang.String</code>, then it may throw
+ * an exception since it accepts an instance of only the
+ * <code>java.lang.String</code> loaded by the parent class loader.
+ *
+ * @see javassist.ClassPool
+ * @see javassist.Translator
+ */
+public class Loader extends ClassLoader {
+ private Hashtable notDefinedHere; // must be atomic.
+ private Vector notDefinedPackages; // must be atomic.
+ private ClassPool source;
+
+ /**
+ * Specifies the algorithm of class loading.
+ *
+ * <p>This class loader uses the parent class loader for
+ * <code>java.*</code> and <code>javax.*</code> classes.
+ * If this variable <code>doDelegation</code>
+ * is <code>false</code>, this class loader does not delegate those
+ * classes to the parent class loader.
+ *
+ * <p>The default value is <code>true</code>.
+ */
+ 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) {
+ notDefinedHere = new Hashtable();
+ notDefinedPackages = new Vector();
+ source = cp;
+ delegateLoadingOf("javassist.Loader");
+ }
+
+ /**
+ * Records a class so that the loading of that class is delegated
+ * to the parent class loader.
+ *
+ * <p>If the given class name ends with <code>.</code> (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 soruce <code>ClassPool</code>.
+ */
+ public void setClassPool(ClassPool cp) {
+ source = cp;
+ }
+
+ /**
+ * Loads a class with an instance of <code>Loader</code>
+ * and calls <code>main()</code> of that class.
+ *
+ * <p>This method calls <code>run()</code>.
+ *
+ * @param args[0] class name to be loaded.
+ * @param args[1-n] parameters passed to <code>main()</code>.
+ *
+ * @see javassist.Loader#run(String[])
+ */
+ public static void main(String[] args) throws Throwable {
+ Loader cl = new Loader();
+ cl.run(args);
+ }
+
+ /**
+ * Loads a class and calls <code>main()</code> in that class.
+ *
+ * @param args[0] the name of the loaded class.
+ * @param args[1-n] parameters passed to <code>main()</code>.
+ */
+ public void run(String[] args) throws Throwable {
+ int n = args.length - 1;
+ if (n >= 0) {
+ String[] args2 = new String[n];
+ for (int i = 0; i < n; ++i)
+ args2[i] = args[i + 1];
+
+ run(args[0], args2);
+ }
+ }
+
+ /**
+ * Loads a class and calls <code>main()</code> in that class.
+ *
+ * @param classname the loaded class.
+ * @param args parameters passed to <code>main()</code>.
+ */
+ 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 (java.lang.reflect.InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ }
+
+ /**
+ * Requests the class loader to load a class.
+ */
+ protected Class loadClass(String name, boolean resolve)
+ throws ClassFormatError, ClassNotFoundException
+ {
+ 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 <code>ClassPath</code>.
+ * If the source throws an exception, this returns null.
+ *
+ * <p>This method can be overridden by a subclass of
+ * <code>Loader</code>.
+ */
+ protected Class findClass(String name) {
+ byte[] classfile;
+ try {
+ if (source != null)
+ classfile = source.write(name);
+ else {
+ String jarname = "/" + name.replace('.', '/') + ".class";
+ InputStream in = this.getClass().getResourceAsStream(jarname);
+
+ classfile = ClassPoolTail.readStream(in);
+ }
+ }
+ catch (Exception e) {
+ return null;
+ }
+
+ return defineClass(name, classfile, 0, classfile.length);
+ }
+
+ private 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.")
+ || notDelegated(name))
+ c = delegateToParent(name);
+
+ return c;
+ }
+
+ private boolean notDelegated(String name) {
+ if (notDefinedHere.get(name) != null)
+ return true;
+
+ int n = notDefinedPackages.size();
+ for (int i = 0; i < n; ++i)
+ if (name.startsWith((String)notDefinedPackages.elementAt(i)))
+ return true;
+
+ return false;
+ }
+
+ private Class delegateToParent(String classname)
+ throws ClassNotFoundException
+ {
+ ClassLoader cl = getParent();
+ if (cl != null)
+ return cl.loadClass(classname);
+ else
+ return findSystemClass(classname);
+ }
+}