KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > compiler > AccessorMaker


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.compiler;
17
18 import javassist.*;
19 import javassist.bytecode.*;
20 import java.util.HashMap JavaDoc;
21
22 /**
23  * AccessorMaker maintains accessors to private members of an enclosing
24  * class. It is necessary for compiling a method in an inner class.
25  */

26 public class AccessorMaker {
27     private CtClass clazz;
28     private int uniqueNumber;
29     private HashMap JavaDoc accessors;
30
31     static final String JavaDoc lastParamType = "javassist.runtime.Inner";
32
33     public AccessorMaker(CtClass c) {
34         clazz = c;
35         uniqueNumber = 1;
36         accessors = new HashMap JavaDoc();
37     }
38
39     public String JavaDoc getConstructor(CtClass c, String JavaDoc desc, MethodInfo orig)
40         throws CompileError
41     {
42         String JavaDoc key = "<init>:" + desc;
43         String JavaDoc consDesc = (String JavaDoc)accessors.get(key);
44         if (consDesc != null)
45             return consDesc; // already exists.
46

47         consDesc = Descriptor.appendParameter(lastParamType, desc);
48         ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
49
try {
50             ConstPool cp = cf.getConstPool();
51             ClassPool pool = clazz.getClassPool();
52             MethodInfo minfo
53                 = new MethodInfo(cp, MethodInfo.nameInit, consDesc);
54             minfo.setAccessFlags(0);
55             minfo.addAttribute(new SyntheticAttribute(cp));
56             ExceptionsAttribute ea = orig.getExceptionsAttribute();
57             if (ea != null)
58                 minfo.addAttribute(ea.copy(cp, null));
59
60             CtClass[] params = Descriptor.getParameterTypes(desc, pool);
61             Bytecode code = new Bytecode(cp);
62             code.addAload(0);
63             int regno = 1;
64             for (int i = 0; i < params.length; ++i)
65                 regno += code.addLoad(regno, params[i]);
66             code.setMaxLocals(regno + 1); // the last parameter is added.
67
code.addInvokespecial(clazz, MethodInfo.nameInit, desc);
68
69             code.addReturn(null);
70             minfo.setCodeAttribute(code.toCodeAttribute());
71             cf.addMethod(minfo);
72         }
73         catch (CannotCompileException e) {
74             throw new CompileError(e);
75         }
76         catch (NotFoundException e) {
77             throw new CompileError(e);
78         }
79
80         accessors.put(key, consDesc);
81         return consDesc;
82     }
83
84     /**
85      * Returns the name of the method for accessing a private method.
86      *
87      * @param name the name of the private method.
88      * @param desc the descriptor of the private method.
89      * @param accDesc the descriptor of the accessor method. The first
90      * parameter type is <code>clazz</code>.
91      * If the private method is static,
92      * <code>accDesc<code> must be equal to <code>desc</code>.
93      *
94      * @param orig the method info of the private method.
95      * @return
96      */

97     public String JavaDoc getMethodAccessor(String JavaDoc name, String JavaDoc desc, String JavaDoc accDesc,
98                                     MethodInfo orig)
99         throws CompileError
100     {
101         String JavaDoc key = name + ":" + desc;
102         String JavaDoc accName = (String JavaDoc)accessors.get(key);
103         if (accName != null)
104             return accName; // already exists.
105

106         ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
107
accName = findAccessorName(cf);
108         try {
109             ConstPool cp = cf.getConstPool();
110             ClassPool pool = clazz.getClassPool();
111             MethodInfo minfo
112                 = new MethodInfo(cp, accName, accDesc);
113             minfo.setAccessFlags(AccessFlag.STATIC);
114             minfo.addAttribute(new SyntheticAttribute(cp));
115             ExceptionsAttribute ea = orig.getExceptionsAttribute();
116             if (ea != null)
117                 minfo.addAttribute(ea.copy(cp, null));
118
119             CtClass[] params = Descriptor.getParameterTypes(accDesc, pool);
120             int regno = 0;
121             Bytecode code = new Bytecode(cp);
122             for (int i = 0; i < params.length; ++i)
123                 regno += code.addLoad(regno, params[i]);
124
125             code.setMaxLocals(regno);
126             if (desc == accDesc)
127                 code.addInvokestatic(clazz, name, desc);
128             else
129                 code.addInvokevirtual(clazz, name, desc);
130
131             code.addReturn(Descriptor.getReturnType(desc, pool));
132             minfo.setCodeAttribute(code.toCodeAttribute());
133             cf.addMethod(minfo);
134         }
135         catch (CannotCompileException e) {
136             throw new CompileError(e);
137         }
138         catch (NotFoundException e) {
139             throw new CompileError(e);
140         }
141
142         accessors.put(key, accName);
143         return accName;
144     }
145
146     /**
147      * Returns the method_info representing the added getter.
148      */

149     public MethodInfo getFieldGetter(FieldInfo finfo, boolean is_static)
150         throws CompileError
151     {
152         String JavaDoc fieldName = finfo.getName();
153         String JavaDoc key = fieldName + ":getter";
154         Object JavaDoc res = accessors.get(key);
155         if (res != null)
156             return (MethodInfo)res; // already exists.
157

158         ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
159
String JavaDoc accName = findAccessorName(cf);
160         try {
161             ConstPool cp = cf.getConstPool();
162             ClassPool pool = clazz.getClassPool();
163             String JavaDoc fieldType = finfo.getDescriptor();
164             String JavaDoc accDesc;
165             if (is_static)
166                 accDesc = "()" + fieldType;
167             else
168                 accDesc = "(" + Descriptor.of(clazz) + ")" + fieldType;
169
170             MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
171             minfo.setAccessFlags(AccessFlag.STATIC);
172             minfo.addAttribute(new SyntheticAttribute(cp));
173             Bytecode code = new Bytecode(cp);
174             if (is_static) {
175                 code.addGetstatic(Bytecode.THIS, fieldName, fieldType);
176             }
177             else {
178                 code.addAload(0);
179                 code.addGetfield(Bytecode.THIS, fieldName, fieldType);
180                 code.setMaxLocals(1);
181             }
182
183             code.addReturn(Descriptor.toCtClass(fieldType, pool));
184             minfo.setCodeAttribute(code.toCodeAttribute());
185             cf.addMethod(minfo);
186             accessors.put(key, minfo);
187             return minfo;
188         }
189         catch (CannotCompileException e) {
190             throw new CompileError(e);
191         }
192         catch (NotFoundException e) {
193             throw new CompileError(e);
194         }
195     }
196
197     /**
198      * Returns the method_info representing the added setter.
199      */

200     public MethodInfo getFieldSetter(FieldInfo finfo, boolean is_static)
201         throws CompileError
202     {
203         String JavaDoc fieldName = finfo.getName();
204         String JavaDoc key = fieldName + ":setter";
205         Object JavaDoc res = accessors.get(key);
206         if (res != null)
207             return (MethodInfo)res; // already exists.
208

209         ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
210
String JavaDoc accName = findAccessorName(cf);
211         try {
212             ConstPool cp = cf.getConstPool();
213             ClassPool pool = clazz.getClassPool();
214             String JavaDoc fieldType = finfo.getDescriptor();
215             String JavaDoc accDesc;
216             if (is_static)
217                 accDesc = "(" + fieldType + ")V";
218             else
219                 accDesc = "(" + Descriptor.of(clazz) + fieldType + ")V";
220
221             MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
222             minfo.setAccessFlags(AccessFlag.STATIC);
223             minfo.addAttribute(new SyntheticAttribute(cp));
224             Bytecode code = new Bytecode(cp);
225             int reg;
226             if (is_static) {
227                 reg = code.addLoad(0, Descriptor.toCtClass(fieldType, pool));
228                 code.addPutstatic(Bytecode.THIS, fieldName, fieldType);
229             }
230             else {
231                 code.addAload(0);
232                 reg = code.addLoad(1, Descriptor.toCtClass(fieldType, pool))
233                       + 1;
234                 code.addPutfield(Bytecode.THIS, fieldName, fieldType);
235             }
236
237             code.addReturn(null);
238             code.setMaxLocals(reg);
239             minfo.setCodeAttribute(code.toCodeAttribute());
240             cf.addMethod(minfo);
241             accessors.put(key, minfo);
242             return minfo;
243         }
244         catch (CannotCompileException e) {
245             throw new CompileError(e);
246         }
247         catch (NotFoundException e) {
248             throw new CompileError(e);
249         }
250     }
251
252     private String JavaDoc findAccessorName(ClassFile cf) {
253         String JavaDoc accName;
254         do {
255             accName = "access$" + uniqueNumber++;
256         } while (cf.getMethod(accName) != null);
257         return accName;
258     }
259 }
260
Popular Tags