From 4fda748aa5e0fcc4d0207169209062399fe2aa81 Mon Sep 17 00:00:00 2001 From: chiba Date: Mon, 30 Aug 2004 17:41:36 +0000 Subject: [PATCH] discarded the last changes git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@129 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- Readme.html | 5 +- src/main/javassist/compiler/CodeGen.java | 25 +- src/main/javassist/compiler/TypeChecker.java | 289 ++++--------------- tutorial/tutorial.html | 254 ++++++++++------ tutorial/tutorial2.html | 21 +- tutorial/tutorial3.html | 12 +- 6 files changed, 246 insertions(+), 360 deletions(-) diff --git a/Readme.html b/Readme.html index a1db7766..035bd6bd 100644 --- a/Readme.html +++ b/Readme.html @@ -262,6 +262,9 @@ see javassist.Dump. changed.
  • javassist.expr.NewArray has been implemented. It enables modifying an expression for array creation. +
  • .class notation has been supported. The modified class + file needs javassist.runtime.DotClass at runtime. +
  • a bug in CtClass.getMethods() has been fixed.

    - version 3.0 beta in May 18th, 2004. @@ -565,7 +568,7 @@ Andreas Salathe, Dante Torres estrada, S. Pam, Nuno Santos, Denis Taye, Colin Sampaleanu, Robert Bialek, Asato Shimotaki, Howard Lewis Ship, Richard Jones, Marjan Sterjev, Bruce McDonald, Mark Brennan, Vlad Skarzhevskyy, -Brett Randall, and Tsuyoshi Murakami +Brett Randall, Tsuyoshi Murakami, and Nathan Meyers for their contributions.


    diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java index 2c186eed..35d06817 100644 --- a/src/main/javassist/compiler/CodeGen.java +++ b/src/main/javassist/compiler/CodeGen.java @@ -199,28 +199,20 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { } public void compileExpr(ASTree expr) throws CompileError { - expr = doTypeCheck(expr); + doTypeCheck(expr); expr.accept(this); } public boolean compileBooleanExpr(boolean branchIf, ASTree expr) throws CompileError { - expr = doTypeCheck(expr); + doTypeCheck(expr); return booleanExpr(branchIf, expr); } - /* This returns a different expression from the given one - * if the given expression has been modified. - */ - private ASTree doTypeCheck(ASTree expr) throws CompileError { - if (typeChecker != null) { + public void doTypeCheck(ASTree expr) throws CompileError { + if (typeChecker != null) expr.accept(typeChecker); - ASTree expr2 = typeChecker.modifiedExpr; - return expr2 == null ? expr : expr2; - } - else - return expr; } public void atASTList(ASTList n) throws CompileError { fatal(); } @@ -308,7 +300,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int op = st.getOperator(); if (op == EXPR) { ASTree expr = st.getLeft(); - expr = doTypeCheck(expr); + doTypeCheck(expr); if (expr instanceof AssignExpr) atAssignExpr((AssignExpr)expr, false); else if (isPlusPlusExpr(expr)) { @@ -568,7 +560,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { */ ASTree init = d.getInitializer(); if (init != null) { - init = doTypeCheck(init); + doTypeCheck(init); atVariableAssign(null, '=', null, d, init, false); } } @@ -798,10 +790,13 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int k = lookupBinOp(token); if (k >= 0) { expr.oprand1().accept(this); + ASTree right = expr.oprand2(); + if (right == null) + return; // see TypeChecker.atBinExpr(). + int type1 = exprType; int dim1 = arrayDim; String cname1 = className; - ASTree right = expr.oprand2(); right.accept(this); if (dim1 != arrayDim) throw new CompileError("incompatible array types"); diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java index d57b95a5..196c7642 100644 --- a/src/main/javassist/compiler/TypeChecker.java +++ b/src/main/javassist/compiler/TypeChecker.java @@ -17,17 +17,11 @@ package javassist.compiler; import javassist.CtClass; import javassist.CtField; -import javassist.Modifier; import javassist.ClassPool; import javassist.NotFoundException; import javassist.compiler.ast.*; import javassist.bytecode.*; -/** - * This class does type checking and, if needed, transformes the original - * abstract syntax tree. The resulting tree is available from - * this.modifiedExpr. - */ public class TypeChecker extends Visitor implements Opcode, TokenId { static final String javaLangObject = "java.lang.Object"; static final String jvmJavaLangObject = "java/lang/Object"; @@ -40,7 +34,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ... protected int arrayDim; protected String className; // JVM-internal representation - protected ASTree modifiedExpr; // null if the given expr was not changed protected MemberResolver resolver; protected CtClass thisClass; @@ -105,7 +98,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { exprType = CLASS; arrayDim = 0; className = MemberResolver.javaToJvmName(cname); - modifiedExpr = null; } } @@ -117,12 +109,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { atMultiNewArray(type, classname, size); else { size.head().accept(this); - if (modifiedExpr != null) - size.setHead(modifiedExpr); - exprType = type; arrayDim = 1; - modifiedExpr = null; if (type == CLASS) className = resolveClassName(classname); else @@ -142,11 +130,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { ++count; s.accept(this); - if (modifiedExpr != null) - size.setHead(modifiedExpr); } - modifiedExpr = null; exprType = type; arrayDim = dim; if (type == CLASS) @@ -189,80 +174,49 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { int varArray = d.getArrayDim(); String varClass = d.getClassName(); - if (op != '=') { + if (op != '=') atVariable(var); - if (modifiedExpr != null) - expr.setOprand1(modifiedExpr); - } right.accept(this); - if (modifiedExpr != null) - expr.setOprand2(modifiedExpr); - exprType = varType; arrayDim = varArray; className = varClass; - modifiedExpr = null; } private void atArrayAssign(Expr expr, int op, Expr array, ASTree right) throws CompileError { - atArrayRead(array); - if (modifiedExpr != null) - expr.setOprand1(modifiedExpr); - + atArrayRead(array.oprand1(), array.oprand2()); int aType = exprType; int aDim = arrayDim; String cname = className; right.accept(this); - if (modifiedExpr != null) - expr.setOprand2(modifiedExpr); - exprType = aType; arrayDim = aDim; className = cname; - modifiedExpr = null; } protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right) throws CompileError { - CtField f = atFieldRead(left); + CtField f = fieldAccess(left); + atFieldRead(f); int fType = exprType; int fDim = arrayDim; String cname = className; - if (modifiedExpr != null) - expr.setOprand1(modifiedExpr); - - if (Modifier.isFinal(f.getModifiers())) - throw new CompileError("assignment to a final field"); - right.accept(this); - if (modifiedExpr != null) - expr.setOprand2(modifiedExpr); - exprType = fType; arrayDim = fDim; className = cname; - modifiedExpr = null; } public void atCondExpr(CondExpr expr) throws CompileError { booleanExpr(expr.condExpr()); - if (modifiedExpr != null) - expr.setCond(modifiedExpr); - expr.thenExpr().accept(this); - if (modifiedExpr != null) - expr.setThen(modifiedExpr); - int type1 = exprType; int dim1 = arrayDim; String cname1 = className; expr.elseExpr().accept(this); - if (modifiedExpr != null) - expr.setElse(modifiedExpr); if (dim1 == 0 && dim1 == arrayDim) if (CodeGen.rightIsStrong(type1, exprType)) @@ -271,89 +225,63 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); exprType = type1; } - - modifiedExpr = null; } public void atBinExpr(BinExpr expr) throws CompileError { int token = expr.getOperator(); int k = CodeGen.lookupBinOp(token); - if (k < 0) { - /* equation: &&, ||, ==, !=, <=, >=, <, > - */ - booleanExpr(expr); - } - else { + if (k >= 0) { /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>> */ - if (token != '+') - atNonPlusExpr(expr, token); - else { + if (token == '+') { Expr e = atPlusExpr(expr); if (e != null) { /* String concatenation has been translated into * an expression using StringBuffer. */ e = CallExpr.makeCall(Expr.make('.', e, - new Member("toString")), null); + new Member("toString")), null); + expr.setLeft(e); + expr.setOprand2(null); // <---- look at this! className = jvmJavaLangString; - modifiedExpr = e; // expr will be replaced with e. } } + else { + expr.oprand1().accept(this); + int type1 = exprType; + expr.oprand2().accept(this); + computeBinExprType(expr, token, type1); + } } - } - - private void atNonPlusExpr(BinExpr expr, int token) throws CompileError { - ASTree left = expr.oprand1(); - ASTree right = expr.oprand2(); - - left.accept(this); - if (modifiedExpr != null) { - left = modifiedExpr; - expr.setOprand1(left); - } - - int type1 = exprType; - right.accept(this); - if (modifiedExpr != null) { - right = modifiedExpr; - expr.setOprand2(right); + else { + /* equation: &&, ||, ==, !=, <=, >=, <, > + */ + booleanExpr(expr); } - - modifiedExpr = computeConstExpr(token, left, right); - computeBinExprType(expr, token, type1); } - /* This method deals with string concatenation. It converts a + - * expression on String such as: - * "value:" + i + "." - * into: - * new StringBuffer().append("value:").append(i).append(".") - * .toString() - * - * This method also inserts a cast operator for the right operand - * if needed. - * - * EXPR must be a + expression. - * - * atPlusExpr() returns null if the expression is not a string - * concatenation. - */ + // expr must be a + expression. private Expr atPlusExpr(BinExpr expr) throws CompileError { ASTree left = expr.oprand1(); ASTree right = expr.oprand2(); + if (right == null) { + /* this expression has been already type-checked since it is + string concatenation. + see atBinExpr() above. + */ + exprType = CLASS; + arrayDim = 0; + className = jvmJavaLangString; + return null; + } if (isPlusExpr(left)) { Expr newExpr = atPlusExpr((BinExpr)left); if (newExpr != null) { right.accept(this); - if (modifiedExpr != null) - right = modifiedExpr; - exprType = CLASS; arrayDim = 0; className = "java/lang/StringBuffer"; - modifiedExpr = null; return makeAppendCall(newExpr, right); } } @@ -363,37 +291,17 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { int type1 = exprType; int dim1 = arrayDim; String cname = className; - if (modifiedExpr != null) { - left = modifiedExpr; - expr.setOprand1(left); - } - right.accept(this); - if (modifiedExpr != null) { - right = modifiedExpr; - expr.setOprand2(right); - } - - modifiedExpr = computeConstExpr('+', left, right); if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) || (exprType == CLASS && arrayDim == 0 - && jvmJavaLangString.equals(className))) - { + && jvmJavaLangString.equals(className))) { + ASTList sbufClass = ASTList.make(new Symbol("java"), + new Symbol("lang"), new Symbol("StringBuffer")); + ASTree e = new NewExpr(sbufClass, null); exprType = CLASS; arrayDim = 0; - if (modifiedExpr != null) { - // this expression is constant. - className = jvmJavaLangString; - return null; - } - else { - className = "java/lang/StringBuffer"; - ASTList sbufClass = ASTList.make(new Symbol("java"), - new Symbol("lang"), - new Symbol("StringBuffer")); - ASTree e = new NewExpr(sbufClass, null); - return makeAppendCall(makeAppendCall(e, left), right); - } + className = "java/lang/StringBuffer"; + return makeAppendCall(makeAppendCall(e, left), right); } else { computeBinExprType(expr, '+', type1); @@ -428,54 +336,33 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { if (CodeGen.isP_INT(exprType)) exprType = INT; // type1 may be BYTE, ... - - arrayDim = 0; - // don't change the value of modifiedExpr. } private void booleanExpr(ASTree expr) throws CompileError { - ASTree modExpr = null; int op = CodeGen.getCompOperator(expr); if (op == EQ) { // ==, !=, ... BinExpr bexpr = (BinExpr)expr; bexpr.oprand1().accept(this); - if (modifiedExpr != null) - bexpr.setOprand1(modifiedExpr); - int type1 = exprType; int dim1 = arrayDim; bexpr.oprand2().accept(this); - if (modifiedExpr != null) - bexpr.setOprand2(modifiedExpr); - if (dim1 == 0 && arrayDim == 0) insertCast(bexpr, type1, exprType); } - else if (op == '!') { + else if (op == '!') ((Expr)expr).oprand1().accept(this); - if (modifiedExpr != null) - ((Expr)expr).setOprand1(modifiedExpr); - } else if (op == ANDAND || op == OROR) { BinExpr bexpr = (BinExpr)expr; bexpr.oprand1().accept(this); - if (modifiedExpr != null) - bexpr.setOprand1(modifiedExpr); - bexpr.oprand2().accept(this); - if (modifiedExpr != null) - bexpr.setOprand2(modifiedExpr); } - else { // others + else // others expr.accept(this); - modExpr = modifiedExpr; - } exprType = BOOLEAN; arrayDim = 0; - modifiedExpr = modExpr; } private void insertCast(BinExpr expr, int type1, int type2) @@ -487,37 +374,18 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { exprType = type1; } - private ASTree computeConstExpr(int op, ASTree left, ASTree right) { - if (left instanceof StringL && right instanceof StringL && op == '+') - return new StringL(((StringL)left).get() + ((StringL)right).get()); - else if (left instanceof IntConst) - return ((IntConst)left).compute(op, right); - else if (left instanceof DoubleConst) - return ((DoubleConst)left).compute(op, right); - else - return null; // not constant expression - } - public void atCastExpr(CastExpr expr) throws CompileError { String cname = resolveClassName(expr.getClassName()); expr.getOprand().accept(this); - if (modifiedExpr != null) - expr.setOprand(modifiedExpr); - exprType = expr.getType(); arrayDim = expr.getArrayDim(); className = cname; - modifiedExpr = null; } public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { expr.getOprand().accept(this); - if (modifiedExpr != null) - expr.setOprand(modifiedExpr); - exprType = BOOLEAN; arrayDim = 0; - modifiedExpr = null; } public void atExpr(Expr expr) throws CompileError { @@ -543,7 +411,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { atFieldRead(expr); } else if (token == ARRAY) - atArrayRead(expr); + atArrayRead(oprand, expr.oprand2()); else if (token == PLUSPLUS || token == MINUSMINUS) atPlusPlus(token, oprand, expr); else if (token == '!') @@ -551,40 +419,13 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { else if (token == CALL) // method call fatal(); else { - oprand.accept(this); - if (modifiedExpr != null) { - oprand = modifiedExpr; - expr.setOprand1(oprand); - } - - modifiedExpr = computeConstExpr(token, oprand); - if (token == '-' || token == '~') { + expr.oprand1().accept(this); + if (token == '-' || token == '~') if (CodeGen.isP_INT(exprType)) exprType = INT; // type may be BYTE, ... - } } } - private ASTree computeConstExpr(int op, ASTree oprand) { - if (oprand instanceof IntConst) { - IntConst c = (IntConst)oprand; - long v = c.get(); - if (op == '-') - v = -v; - else if (op == '~') - v = ~v; - - c.set(v); - } - else if (oprand instanceof DoubleConst) { - DoubleConst c = (DoubleConst)oprand; - if (op == '-') - c.set(-c.get()); - } - - return null; - } - public void atCallExpr(CallExpr expr) throws CompileError { String mname = null; CtClass targetClass = null; @@ -614,8 +455,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { ASTree target = e.oprand1(); try { target.accept(this); - if (modifiedExpr != null) - e.setOprand1(modifiedExpr); } catch (NoFieldException nfe) { if (nfe.getExpr() != target) @@ -643,7 +482,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { MemberResolver.Method minfo = atMethodCallCore(targetClass, mname, args); expr.setMethod(minfo); - modifiedExpr = null; } private static void badMethod() throws CompileError { @@ -651,8 +489,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } /** - * modifiedExpr is not set. - * * @return a pair of the class declaring the invoked method * and the MethodInfo of that method. Never null. */ @@ -695,9 +531,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { while (args != null) { ASTree a = args.head(); a.accept(this); - if (modifiedExpr != null) - args.setHead(modifiedExpr); - types[i] = exprType; dims[i] = arrayDim; cnames[i] = className; @@ -706,8 +539,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } } - /* modifiedExpr is not set. - */ void setReturnType(String desc) throws CompileError { int i = desc.indexOf(')'); if (i < 0) @@ -735,8 +566,11 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } } - private CtField atFieldRead(ASTree expr) throws CompileError { - CtField f = fieldAccess(expr); + private void atFieldRead(ASTree expr) throws CompileError { + atFieldRead(fieldAccess(expr)); + } + + private void atFieldRead(CtField f) throws CompileError { FieldInfo finfo = f.getFieldInfo2(); String type = finfo.getDescriptor(); @@ -755,9 +589,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { className = type.substring(i + 1, type.indexOf(';', i + 1)); else className = null; - - modifiedExpr = null; ?? - return f; } protected CtField fieldAccess(ASTree expr) throws CompileError { @@ -780,9 +611,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { else if (op == '.') try { e.oprand1().accept(this); - if (modifiedExpr != null) - e.setOprand1(modifiedExpr); - if (exprType == CLASS && arrayDim == 0) return resolver.lookupFieldByJvmName(className, (Symbol)e.oprand2()); @@ -808,38 +636,25 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { exprType = CLASS; arrayDim = 0; className =jvmJavaLangClass; - modifiedExpr = null; } public void atArrayLength(Expr expr) throws CompileError { expr.oprand1().accept(this); - if (modifiedExpr != null) - expr.setOprand1(modifiedExpr); - exprType = INT; arrayDim = 0; - modifiedExpr = null; } - public void atArrayRead(Expr expr) throws CompileError { - ASTree array = expr.oprand1(); + public void atArrayRead(ASTree array, ASTree index) + throws CompileError + { array.accept(this); - if (modifiedExpr != null) - expr.setOprand1(modifiedExpr); - int type = exprType; int dim = arrayDim; String cname = className; - - ASTree index = expr.oprand2(); index.accept(this); - if (modifiedExpr != null) - expr.setOprand2(modifiedExpr); - exprType = type; arrayDim = dim - 1; className = cname; - modifiedExpr = null; } private void atPlusPlus(int token, ASTree oprand, Expr expr) @@ -853,13 +668,12 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { Declarator d = ((Variable)oprand).getDeclarator(); exprType = d.getType(); arrayDim = d.getArrayDim(); - modifiedExpr = null; } else { if (oprand instanceof Expr) { Expr e = (Expr)oprand; if (e.getOperator() == ARRAY) { - atArrayRead(e); + atArrayRead(e.oprand1(), e.oprand2()); // arrayDim should be 0. int t = exprType; if (t == INT || t == BYTE || t == CHAR || t == SHORT) @@ -875,7 +689,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { protected void atFieldPlusPlus(ASTree oprand) throws CompileError { - atFieldRead(oprand); + CtField f = fieldAccess(oprand); + atFieldRead(f); int t = exprType; if (t == INT || t == BYTE || t == CHAR || t == SHORT) exprType = INT; diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html index 064f8da8..84de35b4 100644 --- a/tutorial/tutorial.html +++ b/tutorial/tutorial.html @@ -18,19 +18,18 @@ Shigeru Chiba

    Next page
    - + +

    Defining a new class

    + +

    To define a new class from scratch, makeClass() +must be called on a ClassPool. + +

      +ClassPool pool = ClassPool.getDefault();
      +CtClass cc = pool.makeClass("Point");
      +
    + +

    This program defines a class Point +including no members. + +

    Frozen classes

    + +

    If a CtClass object is converted into a class file by +writeFile(), toClass(), or +toBytecode(), Javassist freezes that CtClass +object. Further modifications of that CtClass object are +not permitted. + +

    When Javassist freezes a CtClass object, it also +prunes the data structure contained in that object. To reduce memory +consumption, Javassist discards some part of data structure, for +example, the data of method bodies. Thus, after a +CtClass object is pruned, the bytecode of a method is not +accessible although method names and signatures are accessible. + +

    To disallow pruning a CtClass, stopPruning() +must be called in advance: + +

      +CtClasss cc = ...;
      +cc.stopPruning(true);
      +    :
      +cc.writeFile();                             // convert to a class file.
      +// cc is not pruned.
      +
    + +

    If a CtClass is not pruned, it can be defrost so that +modifications of the class definition can be permitted. For example, + +

      +CtClasss cc = ...;
      +cc.stopPruning(true);
      +    :
      +cc.writeFile();
      +cc.defrost();
      +cc.setSuperclass(...);    // OK since the class is not frozen.
      +
    + +

    Class search path

    The default ClassPool returned @@ -187,21 +239,106 @@ included in the search path.


    -
    -

    2. Defining a new class

    + +

    2. ClassPool

    -

    To define a new class from scratch, makeClass() -must be called on a ClassPool. +

    +A ClassPool object is a container of CtClass +objects. Once a CtClass object is created, it is +recorded in a ClassPool for ever. This is because a +compiler may need to access the CtClass object later when +it compiles source code that refers to the class represented by that +CtClass. + +

    +For example, suppose that a new method getter() is added +to a CtClass object representing Point +class. Later, the program attempts to compile source code including a +method call to getter() in Point and use the +compiled code as the body of a method, which will be added to another +class Line. If the CtClass object representing +Point is lost, the compiler cannot compile the method call +to getter(). Note that the original class definition does +not include getter(). Therefore, to correctly compile +such a method call, the ClassPool +must contain all the instances of CtClass all the time of +program execution. + +

    Avoid out of memory

    + +

    +This specification of ClassPool may cause huge memory +consumption if the number of CtClass objects becomes +amazingly large (this rarely happens since Javassist tries to reduce +memory consumption in various ways). To avoid this problem, you +can explicitly remove an unnecessary CtClass object from +the ClassPool. If you call detach() on a +CtClass object, then that CtClass object is +removed from the ClassPool. For example,

      -ClassPool pool = ClassPool.getDefault();
      -CtClass cc = pool.makeClass("Point");
      +CtClass cc = ... ;
      +cc.writeFile();
      +cc.detach();
       
    -

    This program defines a class Point -including no members. +

    You must not call any method on that +CtClass object after detach() is called. + +

    +Another idea is to occasionally replace a ClassPool with +a new one and discard the old one. If an old ClassPool +is garbage collected, the CtClass objects included in +that ClassPool are also garbage collected. +To create a new instance of ClassPool, execute the following +code snippet: -

    A new class can be also defined as a copy of an existing class. +

      +ClassPool cp = new ClassPool();
      +cp.appendSystemPath();	// or append another path by appendClassPath()
      +
    + +

    This creates a ClassPool object that behaves as the +default ClassPool returned by +ClassPool.getDefault() does. +Note that ClassPool.getDefault() is a singleton factory method +provided for convenience. Therefore, the default ClassPool +is never garbage-collected. + +

    Cascaded ClassPools.

    + +

    +ClassPool objects can be cascaded like +java.lang.ClassLoader. For example, + +

      +ClassPool parent = ClassPool.getDefault();
      +ClassPool child = new ClassPool(parent);
      +child.insertClassPath("./classes");
      +
    + +

    +If child.get() is called, the child ClassPool +first delegates to the parent ClassPool. If the parent +ClassPool fails to find a class file, then the child +ClassPool attempts to find a class file +under the ./classes directory. + +

    +If child.childFirstLookup is true, the child +ClassPool attempts to find a class file before delegating +to the parent ClassPool. For example, + +

      +ClassPool parent = ClassPool.getDefault();
      +ClassPool child = new ClassPool(parent);
      +child.appendSystemPath();         // the same class path as the default one.
      +child.childFirstLookup = true;    // changes the behavior of the child.
      +
    + +

    Changing a class name for defining a new class

    + +

    A new class can be defined as a copy of an existing class. The program below does that: