KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > jmi > util > ClassFileGenerator


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.lib.jmi.util;
20
21 import java.io.ByteArrayOutputStream JavaDoc;
22 import java.io.DataOutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.util.*;
26
27 /**
28  * @author Martin Matula, Dusan Balek
29  * @version 0.1
30  */

31 public abstract class ClassFileGenerator {
32
33     /* Class File Constants */
34     public static final int JAVA_MAGIC = 0xcafebabe;
35
36     /* Generate class file version for 1.1 by default */
37     public static final int JAVA_DEFAULT_VERSION = 45;
38     public static final int JAVA_DEFAULT_MINOR_VERSION = 3;
39     
40     /* Constant table */
41     public static final int CONSTANT_UTF8 = 1;
42     public static final int CONSTANT_INTEGER = 3;
43     public static final int CONSTANT_FLOAT = 4;
44     public static final int CONSTANT_LONG = 5;
45     public static final int CONSTANT_DOUBLE = 6;
46     public static final int CONSTANT_CLASS = 7;
47     public static final int CONSTANT_STRING = 8;
48     public static final int CONSTANT_FIELD = 9;
49     public static final int CONSTANT_METHOD = 10;
50     public static final int CONSTANT_INTERFACEMETHOD = 11;
51     public static final int CONSTANT_NAMEANDTYPE = 12;
52     
53     /* Access and modifier flags */
54     public static final int ACC_PUBLIC = 0x00000001;
55     public static final int ACC_PRIVATE = 0x00000002;
56     public static final int ACC_PROTECTED = 0x00000004;
57     public static final int ACC_STATIC = 0x00000008;
58     public static final int ACC_FINAL = 0x00000010;
59     public static final int ACC_SUPER = 0x00000020;
60     public static final int ACC_INTERFACE = 0x00000200;
61     public static final int ACC_ABSTRACT = 0x00000400;
62     
63     /* Type codes */
64     public static final int T_BYTE = 0x00000008;
65     
66     /* Opcodes */
67     public static final int opc_aconst_null = 1;
68     public static final int opc_iconst_0 = 3;
69     public static final int opc_iconst_1 = 4;
70     public static final int opc_lconst_0 = 9;
71     public static final int opc_fconst_0 = 11;
72     public static final int opc_dconst_0 = 14;
73     public static final int opc_bipush = 16;
74     public static final int opc_sipush = 17;
75     public static final int opc_ldc = 18;
76     public static final int opc_ldc_w = 19;
77     public static final int opc_iload = 21;
78     public static final int opc_lload = 22;
79     public static final int opc_fload = 23;
80     public static final int opc_dload = 24;
81     public static final int opc_aload = 25;
82     public static final int opc_iload_0 = 26;
83     public static final int opc_lload_0 = 30;
84     public static final int opc_fload_0 = 34;
85     public static final int opc_dload_0 = 38;
86     public static final int opc_aload_0 = 42;
87     public static final int opc_aload_1 = 43;
88     public static final int opc_aaload = 50;
89     public static final int opc_istore = 54;
90     public static final int opc_lstore = 55;
91     public static final int opc_fstore = 56;
92     public static final int opc_dstore = 57;
93     public static final int opc_astore = 58;
94     public static final int opc_istore_0 = 59;
95     public static final int opc_lstore_0 = 63;
96     public static final int opc_fstore_0 = 67;
97     public static final int opc_dstore_0 = 71;
98     public static final int opc_astore_0 = 75;
99     public static final int opc_aastore = 83;
100     public static final int opc_bastore = 84;
101     public static final int opc_pop = 87;
102     public static final int opc_dup = 89;
103     public static final int opc_ifeq = 153;
104     public static final int opc_ifne = 154;
105     public static final int opc_ifle = 158;
106     public static final int opc_if_icmpeq = 159;
107     public static final int opc_if_acmpne = 166;
108     public static final int opc_goto = 167;
109     public static final int opc_jsr = 168;
110     public static final int opc_ret = 169;
111     public static final int opc_ireturn = 172;
112     public static final int opc_lreturn = 173;
113     public static final int opc_freturn = 174;
114     public static final int opc_dreturn = 175;
115     public static final int opc_areturn = 176;
116     public static final int opc_return = 177;
117     public static final int opc_getstatic = 178;
118     public static final int opc_putstatic = 179;
119     public static final int opc_getfield = 180;
120     public static final int opc_putfield = 181;
121     public static final int opc_invokevirtual = 182;
122     public static final int opc_invokespecial = 183;
123     public static final int opc_invokestatic = 184;
124     public static final int opc_invokeinterface = 185;
125     public static final int opc_new = 187;
126     public static final int opc_newarray = 188;
127     public static final int opc_anewarray = 189;
128     public static final int opc_arraylength = 190;
129     public static final int opc_athrow = 191;
130     public static final int opc_checkcast = 192;
131     public static final int opc_instanceof = 193;
132     public static final int opc_wide = 196;
133     public static final int opc_ifnull = 198;
134     
135     /** name of generated class */
136     protected String JavaDoc className;
137     
138     /** access flags */
139     protected int accessFlags;
140     
141     /** superclass name */
142     protected String JavaDoc superclassName;
143     
144     /** interface names */
145     protected String JavaDoc[] ifaceNames;
146     
147     /** constant pool of class being generated */
148     protected ConstantPool cp = new ConstantPool();
149     
150     /**
151      * Construct a HandlerGenerator to generate a handler class with the
152      * specified name and for the given interfaces.
153      */

154     protected ClassFileGenerator(String JavaDoc className, String JavaDoc[] interfaces, String JavaDoc superclass, int accessFlags) {
155         this.className = className;
156         this.ifaceNames = interfaces;
157         this.superclassName = superclass;
158         this.accessFlags = accessFlags;
159     }
160     
161     /**
162      * Generate a class file for the handler. This method drives the
163      * class file generation process.
164      */

165     final protected void generateClassFile(OutputStream JavaDoc stream) {
166         try {
167             // collect field info and method info structs
168
MethodInfo[] methods = generateMethods();
169             FieldInfo[] fields = generateFields();
170             
171             // make sure these classes are in the constant pool
172
cp.getClass(dotToSlash(className));
173             cp.getClass(dotToSlash(superclassName));
174             for (int i = 0; i < ifaceNames.length; i++)
175                 cp.getClass(dotToSlash(ifaceNames[i]));
176             cp.setReadOnly();
177             
178             // write the class file
179
DataOutputStream JavaDoc dout = new DataOutputStream JavaDoc(stream);
180             
181             // u4 magic;
182
dout.writeInt(JAVA_MAGIC);
183             // u2 major_version;
184
dout.writeShort(JAVA_DEFAULT_MINOR_VERSION);
185             // u2 minor_version;
186
dout.writeShort(JAVA_DEFAULT_VERSION);
187             
188             // constant pool
189
cp.write(dout);
190             
191             // u2 access_flags;
192
dout.writeShort(accessFlags);
193             
194             // u2 this_class;
195
dout.writeShort(cp.getClass(dotToSlash(className)));
196             
197             // u2 super_class;
198
dout.writeShort(cp.getClass(dotToSlash(superclassName)));
199             
200             // u2 interfaces_count;
201
dout.writeShort(ifaceNames.length);
202             // u2 interfaces[interfaces_count];
203
for (int i = 0; i < ifaceNames.length; i++)
204                 dout.writeShort(cp.getClass(dotToSlash(ifaceNames[i])));
205             
206             // u2 fields_count;
207
dout.writeShort(fields.length);
208             // field_info fields[fields_count];
209
for (int i = 0; i < fields.length; i++)
210                 fields[i].write(dout);
211             
212             // u2 methods_count;
213
dout.writeShort(methods.length);
214             // method_info methods[methods_count];
215
for (int i = 0 ; i < methods.length; i++)
216                 methods[i].write(dout);
217             
218             // u2 attributes_count;
219
dout.writeShort(0);
220             dout.close();
221         } catch (IOException JavaDoc e) {
222             throw new InternalError JavaDoc("unexpected I/O Exception"); //NOI18N
223
}
224     }
225     
226     protected abstract MethodInfo[] generateMethods() throws IOException JavaDoc;
227     protected abstract FieldInfo[] generateFields() throws IOException JavaDoc;
228     
229     /**
230      * A FieldInfo object contains information about a particular field
231      * in the class being generated. The class mirrors the data items of
232      * the "field_info" structure of the class file format (see JVMS 4.5).
233      */

234     final protected class FieldInfo {
235         private int accessFlags;
236         private String JavaDoc name;
237         private String JavaDoc descriptor;
238         private Object JavaDoc constValue;
239         
240         public FieldInfo(String JavaDoc name, String JavaDoc descriptor, int accessFlags) {
241             this.name = name;
242             this.descriptor = descriptor;
243             this.accessFlags = accessFlags;
244             
245             /*
246              * Make sure that constant pool indexes are reserved for the
247              * following items before starting to write the final class file.
248              */

249             cp.getUtf8(name);
250             cp.getUtf8(descriptor);
251         }
252         
253         public void setConstValue(Object JavaDoc value) {
254             if ((accessFlags & ACC_STATIC) != 0) {
255                 constValue = value;
256                 cp.getUtf8("ConstantValue"); //NOI18N
257
cp.getUnknownValue(constValue);
258             }
259         }
260         
261         final public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
262             /*
263              * Write all the items of the "field_info" structure.
264              * See JVMS section 4.5.
265              */

266             // u2 access_flags;
267
out.writeShort(accessFlags);
268             // u2 name_index;
269
out.writeShort(cp.getUtf8(name));
270             // u2 descriptor_index;
271
out.writeShort(cp.getUtf8(descriptor));
272             // u2 attributes_count;
273
if (constValue == null)
274                 out.writeShort(0); // (no field_info attributes for proxy classes)
275
else {
276                 out.writeShort(1);
277                 // u2 attribute_name_index;
278
out.writeShort(cp.getUtf8("ConstantValue")); //NOI18N
279
// u4 attribute_length;
280
out.writeInt(2);
281                 // u2 constantvalue_index
282
out.writeShort(cp.getUnknownValue(constValue));
283             }
284         }
285         
286         public boolean equals(Object JavaDoc o) {
287             if (o instanceof FieldInfo) {
288                 return ((FieldInfo) o).name.equalsIgnoreCase(name);
289             } else {
290                 return false;
291             }
292         }
293         
294         public int hashCode() {
295             return name.toUpperCase(Locale.US).hashCode();
296         }
297     }
298     
299     /**
300      * An ExceptionTableEntry object holds values for the data items of
301      * an entry in the "exception_table" item of the "Code" attribute of
302      * "method_info" structures (see JVMS 4.7.3).
303      */

