KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > enhancer > CommonClassGenerator


1 /**
2  * EasyBeans
3  * Copyright (C) 2006 Bull S.A.S.
4  * Contact: easybeans@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: CommonClassGenerator.java 1133 2006-10-04 14:30:41Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.enhancer;
27
28 import org.objectweb.asm.ClassVisitor;
29 import org.objectweb.asm.ClassWriter;
30 import org.objectweb.asm.FieldVisitor;
31 import org.objectweb.asm.MethodVisitor;
32 import org.objectweb.asm.Opcodes;
33 import org.objectweb.asm.Type;
34 import org.objectweb.easybeans.api.Factory;
35
36 /**
37  * Class with useful routines for writing a class.
38  * @author Florent Benoit
39  */

40 public abstract class CommonClassGenerator implements Opcodes {
41
42     /**
43      * Define an array of objects.
44      */

45     public static final String JavaDoc ARRAY_OBJECTS = "[Ljava/lang/Object;";
46
47     /**
48      * Defines java.lang.Object class.
49      */

50     public static final String JavaDoc JAVA_LANG_OBJECT = "Ljava/lang/Object;";
51
52     /**
53      * Defines a void method with JAVA_LANG_OBJECT as parameter.
54      */

55     public static final String JavaDoc VOID_METHOD_JAVA_LANG_OBJECT = "(Ljava/lang/Object;)V";
56
57     /**
58      * Defines java.lang.Exception class.
59      */

60     public static final String JavaDoc JAVA_LANG_EXCEPTION = "Ljava/lang/Exception;";
61
62     /**
63      * Define java.lang.reflect.Method.
64      */

65     public static final String JavaDoc JAVA_LANG_REFLECT_METHOD = "Ljava/lang/reflect/Method;";
66
67     /**
68      * Factory class (used to make the bean factory available).
69      */

70     public static final String JavaDoc EASYBEANS_FACTORY = Type.getDescriptor(Factory.class);
71
72     /**
73      * Version used for generated class.
74      */

75     public static final int GENERATED_CLASS_VERSION = V1_5;
76
77     /**
78      * The {@link org.objectweb.asm.ClassWriter} to which this adapter delegates
79      * calls.
80      */

81     private ClassWriter cw;
82
83     /**
84      * Field visitor.
85      */

86     private FieldVisitor fv = null;
87
88     /**
89      * Creates a default class with useful routines for writing a class.
90      * @param cw the class writer which will generate the class
91      */

92     public CommonClassGenerator(final ClassWriter cw) {
93         this.cw = cw;
94     }
95
96     /**
97      * Adds an attribute in the current classwriter.
98      * @param access the field's access flags (see {@link Opcodes}). This
99      * parameter also indicates if the field is synthetic and/or
100      * deprecated.
101      * @param name the field's name.
102      * @param desc the field's descriptor (see {@link Type Type}).
103      */

104     protected void addAttribute(final int access, final String JavaDoc name, final String JavaDoc desc) {
105         addAttribute(access, name, desc, null);
106     }
107
108     /**
109      * Adds an attribute in the current classwriter.
110      * @param access the field's access flags (see {@link Opcodes}). This
111      * parameter also indicates if the field is synthetic and/or
112      * deprecated.
113      * @param name the field's name.
114      * @param desc the field's descriptor (see {@link Type Type}).
115      * @param value the field's initial value. This parameter, which may be
116      * <tt>null</tt> if the field does not have an initial value, must
117      * be an {@link Integer}, a {@link Float}, a {@link Long}, a
118      * {@link Double} or a {@link String} (for <tt>int</tt>,
119      * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
120      * respectively). <i>This parameter is only used for static fields</i>.
121      * Its value is ignored for non static fields, which must be
122      * initialized through bytecode instructions in constructors or
123      * methods.
124      */

125     protected void addAttribute(final int access, final String JavaDoc name, final String JavaDoc desc, final Object JavaDoc value) {
126         fv = cw.visitField(access, name, desc, null, value);
127         fv.visitEnd();
128     }
129
130     /**
131      * Encodes an internal classname into a descriptor.
132      * @param className internal class name
133      * @return desc for the given className
134      */

135     public static String JavaDoc encodeClassDesc(final String JavaDoc className) {
136         return "L" + className + ";";
137     }
138
139     /**
140      * Encodes an internal classname into an array descriptor.
141      * @param className internal class name
142      * @return desc for the given className (array mode)
143      */

144     public static String JavaDoc encodeArrayClassDesc(final String JavaDoc className) {
145         return "[L" + className + ";";
146     }
147
148     /**
149      * @return the class writer used by this generator
150      */

151     public ClassWriter getCW() {
152         return cw;
153     }
154
155     /**
156      * Sends the OpCode used in an constructor to set the field.
157      * @param sortCode type of attribute to set
158      * @return op code
159      */

160     public static int putFieldLoadOpCode(final int sortCode) {
161         switch (sortCode) {
162             case Type.BOOLEAN:
163             case Type.BYTE:
164             case Type.CHAR:
165             case Type.SHORT:
166             case Type.INT:
167                 return ILOAD;
168             case Type.FLOAT:
169                 return FLOAD;
170             case Type.LONG:
171                 return LLOAD;
172             case Type.DOUBLE:
173                 return DLOAD;
174             // case ARRAY:
175
// case OBJECT:
176
default:
177                 return ALOAD;
178         }
179     }
180
181     /**
182      * If a type is one of the primitive object : boolean, int, long, etc, adds an instruction to transform type into an object.
183      * ie : from int to Integer by calling Integer.valueOf(i);
184      * @param type the object that need to be processed
185      * @param mv the method visitor on which there is a need to adds an instruction
186      */

187     public static void transformPrimitiveIntoObject(final Type type, final MethodVisitor mv) {
188         switch (type.getSort()) {
189             case Type.BOOLEAN:
190                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
191                 break;
192             case Type.BYTE:
193                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
194                 break;
195             case Type.CHAR:
196                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
197                 break;
198             case Type.SHORT:
199                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
200                 break;
201             case Type.INT:
202                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
203                 break;
204             case Type.FLOAT:
205                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
206                 break;
207             case Type.LONG:
208                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
209                 break;
210             case Type.DOUBLE:
211                 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
212                 break;
213             // case ARRAY:
214
// case OBJECT:
215
default:
216                 // nothing as this is already objects !
217
break;
218         }
219     }
220
221     /**
222      * If a type is one of the object type with something which could be linked to a primitive type, cast object into primitive.
223      * ie : from Integer to int by calling ((Integer) object).intValue();
224      * @param type the object that need to be processed
225      * @param mv the method visitor on which there is a need to adds an instruction
226      */

227     public static void transformObjectIntoPrimitive(final Type type, final MethodVisitor mv) {
228         switch (type.getSort()) {
229             case Type.BOOLEAN:
230                 mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
231                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
232                 break;
233             case Type.BYTE:
234                 mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
235                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
236                 break;
237             case Type.CHAR:
238                 mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
239                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
240                 break;
241             case Type.SHORT:
242                 mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
243                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
244                 break;
245             case Type.INT:
246                 mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
247                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
248                 break;
249             case Type.FLOAT:
250                 mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
251                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
252                 break;
253             case Type.LONG:
254                 mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
255                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
256                 break;
257             case Type.DOUBLE:
258                 mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
259                 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
260                 break;
261             case Type.VOID:
262                 mv.visitInsn(POP);
263                 break;
264              case Type.ARRAY:
265                  mv.visitTypeInsn(CHECKCAST, type.getDescriptor());
266                  break;
267             case Type.OBJECT:
268                 mv.visitTypeInsn(CHECKCAST, type.getInternalName());
269                 break;
270             default:
271                 // nothing as this is already objects !
272
break;
273         }
274     }
275
276
277     /**
278      * Adds a return entry depending of the type value.
279      * ie, for int : mv.visitInsn(IRETURN);
280      * for void : mv.visitInsn(RETURN);
281      * @param type the object that need to be processed
282      * @param mv the method visitor on which there is a need to adds an instruction
283      */

284     public static void addReturnType(final Type type, final MethodVisitor mv) {
285         switch (type.getSort()) {
286             case Type.BOOLEAN:
287             case Type.BYTE:
288             case Type.CHAR:
289             case Type.SHORT:
290             case Type.INT:
291                 mv.visitInsn(IRETURN);
292                 break;
293             case Type.FLOAT:
294                 mv.visitInsn(FRETURN);
295                 break;
296             case Type.LONG:
297                 mv.visitInsn(LRETURN);
298                 break;
299             case Type.DOUBLE:
300                 mv.visitInsn(DRETURN);
301                 break;
302             case Type.VOID:
303                 mv.visitInsn(RETURN);
304                 break;
305              case Type.ARRAY:
306              case Type.OBJECT:
307                  mv.visitInsn(ARETURN);
308                  break;
309             default:
310                 // nothing as this is already objects !
311
break;
312         }
313     }
314
315
316
317
318
319     /**
320      * Allow to access to a class.<br>
321      * ie, for int.class it will access to Integer.TYPE.<br>
322      * For objects, it only calls the Object.
323      * @param type the type of the object from which we want the class
324      * @param mv object on which we add the instruction
325      */

326     public static void visitClassType(final Type type, final MethodVisitor mv) {
327         switch (type.getSort()) {
328             case Type.BOOLEAN:
329                 mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
330                 break;
331             case Type.BYTE:
332                 mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
333                 break;
334             case Type.CHAR:
335                 mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
336                 break;
337             case Type.SHORT:
338                 mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
339                 break;
340             case Type.INT:
341                 mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
342                 break;
343             case Type.FLOAT:
344                 mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
345                 break;
346             case Type.LONG:
347                 mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
348                 break;
349             case Type.DOUBLE:
350                 mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
351                 break;
352             // case ARRAY:
353
// case OBJECT:
354
default:
355                 mv.visitLdcInsn(type);
356                 break;
357         }
358     }
359
360     /**
361      * Returns the object by casting it or return null if method is of void type.
362      * @param returnType the kind of return for this method.
363      * @param mv object on which we add the instruction.
364      */

365     public static void returnsObject(final Type returnType, final MethodVisitor mv) {
366         if (returnType.equals(Type.VOID_TYPE)) {
367             mv.visitInsn(ACONST_NULL);
368         } else {
369             transformPrimitiveIntoObject(returnType, mv);
370         }
371         mv.visitInsn(ARETURN);
372     }
373
374     /**
375      * Adds a field with its getters/setters.
376      * @param cv the classvisitor to add field/methods
377      * @param beanClassName the name of the bean's class
378      * @param fieldName the name of the attribute
379      * @param clazz the class of the attribute.
380      */

381     public static void addFieldGettersSetters(final ClassVisitor cv, final String JavaDoc beanClassName,
382             final String JavaDoc fieldName, final Class JavaDoc clazz) {
383         String JavaDoc className = Type.getDescriptor(clazz);
384         addFieldGettersSetters(cv, beanClassName, fieldName, className);
385     }
386
387     /**
388      * Adds a field with its getters/setters.
389      * @param cv the classvisitor to add field/methods
390      * @param beanClassName the name of the bean's class
391      * @param fieldName the name of the attribute
392      * @param className the className of the attribute.
393      */

394     public static void addFieldGettersSetters(final ClassVisitor cv, final String JavaDoc beanClassName,
395             final String JavaDoc fieldName, final String JavaDoc className) {
396
397
398         // Get type of the class
399
Type type = Type.getType(className);
400
401         // Add the fieldName attribute
402
// private CLASSNAME fieldName = null;
403
FieldVisitor fv = cv.visitField(ACC_PRIVATE, fieldName, className, null, null);
404         fv.visitEnd();
405
406         // build getterName
407
String JavaDoc appendName = fieldName.toUpperCase().charAt(0) + fieldName.substring(1);
408         String JavaDoc getterName = "get" + appendName;
409
410         // Add its getter :
411
// public CLASSNAME getterName() {
412
// return this.fieldName;
413
// }
414
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, getterName, "()" + className, null, null);
415         mv.visitCode();
416         mv.visitVarInsn(ALOAD, 0);
417         mv.visitFieldInsn(GETFIELD, beanClassName, fieldName, className);
418         // return type is depending of the type
419
addReturnType(type, mv);
420         mv.visitMaxs(0, 0);
421         mv.visitEnd();
422
423         // Add the setter
424
// public void setterName(final CLASSNAME setterName) {
425
// this.fieldName = fieldName;
426
// }
427
String JavaDoc setterName = "set" + appendName;
428         mv = cv.visitMethod(ACC_PUBLIC, setterName, "(" + className + ")V", null, null);
429         mv.visitCode();
430         mv.visitVarInsn(ALOAD, 0);
431         // Depends of the type
432
int opCode = putFieldLoadOpCode(type.getSort());
433         mv.visitVarInsn(opCode, 1);
434         mv.visitFieldInsn(PUTFIELD, beanClassName, fieldName, className);
435         mv.visitInsn(RETURN);
436         mv.visitMaxs(0, 0);
437         mv.visitEnd();
438     }
439
440     /**
441      * Adds a getter for a given fieldName. If the fieldName is null, it's return null.
442      * @param cv the classvisitor to add the method
443      * @param getterName the name of the method
444      * @param clazz the class of the returned object.
445      */

446     public static void addNullGetter(final ClassVisitor cv, final String JavaDoc getterName, final Class JavaDoc clazz) {
447         String JavaDoc returnedClassName = Type.getDescriptor(clazz);
448         // Add its getter :
449
// public returnedClassName getterName() {
450
// return null;
451
// }
452
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, getterName, "()" + returnedClassName, null, null);
453         mv.visitCode();
454         mv.visitInsn(ACONST_NULL);
455         mv.visitInsn(ARETURN);
456
457         mv.visitMaxs(0, 0);
458         mv.visitEnd();
459     }
460
461
462 }
463
Popular Tags