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
/** | /** | ||||
* The version number of this release. | * 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. | * Prints the version number and the copyright notice. |
/** | /** | ||||
* Constructs a <code>method_info</code> structure. | * Constructs a <code>method_info</code> structure. | ||||
* The initial value of <code>access_flags</code> is zero. | |||||
* | * | ||||
* @param cp a constant pool table | * @param cp a constant pool table | ||||
* @param methodname method name | * @param methodname method name |
private int uniqueNumber; | private int uniqueNumber; | ||||
private HashMap accessors; | private HashMap accessors; | ||||
static final String lastParamType = "javassist.runtime.Inner"; | |||||
public AccessorMaker(CtClass c) { | public AccessorMaker(CtClass c) { | ||||
clazz = c; | clazz = c; | ||||
uniqueNumber = 1; | uniqueNumber = 1; | ||||
accessors = new HashMap(); | 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. | * Returns the name of the method for accessing a private method. | ||||
* | * |
int stack = bytecode.getStackDepth(); | int stack = bytecode.getStackDepth(); | ||||
// generate code for evaluating arguments. | |||||
atMethodArgs(args, types, dims, cnames); | atMethodArgs(args, types, dims, cnames); | ||||
// used by invokeinterface | // used by invokeinterface | ||||
isSpecial = true; | isSpecial = true; | ||||
if (declClass != targetClass) | if (declClass != targetClass) | ||||
throw new CompileError("no such a constructor"); | 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)) | else if (AccessFlag.isPrivate(acc)) | ||||
if (declClass == thisClass) | if (declClass == thisClass) | ||||
isSpecial = true; | isSpecial = true; | ||||
else { | else { | ||||
String orgName = mname; | |||||
isSpecial = false; | isSpecial = false; | ||||
isStatic = true; | isStatic = true; | ||||
String origDesc = desc; | String origDesc = desc; | ||||
acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC; | acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC; | ||||
mname = getAccessiblePrivate(mname, origDesc, desc, | mname = getAccessiblePrivate(mname, origDesc, desc, | ||||
minfo, declClass); | minfo, declClass); | ||||
if (mname == null) | |||||
throw new CompileError("Method " + orgName | |||||
+ " is private"); | |||||
} | } | ||||
boolean popTarget = false; | boolean popTarget = false; | ||||
{ | { | ||||
if (isEnclosing(declClass, thisClass)) { | if (isEnclosing(declClass, thisClass)) { | ||||
AccessorMaker maker = declClass.getAccessorMaker(); | AccessorMaker maker = declClass.getAccessorMaker(); | ||||
if (maker == null) | |||||
return null; | |||||
else | |||||
if (maker != null) | |||||
return maker.getMethodAccessor(methodName, desc, newDesc, | return maker.getMethodAccessor(methodName, desc, newDesc, | ||||
minfo); | 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) { | private boolean isEnclosing(CtClass outer, CtClass inner) { |
/* | |||||
* 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 { | |||||
} |