304     final protected static class ExceptionTableEntry {
305         public short startPc;
306         public short endPc;
307         public short handlerPc;
308         public short catchType;
309         
310         public ExceptionTableEntry(short startPc, short endPc,
311         short handlerPc, short catchType) {
312             this.startPc = startPc;
313             this.endPc = endPc;
314             this.handlerPc = handlerPc;
315             this.catchType = catchType;
316         }
317     };
318     
319     /**
320      * A MethodInfo object contains information about a particular method
321      * in the class being generated. This class mirrors the data items of
322      * the "method_info" structure of the class file format (see JVMS 4.6).
323      */

324     final protected class MethodInfo {
325         private int accessFlags;
326         private String JavaDoc name;
327         private String JavaDoc descriptor;
328         private ByteArrayOutputStream JavaDoc code = new ByteArrayOutputStream JavaDoc();
329         private short maxStack;
330         private short maxLocals;
331         private short[] declaredExceptions;
332         private List exceptionTable = new ArrayList();
333         
334         public MethodInfo(String JavaDoc name, String JavaDoc descriptor, int accessFlags) {
335             this.name = name;
336             this.descriptor = descriptor;
337             this.accessFlags = accessFlags;
338             
339             /*
340              * Make sure that constant pool indexes are reserved for the
341              * following items before starting to write the final class file.
342              */

343             cp.getUtf8(name);
344             cp.getUtf8(descriptor);
345         }
346         
347         public void setDeclaredExceptions(short[] exceptions) {
348             cp.getUtf8("Exceptions"); //NOI18N
349
declaredExceptions = exceptions;
350         }
351         
352         public ByteArrayOutputStream JavaDoc getCodeStream() {
353             cp.getUtf8("Code"); //NOI18N
354
return code;
355         }
356         
357         public void setMaxStack(short max) {
358             maxStack = max;
359         }
360         
361         public void setMaxLocals(short max) {
362             maxLocals = max;
363         }
364         
365         public List getExceptionTable() {
366             return exceptionTable;
367         }
368         
369         public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
370             /*
371              * Write all the items of the "method_info" structure.
372              * See JVMS section 4.6.
373              */

374             // u2 access_flags;
375
out.writeShort(accessFlags);
376             // u2 name_index;
377
out.writeShort(cp.getUtf8(name));
378             // u2 descriptor_index;
379
out.writeShort(cp.getUtf8(descriptor));
380             // u2 attributes_count;
381
short count = 0;
382             if (code.size() > 0)
383                 count++;
384             if (declaredExceptions != null && declaredExceptions.length > 0)
385                 count++;
386             out.writeShort(count);
387             
388             // Write "Code" attribute. See JVMS section 4.7.3.
389
if (code.size() > 0) {
390                 // u2 attribute_name_index;
391
out.writeShort(cp.getUtf8("Code")); //NOI18N
392
// u4 attribute_length;
393
out.writeInt(12 + code.size() + 8 * exceptionTable.size());
394                 // u2 max_stack;
395
out.writeShort(maxStack);
396                 // u2 max_locals;
397
out.writeShort(maxLocals);
398                 // u2 code_length;
399
out.writeInt(code.size());
400                 // u1 code[code_length];
401
code.writeTo(out);
402                 // u2 exception_table_length;
403
out.writeShort(exceptionTable.size());
404                 for (Iterator iter = exceptionTable.iterator(); iter.hasNext();) {
405                     ExceptionTableEntry e = (ExceptionTableEntry) iter.next();
406                     // u2 start_pc;
407
out.writeShort(e.startPc);
408                     // u2 end_pc;
409
out.writeShort(e.endPc);
410                     // u2 handler_pc;
411
out.writeShort(e.handlerPc);
412                     // u2 catch_type;
413
out.writeShort(e.catchType);
414                 }
415                 // u2 attributes_count;
416
out.writeShort(0);
417             }
418             
419             // write "Exceptions" attribute. See JVMS section 4.7.4.
420
if (declaredExceptions != null && declaredExceptions.length > 0) {
421                 // u2 attribute_name_index;
422
out.writeShort(cp.getUtf8("Exceptions")); //NOI18N
423
// u4 attributes_length;
424
out.writeInt(2 + 2 * declaredExceptions.length);
425                 // u2 number_of_exceptions;
426
out.writeShort(declaredExceptions.length);
427                 // u2 exception_index_table[number_of_exceptions];
428
for (int i = 0; i < declaredExceptions.length; i++)
429                     out.writeShort(declaredExceptions[i]);
430             }
431         }
432         
433     }
434     
435     /*
436      * =============== Code Generation Utility Methods ===============
437      */

