a private constructor declared in an enclosing class. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@99 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -35,7 +35,7 @@ public abstract class CtClass { | |||
/** | |||
* The version number of this release. | |||
*/ | |||
public static final String version = "3.0 RC1"; | |||
public static final String version = "3.0 RC0"; | |||
/** | |||
* Prints the version number and the copyright notice. |
@@ -57,6 +57,7 @@ public final class MethodInfo { | |||
/** | |||
* Constructs a <code>method_info</code> structure. | |||
* The initial value of <code>access_flags</code> is zero. | |||
* | |||
* @param cp a constant pool table | |||
* @param methodname method name |
@@ -28,12 +28,59 @@ public class AccessorMaker { | |||
private int uniqueNumber; | |||
private HashMap accessors; | |||
static final String lastParamType = "javassist.runtime.Inner"; | |||
public AccessorMaker(CtClass c) { | |||
clazz = c; | |||
uniqueNumber = 1; | |||
accessors = new HashMap(); | |||
} | |||
public String getConstructor(CtClass c, String desc, MethodInfo orig) | |||
throws CompileError | |||
{ | |||
String key = "<init>:" + desc; | |||
String consDesc = (String)accessors.get(key); | |||
if (consDesc != null) | |||
return consDesc; // already exists. | |||
consDesc = Descriptor.appendParameter(lastParamType, desc); | |||
ClassFile cf = clazz.getClassFile(); // turn on the modified flag. | |||
try { | |||
ConstPool cp = cf.getConstPool(); | |||
ClassPool pool = clazz.getClassPool(); | |||
MethodInfo minfo | |||
= new MethodInfo(cp, MethodInfo.nameInit, consDesc); | |||
minfo.setAccessFlags(0); | |||
minfo.addAttribute(new SyntheticAttribute(cp)); | |||
ExceptionsAttribute ea = orig.getExceptionsAttribute(); | |||
if (ea != null) | |||
minfo.addAttribute(ea.copy(cp, null)); | |||
CtClass[] params = Descriptor.getParameterTypes(desc, pool); | |||
Bytecode code = new Bytecode(cp); | |||
code.addAload(0); | |||
int regno = 1; | |||
for (int i = 0; i < params.length; ++i) | |||
regno += code.addLoad(regno, params[i]); | |||
code.setMaxLocals(regno + 1); // the last parameter is added. | |||
code.addInvokespecial(clazz, MethodInfo.nameInit, desc); | |||
code.addReturn(null); | |||
minfo.setCodeAttribute(code.toCodeAttribute()); | |||
cf.addMethod(minfo); | |||
} | |||
catch (CannotCompileException e) { | |||
throw new CompileError(e); | |||
} | |||
catch (NotFoundException e) { | |||
throw new CompileError(e); | |||
} | |||
accessors.put(key, consDesc); | |||
return consDesc; | |||
} | |||
/** | |||
* Returns the name of the method for accessing a private method. | |||
* |
@@ -331,6 +331,7 @@ public class MemberCodeGen extends CodeGen { | |||
int stack = bytecode.getStackDepth(); | |||
// generate code for evaluating arguments. | |||
atMethodArgs(args, types, dims, cnames); | |||
// used by invokeinterface | |||
@@ -370,12 +371,16 @@ public class MemberCodeGen extends CodeGen { | |||
isSpecial = true; | |||
if (declClass != targetClass) | |||
throw new CompileError("no such a constructor"); | |||
if (declClass != thisClass && AccessFlag.isPrivate(acc)) { | |||
desc = getAccessibleConstructor(desc, declClass, minfo); | |||
bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter | |||
} | |||
} | |||
else if (AccessFlag.isPrivate(acc)) | |||
if (declClass == thisClass) | |||
isSpecial = true; | |||
else { | |||
String orgName = mname; | |||
isSpecial = false; | |||
isStatic = true; | |||
String origDesc = desc; | |||
@@ -386,9 +391,6 @@ public class MemberCodeGen extends CodeGen { | |||
acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC; | |||
mname = getAccessiblePrivate(mname, origDesc, desc, | |||
minfo, declClass); | |||
if (mname == null) | |||
throw new CompileError("Method " + orgName | |||
+ " is private"); | |||
} | |||
boolean popTarget = false; | |||
@@ -435,14 +437,36 @@ public class MemberCodeGen extends CodeGen { | |||
{ | |||
if (isEnclosing(declClass, thisClass)) { | |||
AccessorMaker maker = declClass.getAccessorMaker(); | |||
if (maker == null) | |||
return null; | |||
else | |||
if (maker != null) | |||
return maker.getMethodAccessor(methodName, desc, newDesc, | |||
minfo); | |||
} | |||
else | |||
return null; // cannot access this private method. | |||
throw new CompileError("Method " + methodName | |||
+ " is private"); | |||
} | |||
/* | |||
* Finds (or adds if necessary) a hidden constructor if the given | |||
* constructor is in an enclosing class. | |||
* | |||
* @param desc the descriptor of the constructor. | |||
* @param declClass the class declaring the constructor. | |||
* @param minfo the method info of the constructor. | |||
* @return the descriptor of the hidden constructor. | |||
*/ | |||
protected String getAccessibleConstructor(String desc, CtClass declClass, | |||
MethodInfo minfo) | |||
throws CompileError | |||
{ | |||
if (isEnclosing(declClass, thisClass)) { | |||
AccessorMaker maker = declClass.getAccessorMaker(); | |||
if (maker != null) | |||
return maker.getConstructor(declClass, desc, minfo); | |||
} | |||
throw new CompileError("the called constructor is private in " | |||
+ declClass.getName()); | |||
} | |||
private boolean isEnclosing(CtClass outer, CtClass inner) { |
@@ -0,0 +1,24 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 1999-2004 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 javassist.runtime; | |||
/** | |||
* A support class for compiling a method declared in an inner class. | |||
* This support class is required at runtime | |||
* only if the method calls a private constructor in the enclosing class. | |||
*/ | |||
public class Inner { | |||
} |