aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2005-11-04 09:29:35 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2005-11-04 09:29:35 +0000
commit7696279d0e1cbf5021ad38fb7328f223b94c1031 (patch)
tree3c432f56c58ec4ee1fc9aaeb8318edc80d47254f
parenteb12cc5d6bcbc25ea70f678321693971a0bd921c (diff)
downloadjavassist-7696279d0e1cbf5021ad38fb7328f223b94c1031.tar.gz
javassist-7696279d0e1cbf5021ad38fb7328f223b94c1031.zip
changed the behavior of CtClass#getMethods(), getFields(), and getConstructors().
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@217 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
-rw-r--r--Readme.html3
-rw-r--r--sample/preproc/Assistant.java53
-rw-r--r--sample/preproc/Compiler.java352
-rw-r--r--sample/preproc/package.html14
-rw-r--r--src/main/javassist/CtClass.java32
-rw-r--r--src/main/javassist/CtClassType.java14
-rw-r--r--src/main/javassist/reflect/ClassMetaobject.java12
-rw-r--r--tutorial/tutorial.html7
8 files changed, 473 insertions, 14 deletions
diff --git a/Readme.html b/Readme.html
index 8cbfa2b9..5ecc3b3b 100644
--- a/Readme.html
+++ b/Readme.html
@@ -284,6 +284,9 @@ see javassist.Dump.
<p>- version 3.1
<ul>
+ <li>getFields(), getMethods(), and getConstructors() in CtClass
+ were changed to return non-private memebers instead of only
+ public members.
<li>getEnclosingClass() in javassist.CtClass was renamed
to getEnclosingMethod().
<li>toMethod() in javassist.CtConstructor has been implemented.
diff --git a/sample/preproc/Assistant.java b/sample/preproc/Assistant.java
new file mode 100644
index 00000000..81b93b25
--- /dev/null
+++ b/sample/preproc/Assistant.java
@@ -0,0 +1,53 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 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.
+ *
+ * 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 sample.preproc;
+
+import javassist.CtClass;
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+
+/**
+ * This is an interface for objects invoked by the
+ * Javassist preprocessor when the preprocessor encounters an annotated
+ * import declaration.
+ *
+ * @see sample.preproc.Compiler
+ */
+public interface Assistant {
+ /**
+ * Is called when the Javassist preprocessor encounters an
+ * import declaration annotated with the "by" keyword.
+ *
+ * <p>The original import declaration is replaced with new import
+ * declarations of classes returned by this method. For example,
+ * the following implementation does not change the original
+ * declaration:
+ *
+ * <ul><pre>
+ * public CtClass[] assist(ClassPool cp, String importname, String[] args) {
+ * return new CtClass[] { cp.get(importname) };
+ * }
+ * </pre></uL>
+ *
+ * @param cp class pool
+ * @param importname the class imported by the declaration
+ * @param args the parameters specified by the annotation
+ * @return the classes imported in the java source
+ * program produced by the preprocessor.
+ */
+ public CtClass[] assist(ClassPool cp, String importname,
+ String[] args) throws CannotCompileException;
+}
diff --git a/sample/preproc/Compiler.java b/sample/preproc/Compiler.java
new file mode 100644
index 00000000..5481c0fc
--- /dev/null
+++ b/sample/preproc/Compiler.java
@@ -0,0 +1,352 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 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.
+ *
+ * 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 sample.preproc;
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.util.Vector;
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.ClassPool;
+
+/**
+ * This is a preprocessor for Java source programs using annotated
+ * import declarations.
+ *
+ * <ul><pre>
+ * import <i>class-name</i> by <i>assistant-name</i> [(<i>arg1, arg2, ...</i>)]
+ * </pre></ul>
+ *
+ * <p>To process this annotation, run this class as follows:
+ *
+ * <ul><pre>
+ * java sample.preproc.Compiler sample.j
+ * </pre></ul>
+ *
+ * <p>This command produces <code>sample.java</code>, which only includes
+ * regular import declarations. Also, the Javassist program
+ * specified by <i>assistant-name</i> is executed so that it produces
+ * class files under the <code>./tmpjvst</code> directory. The class
+ * specified by <i>assistant-name</i> must implement
+ * <code>sample.preproc.Assistant</code>.
+ *
+ * @see sample.preproc.Assistant
+ */
+
+public class Compiler {
+ protected BufferedReader input;
+ protected BufferedWriter output;
+ protected ClassPool classPool;
+
+ /**
+ * Constructs a <code>Compiler</code> with a source file.
+ *
+ * @param inputname the name of the source file.
+ */
+ public Compiler(String inputname) throws CannotCompileException {
+ try {
+ input = new BufferedReader(new FileReader(inputname));
+ }
+ catch (IOException e) {
+ throw new CannotCompileException("cannot open: " + inputname);
+ }
+
+ String outputname = getOutputFilename(inputname);
+ if (outputname.equals(inputname))
+ throw new CannotCompileException("invalid source name: "
+ + inputname);
+
+ try {
+ output = new BufferedWriter(new FileWriter(outputname));
+ }
+ catch (IOException e) {
+ throw new CannotCompileException("cannot open: " + outputname);
+ }
+
+ classPool = ClassPool.getDefault();
+ }
+
+ /**
+ * Starts preprocessing.
+ */
+ public void process() throws IOException, CannotCompileException {
+ int c;
+ CommentSkipper reader = new CommentSkipper(input, output);
+ while ((c = reader.read()) != -1) {
+ output.write(c);
+ if (c == 'p') {
+ if (skipPackage(reader))
+ break;
+ }
+ else if (c == 'i')
+ readImport(reader);
+ else if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
+ break;
+ }
+
+ while ((c = input.read()) != -1)
+ output.write(c);
+
+ input.close();
+ output.close();
+ }
+
+ private boolean skipPackage(CommentSkipper reader) throws IOException {
+ int c;
+ c = reader.read();
+ output.write(c);
+ if (c != 'a')
+ return true;
+
+ while ((c = reader.read()) != -1) {
+ output.write(c);
+ if (c == ';')
+ break;
+ }
+
+ return false;
+ }
+
+ private void readImport(CommentSkipper reader)
+ throws IOException, CannotCompileException
+ {
+ int word[] = new int[5];
+ int c;
+ for (int i = 0; i < 5; ++i) {
+ word[i] = reader.read();
+ output.write(word[i]);
+ }
+
+ if (word[0] != 'm' || word[1] != 'p' || word[2] != 'o'
+ || word[3] != 'r' || word[4] != 't')
+ return; // syntax error?
+
+ c = skipSpaces(reader, ' ');
+ StringBuffer classbuf = new StringBuffer();
+ while (c != ' ' && c != '\t' && c != '\n' && c != '\r'
+ && c != ';' && c != -1) {
+ classbuf.append((char)c);
+ c = reader.read();
+ }
+
+ String importclass = classbuf.toString();
+ c = skipSpaces(reader, c);
+ if (c == ';') {
+ output.write(importclass);
+ output.write(';');
+ return;
+ }
+ if (c != 'b')
+ syntaxError(importclass);
+
+ reader.read(); // skip 'y'
+
+ StringBuffer assistant = new StringBuffer();
+ Vector args = new Vector();
+ c = readAssistant(reader, importclass, assistant, args);
+ c = skipSpaces(reader, c);
+ if (c != ';')
+ syntaxError(importclass);
+
+ runAssistant(importclass, assistant.toString(), args);
+ }
+
+ void syntaxError(String importclass) throws CannotCompileException {
+ throw new CannotCompileException("Syntax error. Cannot import "
+ + importclass);
+ }
+
+ int readAssistant(CommentSkipper reader, String importclass,
+ StringBuffer assistant, Vector args)
+ throws IOException, CannotCompileException
+ {
+ int c = readArgument(reader, assistant);
+ c = skipSpaces(reader, c);
+ if (c == '(') {
+ do {
+ StringBuffer arg = new StringBuffer();
+ c = readArgument(reader, arg);
+ args.addElement(arg.toString());
+ c = skipSpaces(reader, c);
+ } while (c == ',');
+
+ if (c != ')')
+ syntaxError(importclass);
+
+ return reader.read();
+ }
+
+ return c;
+ }
+
+ int readArgument(CommentSkipper reader, StringBuffer buf)
+ throws IOException
+ {
+ int c = skipSpaces(reader, ' ');
+ while ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+ || '0' <= c && c <= '9' || c == '.' || c == '_') {
+ buf.append((char)c);
+ c = reader.read();
+ }
+
+ return c;
+ }
+
+ int skipSpaces(CommentSkipper reader, int c) throws IOException {
+ while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
+ if (c == '\n' || c == '\r')
+ output.write(c);
+
+ c = reader.read();
+ }
+
+ return c;
+ }
+
+ /**
+ * Is invoked if this compiler encoutenrs:
+ *
+ * <ul><pre>
+ * import <i>class name</i> by <i>assistant</i> (<i>args1</i>, <i>args2</i>, ...);
+ * </pre></ul>
+ *
+ * @param classname class name
+ * @param assistantname assistant
+ * @param argv args1, args2, ...
+ */
+ private void runAssistant(String importname, String assistantname,
+ Vector argv)
+ throws IOException, CannotCompileException
+ {
+ Class assistant;
+ Assistant a;
+ int s = argv.size();
+ String[] args = new String[s];
+ for (int i = 0; i < s; ++i)
+ args[i] = (String)argv.elementAt(i);
+
+ try {
+ assistant = Class.forName(assistantname);
+ }
+ catch (ClassNotFoundException e) {
+ throw new CannotCompileException("Cannot find " + assistantname);
+ }
+
+ try {
+ a = (Assistant)assistant.newInstance();
+ }
+ catch (Exception e) {
+ throw new CannotCompileException(e);
+ }
+
+ CtClass[] imports = a.assist(classPool, importname, args);
+ s = imports.length;
+ if (s < 1)
+ output.write(" java.lang.Object;");
+ else {
+ output.write(' ');
+ output.write(imports[0].getName());
+ output.write(';');
+ for (int i = 1; i < s; ++i) {
+ output.write(" import ");
+ output.write(imports[1].getName());
+ output.write(';');
+ }
+ }
+ }
+
+ private String getOutputFilename(String input) {
+ int i = input.lastIndexOf('.');
+ if (i < 0)
+ i = input.length();
+
+ return input.substring(0, i) + ".java";
+ }
+
+ public static void main(String[] args) {
+ if (args.length > 0)
+ try {
+ Compiler c = new Compiler(args[0]);
+ c.process();
+ }
+ catch (IOException e) {
+ System.err.println(e);
+ }
+ catch (CannotCompileException e) {
+ System.err.println(e);
+ }
+ else {
+ System.err.println("Javassist version " + CtClass.version);
+ System.err.println("No source file is specified.");
+ }
+ }
+}
+
+class CommentSkipper {
+ private BufferedReader input;
+ private BufferedWriter output;
+
+ public CommentSkipper(BufferedReader reader, BufferedWriter writer) {
+ input = reader;
+ output = writer;
+ }
+
+ public int read() throws IOException {
+ int c;
+ while ((c = input.read()) != -1)
+ if (c != '/')
+ return c;
+ else {
+ c = input.read();
+ if (c == '/')
+ skipCxxComments();
+ else if (c == '*')
+ skipCComments();
+ else
+ output.write('/');
+ }
+
+ return c;
+ }
+
+ private void skipCxxComments() throws IOException {
+ int c;
+ output.write("//");
+ while ((c = input.read()) != -1) {
+ output.write(c);
+ if (c == '\n' || c == '\r')
+ break;
+ }
+ }
+
+ private void skipCComments() throws IOException {
+ int c;
+ boolean star = false;
+ output.write("/*");
+ while ((c = input.read()) != -1) {
+ output.write(c);
+ if (c == '*')
+ star = true;
+ else if(star && c == '/')
+ break;
+ else
+ star = false;
+ }
+ }
+}
diff --git a/sample/preproc/package.html b/sample/preproc/package.html
new file mode 100644
index 00000000..dee15e02
--- /dev/null
+++ b/sample/preproc/package.html
@@ -0,0 +1,14 @@
+<html>
+<body>
+A sample preprocessor.
+
+<p>The preprocessor for running Javassist at compile time.
+The produced class files are saved on a local disk.
+
+<p>This package is provided as a sample implementation of the
+preprocessor using Javassist. All the programs in this package
+uses only the regular Javassist API; they never call any hidden
+methods.
+
+</body>
+</html>
diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java
index c0962808..55f81b81 100644
--- a/src/main/javassist/CtClass.java
+++ b/src/main/javassist/CtClass.java
@@ -582,8 +582,8 @@ public abstract class CtClass {
/**
* Returns an array containing <code>CtField</code> objects
- * representing all the public fields of the class.
- * That array includes public fields inherited from the
+ * representing all the non-private fields of the class.
+ * That array includes non-private fields inherited from the
* superclasses.
*/
public CtField[] getFields() { return new CtField[0]; }
@@ -628,7 +628,7 @@ public abstract class CtClass {
/**
* Returns an array containing <code>CtConstructor</code> objects
- * representing all the public constructors of the class.
+ * representing all the non-private constructors of the class.
*/
public CtConstructor[] getConstructors() {
return new CtConstructor[0];
@@ -686,8 +686,8 @@ public abstract class CtClass {
/**
* Returns an array containing <code>CtMethod</code> objects
- * representing all the public methods of the class.
- * That array includes public methods inherited from the
+ * representing all the non-private methods of the class.
+ * That array includes pon-private methods inherited from the
* superclasses.
*/
public CtMethod[] getMethods() {
@@ -1043,12 +1043,13 @@ public abstract class CtClass {
* is on by default. Otherwise, it is off.
*
* @param stop disallow pruning if true. Otherwise, allow.
+ * @return the previous status of pruning. true if pruning is already stopped.
*
* @see #detach()
* @see #prune()
* @see ClassPool#doPruning
*/
- public void stopPruning(boolean stop) {}
+ public boolean stopPruning(boolean stop) { return true; }
/**
* Discards unnecessary attributes, in particuar,
@@ -1144,6 +1145,25 @@ public abstract class CtClass {
}
}
+ /**
+ * Writes a class file as <code>writeFile()</code> does although this
+ * method does not prune or freeze the class after writing the class
+ * file. Note that, once <code>writeFile()</code> or <code>toBytecode()</code>
+ * is called, it cannot be called again since the class is pruned and frozen.
+ * This method would be useful for debugging.
+ */
+ public void debugWriteFile() {
+ try {
+ boolean p = stopPruning(true);
+ writeFile();
+ defrost();
+ stopPruning(p);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
static class DelayedFileOutputStream extends OutputStream {
private FileOutputStream file;
private String filename;
diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java
index 8d8e67d1..46fb268a 100644
--- a/src/main/javassist/CtClassType.java
+++ b/src/main/javassist/CtClassType.java
@@ -564,7 +564,7 @@ class CtClassType extends CtClass {
CtMember cf = ((CtClassType)cc).getFieldsCache();
while (cf != null) {
- if (Modifier.isPublic(cf.getModifiers()))
+ if (!Modifier.isPrivate(cf.getModifiers()))
alist.add(cf);
cf = cf.next;
@@ -680,7 +680,7 @@ class CtClassType extends CtClass {
int n = 0;
int i = cons.length;
while (--i >= 0)
- if (Modifier.isPublic(cons[i].getModifiers()))
+ if (!Modifier.isPrivate(cons[i].getModifiers()))
++n;
CtConstructor[] result = new CtConstructor[n];
@@ -688,7 +688,7 @@ class CtClassType extends CtClass {
i = cons.length;
while (--i >= 0) {
CtConstructor c = cons[i];
- if (Modifier.isPublic(c.getModifiers()))
+ if (!Modifier.isPrivate(c.getModifiers()))
result[n++] = c;
}
@@ -756,7 +756,7 @@ class CtClassType extends CtClass {
public CtMethod[] getMethods() {
HashMap h = new HashMap();
getMethods0(h, this);
- return (CtMethod[])h.values().toArray(new CtMethod[0]);
+ return (CtMethod[])h.values().toArray(new CtMethod[h.size()]);
}
private static void getMethods0(HashMap h, CtClass cc) {
@@ -778,7 +778,7 @@ class CtClassType extends CtClass {
if (cc instanceof CtClassType) {
CtMember cm = ((CtClassType)cc).getMethodsCache();
while (cm != null) {
- if (Modifier.isPublic(cm.getModifiers()))
+ if (!Modifier.isPrivate(cm.getModifiers()))
h.put(((CtMethod)cm).getStringRep(), cm);
cm = cm.next;
@@ -1120,8 +1120,10 @@ class CtClassType extends CtClass {
+ " was pruned.");
}
- public void stopPruning(boolean stop) {
+ public boolean stopPruning(boolean stop) {
+ boolean prev = !doPruning;
doPruning = !stop;
+ return prev;
}
private void modifyClassConstructor(ClassFile cf)
diff --git a/src/main/javassist/reflect/ClassMetaobject.java b/src/main/javassist/reflect/ClassMetaobject.java
index bfbc3f48..61328452 100644
--- a/src/main/javassist/reflect/ClassMetaobject.java
+++ b/src/main/javassist/reflect/ClassMetaobject.java
@@ -251,7 +251,8 @@ public class ClassMetaobject implements Serializable {
Class baseclass = getJavaClass();
Method[] allmethods = baseclass.getDeclaredMethods();
int n = allmethods.length;
- methods = new Method[n];
+ int[] index = new int[n];
+ int max = 0;
for (int i = 0; i < n; ++i) {
Method m = allmethods[i];
String mname = m.getName();
@@ -265,10 +266,17 @@ public class ClassMetaobject implements Serializable {
break;
}
- methods[k] = m;
+ index[i] = ++k;
+ if (k > max)
+ max = k;
}
}
+ methods = new Method[max];
+ for (int i = 0; i < n; ++i)
+ if (index[i] > 0)
+ methods[index[i] - 1] = allmethods[i];
+
return methods;
}
diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html
index 271e88de..9644016a 100644
--- a/tutorial/tutorial.html
+++ b/tutorial/tutorial.html
@@ -177,6 +177,13 @@ cc.setSuperclass(...); // OK since the class is not frozen.
<p>To disallow pruning for all the <code>CtClass</code>es, set
<code>ClassPool.doPruning</code> to <code>false</code>.
+<ul><b>Note:</b>
+While debugging, you might want to temporarily stop pruning and write a modified
+class file to a disk drive. <code>debugWriteFile()</code> is a convenient method
+for that purpose. It stops pruning, write a class file, defrost it, and turn
+pruning on again (if it was initially on).
+</ul>
+
<h4>Class search path</h4>
<p>The default <code>ClassPool</code> returned