438     
439     /*
440      * The following methods generate code for the load or store operation
441      * indicated by their name for the given local variable. The code is
442      * written to the supplied stream.
443      */

444     
445     protected void code_iload(int lvar, DataOutputStream JavaDoc out)
446     throws IOException JavaDoc {
447         codeLocalLoadStore(lvar,
448         opc_iload, opc_iload_0, out);
449     }
450     
451     protected void code_lload(int lvar, DataOutputStream JavaDoc out)
452     throws IOException JavaDoc {
453         codeLocalLoadStore(lvar,
454         opc_lload, opc_lload_0, out);
455     }
456     
457     protected void code_fload(int lvar, DataOutputStream JavaDoc out)
458     throws IOException JavaDoc {
459         codeLocalLoadStore(lvar,
460         opc_fload, opc_fload_0, out);
461     }
462     
463     protected void code_dload(int lvar, DataOutputStream JavaDoc out)
464     throws IOException JavaDoc {
465         codeLocalLoadStore(lvar,
466         opc_dload, opc_dload_0, out);
467     }
468     
469     protected void code_aload(int lvar, DataOutputStream JavaDoc out)
470     throws IOException JavaDoc {
471         codeLocalLoadStore(lvar,
472         opc_aload, opc_aload_0, out);
473     }
474     
475     protected void code_istore(int lvar, DataOutputStream JavaDoc out)
476     throws IOException JavaDoc {
477         codeLocalLoadStore(lvar,
478         opc_istore, opc_istore_0, out);
479     }
480     
481     protected void code_lstore(int lvar, DataOutputStream JavaDoc out)
482     throws IOException JavaDoc {
483         codeLocalLoadStore(lvar,
484         opc_lstore, opc_lstore_0, out);
485     }
486     
487     protected void code_fstore(int lvar, DataOutputStream JavaDoc out)
488     throws IOException JavaDoc {
489         codeLocalLoadStore(lvar,
490         opc_fstore, opc_fstore_0, out);
491     }
492     
493     protected void code_dstore(int lvar, DataOutputStream JavaDoc out)
494     throws IOException JavaDoc {
495         codeLocalLoadStore(lvar,
496         opc_dstore, opc_dstore_0, out);
497     }
498     
499     protected void code_astore(int lvar, DataOutputStream JavaDoc out)
500     throws IOException JavaDoc {
501         codeLocalLoadStore(lvar,
502         opc_astore, opc_astore_0, out);
503     }
504     
505     /**
506      * Generate code for a load or store instruction for the given local
507      * variable. The code is written to the supplied stream.
508      *
509      * "opcode" indicates the opcode form of the desired load or store
510      * instruction that takes an explicit local variable index, and
511      * "opcode_0" indicates the corresponding form of the instruction
512      * with the implicit index 0.
513      */

514     protected void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
515     DataOutputStream JavaDoc out)
516     throws IOException JavaDoc {
517         _assert(lvar >= 0 && lvar <= 0xFFFF);
518         if (lvar <= 3) {
519             out.writeByte(opcode_0 + lvar);
520         } else if (lvar <= 0xFF) {
521             out.writeByte(opcode);
522             out.writeByte(lvar & 0xFF);
523         } else {
524             /*
525              * Use the "wide" instruction modifier for local variable
526              * indexes that do not fit into an unsigned byte.
527              */

528             out.writeByte(opc_wide);
529             out.writeByte(opcode);
530             out.writeShort(lvar & 0xFFFF);
531         }
532     }
533     
534     /**
535      * Generate code for an "ldc" instruction for the given constant pool
536      * index (the "ldc_w" instruction is used if the index does not fit
537      * into an unsigned byte). The code is written to the supplied stream.
538      */

539     protected void code_ldc(int index, DataOutputStream JavaDoc out)
540     throws IOException JavaDoc {
541         _assert(index >= 0 && index <= 0xFFFF);
542         if (index <= 0xFF) {
543             out.writeByte(opc_ldc);
544             out.writeByte(index & 0xFF);
545         } else {
546             out.writeByte(opc_ldc_w);
547             out.writeShort(index & 0xFFFF);
548         }
549     }
550     
551     /**
552      * Generate code to push a constant integer value on to the operand
553      * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
554      * depending on the size of the value. The code is written to the
555      * supplied stream.
556      */

557     protected void code_ipush(int value, DataOutputStream JavaDoc out)
558     throws IOException JavaDoc {
559         if (value >= -1 && value <= 5) {
560             out.writeByte(opc_iconst_0 + value);
561         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
562             out.writeByte(opc_bipush);
563             out.writeByte(value & 0xFF);
564         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
565             out.writeByte(opc_sipush);
566             out.writeShort(value & 0xFFFF);
567         } else {
568             _assert(false);
569         }
570     }
571     
572     protected void codeReturnFieldValue(String JavaDoc className, String JavaDoc fieldName, String JavaDoc descriptor, boolean isStatic, DataOutputStream JavaDoc out)
573     throws IOException JavaDoc {
574         short index = cp.getFieldRef(dotToSlash(className), fieldName, descriptor);
575         _assert(index >= 0);
576         if (isStatic)
577             out.writeByte(opc_getstatic);
578         else {
579             code_aload(0, out);
580             out.writeByte(opc_getfield);
581         }
582         out.writeShort(index);
583         if (descriptor.equals("I") || descriptor.equals("S") || descriptor.equals("C") || //NOI18N
584
descriptor.equals("B") || descriptor.equals("Z")) //NOI18N
585
out.writeByte(opc_ireturn);
586         else if (descriptor.equals("J")) //NOI18N
587
out.writeByte(opc_lreturn);
588         else if (descriptor.equals("F")) //NOI18N
589
out.writeByte(opc_freturn);
590         else if (descriptor.equals("D")) //NOI18N
591
out.writeByte(opc_dreturn);
592         else
593             out.writeByte(opc_areturn);
594     }
595     
596     /**
597      * Generate code to invoke the Class.forName with the name of the given
598      * class to get its Class object at runtime. The code is written to
599      * the supplied stream. Note that the code generated by this method
600      * may caused the checked ClassNotFoundException to be thrown.
601      */

602     protected void codeClassForName(Class JavaDoc cl, DataOutputStream JavaDoc out)
603     throws IOException JavaDoc {
604         code_ldc(cp.getString(cl.getName()), out);
605         
606         out.writeByte(opc_invokestatic);
607         out.writeShort(cp.getMethodRef(
608         "java/lang/Class", //NOI18N
609
"forName", "(Ljava/lang/String;)Ljava/lang/Class;")); //NOI18N
610
}
611     /*
612      * ==================== General Utility Methods ====================
613      */

614     
615     protected static String JavaDoc firstUpper(String JavaDoc text) {
616         try {
617             return text.substring(0, 1).toUpperCase(Locale.US) + text.substring(1);
618         } catch (IndexOutOfBoundsException JavaDoc e) {
619             return ""; //NOI18N
620
}
621     }
622     
623     protected static String JavaDoc firstLower(String JavaDoc text) {
624         try {
625             return text.substring(0, 1).toLowerCase(Locale.US) + text.substring(1);
626         } catch (IndexOutOfBoundsException JavaDoc e) {
627             return ""; //NOI18N
628
}
629     }
630     
631     /**
632      * Assert that an assertion is true: throw InternalError if it is not.
633      */

634     protected static void _assert(boolean assertion) {
635         if (assertion != true) {
636             throw new InternalError JavaDoc("assertion failure"); //NOI18N
637
}
638     }
639     
640     /**
641      * Convert a fully qualified class name that uses '.' as the package
642      * separator, the external representation used by the Java language
643      * and APIs, to a fully qualified class name that uses '/' as the
644      * package separator, the representation used in the class file
645      * format (see JVMS section 4.2).
646      */

647     protected static String JavaDoc dotToSlash(String JavaDoc name) {
648         return name.replace('.', '/');
649     }
650     
651     /**
652      * Return the "method descriptor" string for a method with the given
653      * parameter types and return type. See JVMS section 4.3.3.
654      */

655     protected static String JavaDoc getMethodDescriptor(String JavaDoc[] parameterTypeNames,
656     String JavaDoc returnTypeName) {
657         return getParameterDescriptors(parameterTypeNames) +
658         ((returnTypeName.equals("void")) ? "V" : getFieldType(returnTypeName)); //NOI18N
659
}
660     
661     /**
662      * Return the list of "parameter descriptor" strings enclosed in
663      * parentheses corresponding to the given parameter types (in other
664      * words, a method descriptor without a return descriptor). This
665      * string is useful for constructing string keys for methods without
666      * regard to their return type.
667      */

668     protected static String JavaDoc getParameterDescriptors(String JavaDoc[] parameterTypeNames) {
669         StringBuffer JavaDoc desc = new StringBuffer JavaDoc("("); //NOI18N
670
for (int i = 0; i < parameterTypeNames.length; i++) {
671             desc.append(getFieldType(parameterTypeNames[i]));
672         }
673         desc.append(')');
674         return desc.toString();
675     }
676     
677     /**
678      * Return the "field type" string for the given type, appropriate for
679      * a field descriptor, a parameter descriptor, or a return descriptor
680      * other than "void". See JVMS section 4.3.2.
681      */

682     protected static String JavaDoc getFieldType(String JavaDoc typeName) {
683         PrimitiveTypeInfo ptInfo = PrimitiveTypeInfo.get(typeName);
684         if (ptInfo != null)
685             return ptInfo.baseTypeString;
686         else if (typeName.endsWith("[]")) //NOI18N
687
return "[" + getFieldType(typeName.substring(0, typeName.length()-2).trim()); //NOI18N
688
else
689             return "L" + dotToSlash(typeName) + ";"; //NOI18N
690
}
691     
692     /**
693      * Return the number of abstract "words", or consecutive local variable
694      * indexes, required to contain a value of the given type. See JVMS
695      * section 3.6.1.
696      *
697      * Note that the original version of the JVMS contained a definition of
698      * this abstract notion of a "word" in section 3.4, but that definition
699      * was removed for the second edition.
700      */

701     protected static int getWordsPerType(String JavaDoc typeName) {
702     if (typeName.equals("long") || typeName.equals("double")) //NOI18N
703
return 2;
704         return 1;
705     }
706
707     /**
708      * A PrimitiveTypeInfo object contains assorted information about
709      * a primitive type in its public fields. The struct for a particular
710      * primitive type can be obtained using the static "get" method.
711      */

712     protected static class PrimitiveTypeInfo {
713         
714         /** "base type" used in various descriptors (see JVMS section 4.3.2) */
715         public String JavaDoc baseTypeString;
716         
717         /** name of corresponding wrapper class */
718         public String JavaDoc wrapperClassName;
719         
720         /** method descriptor for wrapper class constructor */
721         public String JavaDoc wrapperConstructorDesc;
722         
723         /** name of wrapper class method for retrieving primitive value */
724         public String JavaDoc unwrapMethodName;
725         
726         /** descriptor of same method */
727         public String JavaDoc unwrapMethodDesc;
728         
729         private static Map table = new HashMap(11);
730         static {
731             table.put("int", new PrimitiveTypeInfo( //NOI18N
732
"I", "java/lang/Integer", "(I)V", "intValue", "()I")); //NOI18N
733
table.put("boolean", new PrimitiveTypeInfo( //NOI18N
734
"Z", "java/lang/Boolean", "(Z)V", "booleanValue", "()Z")); //NOI18N
735
table.put("byte", new PrimitiveTypeInfo( //NOI18N
736
"B", "java/lang/Byte", "(B)V", "byteValue", "()B")); //NOI18N
737
table.put("char", new PrimitiveTypeInfo( //NOI18N
738
"C", "java/lang/Char", "(C)V", "charValue", "()C")); //NOI18N
739
table.put("short", new PrimitiveTypeInfo( //NOI18N
740
"S", "java/lang/Short", "(S)V", "shortValue", "()S")); //NOI18N
741
table.put("long", new PrimitiveTypeInfo( //NOI18N
742
"J", "java/lang/Long", "(J)V", "longValue", "()J")); //NOI18N
743
table.put("float", new PrimitiveTypeInfo( //NOI18N
744
"F", "java/lang/Float", "(F)V", "floatValue", "()F")); //NOI18N
745
table.put("double", new PrimitiveTypeInfo( //NOI18N
746
"D", "java/lang/Double", "(D)V", "doubleValue", "()D")); //NOI18N
747
}
748         
749         private PrimitiveTypeInfo(String JavaDoc baseTypeString,
750         String JavaDoc wrapperClassName,
751         String JavaDoc wrapperConstructorDesc,
752         String JavaDoc unwrapMethodName,
753         String JavaDoc unwrapMethodDesc) {
754             this.baseTypeString = baseTypeString;
755             this.wrapperClassName = wrapperClassName;
756             this.wrapperConstructorDesc = wrapperConstructorDesc;
757             this.unwrapMethodName = unwrapMethodName;
758             this.unwrapMethodDesc = unwrapMethodDesc;
759         }
760         
761         public static PrimitiveTypeInfo get(String JavaDoc name) {
762             return (PrimitiveTypeInfo) table.get(name);
763         }
764     }
765     
766     
767     /**
768      * A ConstantPool object represents the constant pool of a class file
769      * being generated. This representation of a constant pool is designed
770      * specifically for use by ProxyGenerator; in particular, it assumes
771      * that constant pool entries will not need to be resorted (for example,
772      * by their type, as the Java compiler does), so that the final index
773      * value can be assigned and used when an entry is first created.
774      *
775      * Note that new entries cannot be created after the constant pool has
776      * been written to a class file. To prevent such logic errors, a
777      * ConstantPool instance can be marked "read only", so that further
778      * attempts to add new entries will fail with a runtime exception.
779      *
780      * See JVMS section 4.4 for more information about the constant pool
781      * of a class file.
782      */

783     protected static class ConstantPool {
784         
785         /**
786          * list of constant pool entries, in constant pool index order.
787          *
788          * This list is used when writing the constant pool to a stream
789          * and for assigning the next index value. Note that element 0
790          * of this list corresponds to constant pool index 1.
791          */

792         private List pool = new ArrayList(32);
793         
794         /**
795          * maps constant pool data of all types to constant pool indexes.
796          *
797          * This map is used to look up the index of an existing entry for
798          * values of all types.
799          */

800         private Map map = new HashMap(16);
801         
802         /** true if no new constant pool entries may be added */
803         private boolean readOnly = false;
804         
805         /**
806          * Get or assign the index for a CONSTANT_Utf8 entry.
807          */

808         public short getUtf8(String JavaDoc s) {
809             if (s == null) {
810                 throw new NullPointerException JavaDoc();
811             }
812             return getValue(s);
813         }
814         
815         /**
816          * Get or assign the index for a CONSTANT_Integer entry.
817          */

818         public short getInteger(int i) {
819             return getValue(new Integer JavaDoc(i));
820         }
821         
822         /**
823          * Get or assign the index for a CONSTANT_Float entry.
824          */

825         public short getFloat(float f) {
826             return getValue(new Float JavaDoc(f));
827         }
828         
829         /**
830          * Get or assign the index for a CONSTANT_Long entry.
831          */

832         public short getLong(long l) {
833             return getValue(new Long JavaDoc(l));
834         }
835         
836         /**
837          * Get or assign the index for a CONSTANT_Double entry.
838          */

839         public short getDouble(double d) {
840             return getValue(new Double JavaDoc(d));
841         }
842         
843         /**
844          * Get or assign the index for a CONSTANT_Class entry.
845          */

846         public short getClass(String JavaDoc name) {
847             short utf8Index = getUtf8(name);
848             return getIndirect(new IndirectEntry(
849             CONSTANT_CLASS, utf8Index));
850         }
851         
852         /**
853          * Get or assign the index for a CONSTANT_String entry.
854          */

855         public short getString(String JavaDoc s) {
856             short utf8Index = getUtf8(s);
857             return getIndirect(new IndirectEntry(
858             CONSTANT_STRING, utf8Index));
859         }
860         
861         /**
862          * Get or assign the index for a CONSTANT_FieldRef entry.
863          */

864         public short getFieldRef(String JavaDoc className,
865         String JavaDoc name, String JavaDoc descriptor) {
866             short classIndex = getClass(className);
867             short nameAndTypeIndex = getNameAndType(name, descriptor);
868             return getIndirect(new IndirectEntry(
869             CONSTANT_FIELD,
870             classIndex, nameAndTypeIndex));
871         }
872         
873         /**
874          * Get or assign the index for a CONSTANT_MethodRef entry.
875          */

876         public short getMethodRef(String JavaDoc className,
877         String JavaDoc name, String JavaDoc descriptor) {
878             short classIndex = getClass(className);
879             short nameAndTypeIndex = getNameAndType(name, descriptor);
880             return getIndirect(new IndirectEntry(
881             CONSTANT_METHOD,
882             classIndex, nameAndTypeIndex));
883         }
884         
885         /**
886          * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
887          */

888         public short getInterfaceMethodRef(String JavaDoc className, String JavaDoc name,
889         String JavaDoc descriptor) {
890             short classIndex = getClass(className);
891             short nameAndTypeIndex = getNameAndType(name, descriptor);
892             return getIndirect(new IndirectEntry(
893             CONSTANT_INTERFACEMETHOD,
894             classIndex, nameAndTypeIndex));
895         }
896         
897         /**
898          * Get or assign the index for a CONSTANT_NameAndType entry.
899          */

900         public short getNameAndType(String JavaDoc name, String JavaDoc descriptor) {
901             short nameIndex = getUtf8(name);
902             short descriptorIndex = getUtf8(descriptor);
903             return getIndirect(new IndirectEntry(
904             CONSTANT_NAMEANDTYPE,
905             nameIndex, descriptorIndex));
906         }
907         
908         public short getUnknownValue(Object JavaDoc value) {
909             if (value == null)
910                 throw new NullPointerException JavaDoc();
911             if (value instanceof String JavaDoc)
912                 return getString((String JavaDoc)value);
913             if (value instanceof Integer JavaDoc || value instanceof Float JavaDoc ||
914             value instanceof Long JavaDoc || value instanceof Double JavaDoc)
915                 return getValue(value);
916             throw new InternalError JavaDoc("bogus value entry: " + value); //NOI18N
917
}
918         
919         /**
920          * Set this ConstantPool instance to be "read only".
921          *
922          * After this method has been called, further requests to get
923          * an index for a non-existent entry will cause an InternalError
924          * to be thrown instead of creating of the entry.
925          */

926         public void setReadOnly() {
927             readOnly = true;
928         }
929         
930         /**
931          * Write this constant pool to a stream as part of
932          * the class file format.
933          *
934          * This consists of writing the "constant_pool_count" and
935          * "constant_pool[]" items of the "ClassFile" structure, as
936          * described in JVMS section 4.1.
937          */

938         public void write(OutputStream JavaDoc out) throws IOException JavaDoc {
939             DataOutputStream JavaDoc dataOut = new DataOutputStream JavaDoc(out);
940             
941             // constant_pool_count: number of entries plus one
942
dataOut.writeShort(pool.size() + 1);
943             
944             for (Iterator iter = pool.iterator(); iter.hasNext();) {
945                 Entry e = (Entry) iter.next();
946                 e.write(dataOut);
947             }
948         }
949         
950         /**
951          * Add a new constant pool entry and return its index.
952          */

953         private short addEntry(Entry entry) {
954             pool.add(entry);
955             return (short) pool.size();
956         }
957         
958         /**
959          * Get or assign the index for an entry of a type that contains
960          * a direct value. The type of the given object determines the
961          * type of the desired entry as follows:
962          *
963          * java.lang.String CONSTANT_Utf8
964          * java.lang.Integer CONSTANT_Integer
965          * java.lang.Float CONSTANT_Float
966          * java.lang.Long CONSTANT_Long
967          * java.lang.Double CONSTANT_DOUBLE
968          */

969         private short getValue(Object JavaDoc key) {
970             Short JavaDoc index = (Short JavaDoc) map.get(key);
971             if (index != null) {
972                 return index.shortValue();
973             } else {
974                 if (readOnly) {
975                     throw new InternalError JavaDoc(
976                     "late constant pool addition: " + key); //NOI18N
977
}
978                 short i = addEntry(new ValueEntry(key));
979                 map.put(key, new Short JavaDoc(i));
980                 return i;
981             }
982         }
983         
984         /**
985          * Get or assign the index for an entry of a type that contains
986          * references to other constant pool entries.
987          */

988         private short getIndirect(IndirectEntry e) {
989             Short JavaDoc index = (Short JavaDoc) map.get(e);
990             if (index != null) {
991                 return index.shortValue();
992             } else {
993                 if (readOnly) {
994                     throw new InternalError JavaDoc("late constant pool addition"); //NOI18N
995
}
996                 short i = addEntry(e);
997                 map.put(e, new Short JavaDoc(i));
998                 return i;
999             }
1000        }
1001        
1002        /**
1003         * Entry is the abstact superclass of all constant pool entry types
1004         * that can be stored in the "pool" list; its purpose is to define a
1005         * common method for writing constant pool entries to a class file.
1006         */

1007        private static abstract class Entry {
1008            public abstract void write(DataOutputStream JavaDoc out)
1009            throws IOException JavaDoc;
1010        }
1011        
1012        /**
1013         * ValueEntry represents a constant pool entry of a type that
1014         * contains a direct value (see the comments for the "getValue"
1015         * method for a list of such types).
1016         *
1017         * ValueEntry objects are not used as keys for their entries in the
1018         * Map "map", so no useful hashCode or equals methods are defined.
1019         */

1020        private static class ValueEntry extends Entry {
1021            private Object JavaDoc value;
1022            
1023            public ValueEntry(Object JavaDoc value) {
1024                this.value = value;
1025            }
1026            
1027            public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
1028                if (value instanceof String JavaDoc) {
1029                    out.writeByte(CONSTANT_UTF8);
1030                    out.writeUTF((String JavaDoc) value);
1031                } else if (value instanceof Integer JavaDoc) {
1032                    out.writeByte(CONSTANT_INTEGER);
1033                    out.writeInt(((Integer JavaDoc) value).intValue());
1034                } else if (value instanceof Float JavaDoc) {
1035                    out.writeByte(CONSTANT_FLOAT);
1036                    out.writeFloat(((Float JavaDoc) value).floatValue());
1037                } else if (value instanceof Long JavaDoc) {
1038                    out.writeByte(CONSTANT_LONG);
1039                    out.writeLong(((Long JavaDoc) value).longValue());
1040                } else if (value instanceof Double JavaDoc) {
1041                    out.writeDouble(CONSTANT_DOUBLE);
1042                    out.writeDouble(((Double JavaDoc) value).doubleValue());
1043                } else {
1044                    throw new InternalError JavaDoc("bogus value entry: " + value); //NOI18N
1045
}
1046            }
1047        }
1048        
1049        /**
1050         * IndirectEntry represents a constant pool entry of a type that
1051         * references other constant pool entries, i.e., the following types:
1052         *
1053         * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
1054         * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
1055         * CONSTANT_NameAndType.
1056         *
1057         * Each of these entry types contains either one or two indexes of
1058         * other constant pool entries.
1059         *
1060         * IndirectEntry objects are used as the keys for their entries in
1061         * the Map "map", so the hashCode and equals methods are overridden
1062         * to allow matching.
1063         */

1064        private static class IndirectEntry extends Entry {
1065            private int tag;
1066            private short index0;
1067            private short index1;
1068            
1069            /**
1070             * Construct an IndirectEntry for a constant pool entry type
1071             * that contains one index of another entry.
1072             */

1073            public IndirectEntry(int tag, short index) {
1074                this.tag = tag;
1075                this.index0 = index;
1076                this.index1 = 0;
1077            }
1078            
1079            /**
1080             * Construct an IndirectEntry for a constant pool entry type
1081             * that contains two indexes for other entries.
1082             */

1083            public IndirectEntry(int tag, short index0, short index1) {
1084                this.tag = tag;
1085                this.index0 = index0;
1086                this.index1 = index1;
1087            }
1088            
1089            public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
1090                out.writeByte(tag);
1091                out.writeShort(index0);
1092                /*
1093                 * If this entry type contains two indexes, write
1094                 * out the second, too.
1095                 */

1096                if (tag == CONSTANT_FIELD ||
1097                tag == CONSTANT_METHOD ||
1098                tag == CONSTANT_INTERFACEMETHOD ||
1099                tag == CONSTANT_NAMEANDTYPE) {
1100                    out.writeShort(index1);
1101                }
1102            }
1103            
1104            public int hashCode() {
1105                return tag + index0 + index1;
1106            }
1107            
1108            public boolean equals(Object JavaDoc obj) {
1109                if (obj instanceof IndirectEntry) {
1110                    IndirectEntry other = (IndirectEntry) obj;
1111                    if (tag == other.tag &&
1112                    index0 == other.index0 && index1 == other.index1) {
1113                        return true;
1114                    }
1115                }
1116                return false;
1117            }
1118        }
1119    }
1120}
1121
Popular Tags