KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > classes > ClassItem


1 /*
2 Copyright (c) 2003-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.binding.classes;
30
31 import java.util.HashMap JavaDoc;
32
33 import org.apache.bcel.Constants;
34 import org.apache.bcel.classfile.ExceptionTable;
35 import org.apache.bcel.classfile.FieldOrMethod;
36 import org.apache.bcel.classfile.Method;
37 import org.apache.bcel.classfile.Utility;
38 import org.apache.bcel.generic.ArrayType;
39 import org.apache.bcel.generic.ObjectType;
40 import org.apache.bcel.generic.Type;
41 import org.jibx.runtime.JiBXException;
42
43 /**
44  * Wrapper for field or method information. Provides the information needed
45  * for access to either existing or added methods in existing classes.
46  *
47  * @author Dennis M. Sosnoski
48  * @version 1.0
49  */

50
51 public class ClassItem
52 {
53     /** Empty array of strings. */
54     private static final String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
55     
56     /** Map for primitive type signature variants. */
57     private static HashMap JavaDoc s_primitiveMap = new HashMap JavaDoc();
58     
59     /** Map from type name to BCEL type. */
60     private static HashMap JavaDoc s_typeMap = new HashMap JavaDoc();
61     
62     /** Map from method signature to array of argument types. */
63     private static HashMap JavaDoc s_signatureParamsMap = new HashMap JavaDoc();
64     
65     /** Map from method signature to return type. */
66     private static HashMap JavaDoc s_signatureTypeMap = new HashMap JavaDoc();
67     
68     static {
69         s_primitiveMap.put("boolean", new String JavaDoc[] { "Z", "I" });
70         s_primitiveMap.put("byte", new String JavaDoc[] { "B", "S", "I" });
71         s_primitiveMap.put("char", new String JavaDoc[] { "C", "I" });
72         s_primitiveMap.put("double", new String JavaDoc[] { "D" });
73         s_primitiveMap.put("float", new String JavaDoc[] { "F" });
74         s_primitiveMap.put("int", new String JavaDoc[] { "I" });
75         s_primitiveMap.put("long", new String JavaDoc[] { "J" });
76         s_primitiveMap.put("short", new String JavaDoc[] { "S", "I" });
77         s_primitiveMap.put("void", new String JavaDoc[] { "V" });
78         s_typeMap.put("boolean", Type.BOOLEAN);
79         s_typeMap.put("byte", Type.BYTE);
80         s_typeMap.put("char", Type.CHAR);
81         s_typeMap.put("double", Type.DOUBLE);
82         s_typeMap.put("float", Type.FLOAT);
83         s_typeMap.put("int", Type.INT);
84         s_typeMap.put("long", Type.LONG);
85         s_typeMap.put("short", Type.SHORT);
86         s_typeMap.put("void", Type.VOID);
87     }
88     
89     /** Owning class information. */
90     private ClassFile m_classFile;
91     
92     /** Item name. */
93     private String JavaDoc m_name;
94     
95     /** Encoded signature. */
96     private String JavaDoc m_signature;
97     
98     /** Fully qualified class name of item type. */
99     private String JavaDoc m_typeName;
100     
101     /** Argument types for method. */
102     private String JavaDoc[] m_argTypes;
103     
104     /** Wrapped existing item. */
105     private FieldOrMethod m_item;
106     
107     /**
108      * Constructor. Builds a wrapper for an item based on an existing field or
109      * method.
110      *
111      * @param name field or method name
112      * @param clas owning class information
113      * @param item field or method information
114      */

115      
116     public ClassItem(String JavaDoc name, ClassFile cf, FieldOrMethod item) {
117         m_classFile = cf;
118         m_name = name;
119         m_item = item;
120         m_signature = item.getSignature();
121         if (item instanceof Method) {
122             m_typeName = getTypeFromSignature(m_signature);
123             m_argTypes = getParametersFromSignature(m_signature);
124         } else {
125             m_typeName = Utility.signatureToString(m_signature, false);
126         }
127     }
128     
129     /**
130      * Get owning class information.
131      *
132      * @return owning class information
133      */

134      
135     public ClassFile getClassFile() {
136         return m_classFile;
137     }
138     
139     /**
140      * Get item name.
141      *
142      * @return item name
143      */

144      
145     public String JavaDoc getName() {
146         return m_name;
147     }
148     
149     /**
150      * Get item type as fully qualified class name.
151      *
152      * @return item type name
153      */

154      
155     public String JavaDoc getTypeName() {
156         return m_typeName;
157     }
158     
159     /**
160      * Get number of arguments for method.
161      *
162      * @return argument count for method, or zero if not a method
163      */

164      
165     public int getArgumentCount() {
166         if (m_item instanceof Method) {
167             return m_argTypes.length;
168         } else {
169             return 0;
170         }
171     }
172     
173     /**
174      * Get argument type as fully qualified class name.
175      *
176      * @param index argument number
177      * @return argument type name
178      */

179      
180     public String JavaDoc getArgumentType(int index) {
181         if (m_item instanceof Method) {
182             return m_argTypes[index];
183         } else {
184             return null;
185         }
186     }
187     
188     /**
189      * Get argument types as array of fully qualified class names.
190      *
191      * @return array of argument types
192      */

193      
194     public String JavaDoc[] getArgumentTypes() {
195         if (m_item instanceof Method) {
196             return m_argTypes;
197         } else {
198             return null;
199         }
200     }
201     
202     /**
203      * Get access flags.
204      *
205      * @return flags for access type of field or method
206      */

207      
208     public int getAccessFlags() {
209         return m_item.getAccessFlags();
210     }
211     
212     /**
213      * Set access flags.
214      *
215      * @param flags access flags for field or method
216      */

217      
218     public void setAccessFlags(int flags) {
219         m_item.setAccessFlags(flags);
220         m_classFile.setModified();
221     }
222
223     /**
224      * Make accessible item. Check if this field or method is accessible from
225      * another class, and if not decreases the access restrictions to make it
226      * accessible.
227      *
228      * @param src class file for required access
229      * @throws JiBXException if cannot be accessed
230      */

231
232     public void makeAccessible(ClassFile src) throws JiBXException {
233         
234         // no need to change if already public access
235
int access = getAccessFlags();
236         if ((access & Constants.ACC_PUBLIC) == 0) {
237             
238             // check for same package as most restrictive case
239
ClassFile dest = getClassFile();
240             if (dest.getPackage().equals(src.getPackage())) {
241                 if ((access & Constants.ACC_PRIVATE) != 0) {
242                     access = access - Constants.ACC_PRIVATE;
243                 }
244             } else {
245                 
246                 // check if access is from a subclass of this method class
247
ClassFile ancestor = src;
248                 while ((ancestor = ancestor.getSuperFile()) != null) {
249                     if (ancestor == dest) {
250                         break;
251                     }
252                 }
253                 
254                 // handle access adjustments based on subclass status
255
if (ancestor == null) {
256                     int clear = Constants.ACC_PRIVATE |
257                         Constants.ACC_PROTECTED;
258                     access = (access & ~clear) | Constants.ACC_PUBLIC;
259                 } else if ((access & Constants.ACC_PROTECTED) == 0) {
260                     access = (access & ~Constants.ACC_PRIVATE) |
261                         Constants.ACC_PROTECTED;
262                 }
263             }
264             
265             // set new access flags
266
if (access != getAccessFlags()) {
267                 if (dest.isModifiable()) {
268                     setAccessFlags(access);
269                 } else {
270                     throw new JiBXException
271                         ("Unable to change access permissions for " +
272                         getName() + " in class " + src.getName());
273                 }
274             }
275         }
276     }
277     
278     /**
279      * Check if item is a static.
280      *
281      * @return <code>true</code> if a static, <code>false</code> if member
282      */

283      
284     public boolean isStatic() {
285         return (getAccessFlags() & Constants.ACC_STATIC) != 0;
286     }
287     
288     /**
289      * Get method signature.
290      *
291      * @return encoded method signature
292      */

293      
294     public String JavaDoc getSignature() {
295         return m_signature;
296     }
297     
298     /**
299      * Check if item is a method.
300      *
301      * @return <code>true</code> if a method, <code>false</code> if a field
302      */

303      
304     public boolean isMethod() {
305         return m_item == null || m_item instanceof Method;
306     }
307     
308     /**
309      * Check if item is an initializer.
310      *
311      * @return <code>true</code> if an initializer, <code>false</code> if a
312      * field or normal method
313      */

314      
315     public boolean isInitializer() {
316         return m_item != null && m_item.getName().equals("<init>");
317     }
318     
319     /**
320      * Get names of exceptions thrown by method.
321      *
322      * @return array of exceptions thrown by method, or <code>null</code> if
323      * a field
324      */

325      
326     public String JavaDoc[] getExceptions() {
327         if (m_item instanceof Method) {
328             ExceptionTable etab = ((Method)m_item).getExceptionTable();
329             if (etab != null) {
330                 return etab.getExceptionNames();
331             } else {
332                 return EMPTY_STRING_ARRAY;
333             }
334         }
335         return null;
336     }
337     
338     /**
339      * Check if type name is a primitive.
340      *
341      * @return <code>true</code> if a primitive, <code>false</code> if not
342      */

343      
344     public static boolean isPrimitive(String JavaDoc type) {
345         return s_primitiveMap.get(type) != null;
346     }
347     
348     /**
349      * Get the signature for a primitive.
350      *
351      * @return signature for a primitive type
352      */

353      
354     public static String JavaDoc getPrimitiveSignature(String JavaDoc type) {
355         return ((String JavaDoc[])s_primitiveMap.get(type))[0];
356     }
357     
358     /**
359      * Get parameter type names from method signature.
360      *
361      * @param sig method signature to be decoded
362      * @return array of argument type names
363      */

364      
365     public static String JavaDoc[] getParametersFromSignature(String JavaDoc sig) {
366         String JavaDoc[] types = (String JavaDoc[])s_signatureParamsMap.get(sig);
367         if (types == null) {
368             types = Utility.methodSignatureArgumentTypes(sig, false);
369             s_signatureParamsMap.put(sig, types);
370         }
371         return types;
372     }
373     
374     /**
375      * Get return type names from method signature.
376      *
377      * @param sig method signature to be decoded
378      * @return return type name
379      */

380      
381     public static String JavaDoc getTypeFromSignature(String JavaDoc sig) {
382         String JavaDoc type = (String JavaDoc)s_signatureTypeMap.get(sig);
383         if (type == null) {
384             type = Utility.methodSignatureReturnType(sig, false);
385             s_signatureTypeMap.put(sig, type);
386         }
387         return type;
388     }
389
390     /**
391      * Create type from name.
392      *
393      * @param name fully qualified type name
394      * @return corresponding type
395      */

396
397     public static Type typeFromName(String JavaDoc name) {
398         
399         // first check for type already created
400
Type type = (Type)s_typeMap.get(name);
401         if (type == null) {
402             
403             // new type, strip off array dimensions
404
int dimen = 0;
405             String JavaDoc base = name;
406             while (base.endsWith("[]")) {
407                 dimen++;
408                 base = base.substring(0, base.length()-2);
409             }
410             
411             // check for base type defined if array
412
if (dimen > 0) {
413                 type = (Type)s_typeMap.get(base);
414             }
415             
416             // create and record base type if new
417
if (type == null) {
418                 type = new ObjectType(base);
419                 s_typeMap.put(base, type);
420             }
421             
422             // create and record array type
423
if (dimen > 0) {
424                 type = new ArrayType(type, dimen);
425                 s_typeMap.put(name, type);
426             }
427         }
428         return type;
429     }
430     
431     /**
432      * Get virtual method by fully qualified name. This splits the class
433      * name from the method name, finds the class, and then tries to find a
434      * matching method name in that class or a superclass.
435      *
436      * @param name fully qualified class and method name
437      * @param sigs possible method signatures
438      * @return information for the method, or <code>null</code> if not found
439      * @throws JiBXException if configuration error
440      */

441     
442     public static ClassItem findVirtualMethod(String JavaDoc name, String JavaDoc[] sigs)
443         throws JiBXException {
444         
445         // get the class containing the method
446
int split = name.lastIndexOf('.');
447         String JavaDoc cname = name.substring(0, split);
448         String JavaDoc mname = name.substring(split+1);
449         ClassFile cf = ClassCache.getClassFile(cname);
450         
451         // find the method in class or superclass
452
for (int i = 0; i < sigs.length; i++) {
453             ClassItem method = cf.getMethod(mname, sigs[i]);
454             if (method != null) {
455                 return method;
456             }
457         }
458         return null;
459     }
460     
461     /**
462      * Get static method by fully qualified name. This splits the class
463      * name from the method name, finds the class, and then tries to find a
464      * matching method name in that class.
465      *
466      * @param name fully qualified class and method name
467      * @param sigs possible method signatures
468      * @return information for the method, or <code>null</code> if not found
469      * @throws JiBXException if configuration error
470      */

471     
472     public static ClassItem findStaticMethod(String JavaDoc name, String JavaDoc[] sigs)
473         throws JiBXException {
474         
475         // get the class containing the method
476
int split = name.lastIndexOf('.');
477         String JavaDoc cname = name.substring(0, split);
478         String JavaDoc mname = name.substring(split+1);
479         ClassFile cf = ClassCache.getClassFile(cname);
480         
481         // find the method in class or superclass
482
for (int i = 0; i < sigs.length; i++) {
483             ClassItem method = cf.getStaticMethod(mname, sigs[i]);
484             if (method != null) {
485                 return method;
486             }
487         }
488         return null;
489     }
490     
491     /**
492      * Get all variant signatures for a fully qualified class name. The
493      * returned array gives all signatures (for interfaces or classes) which
494      * instances of the class can match.
495      *
496      * @param name fully qualified class name
497      * @return possible signature variations for instances of the class
498      * @throws JiBXException if configuration error
499      */

500     
501     public static String JavaDoc[] getSignatureVariants(String JavaDoc name)
502         throws JiBXException {
503         Object JavaDoc obj = s_primitiveMap.get(name);
504         if (obj == null) {
505             ClassFile cf = ClassCache.getClassFile(name);
506             return cf.getInstanceSigs();
507         } else {
508             return (String JavaDoc[])obj;
509         }
510     }
511     
512     /**
513      * Check if a value of one type can be directly assigned to another type.
514      * This is basically the equivalent of the instanceof operator, but with
515      * application to primitive types as well as object types.
516      *
517      * @param from fully qualified class name of initial type
518      * @param to fully qualified class name of assignment type
519      * @return <code>true</code> if assignable, <code>false</code> if not
520      * @throws JiBXException if configuration error
521      */

522     
523     public static boolean isAssignable(String JavaDoc from, String JavaDoc to)
524         throws JiBXException {
525         
526         // always assignable if the two are the same
527
if (from.equals(to)) {
528             return true;
529         } else {
530             
531             // try direct lookup for primitive types
532
Object JavaDoc fobj = s_primitiveMap.get(from);
533             Object JavaDoc tobj = s_primitiveMap.get(to);
534             if (fobj == null && tobj == null) {
535                 
536                 // assignable if from type has to as a possible signature
537
ClassFile cf = ClassCache.getClassFile(from);
538                 String JavaDoc[] sigs = cf.getInstanceSigs();
539                 String JavaDoc match = Utility.getSignature(to);
540                 for (int i = 0; i < sigs.length; i++) {
541                     if (match.equals(sigs[i])) {
542                         return true;
543                     }
544                 }
545                 return false;
546                 
547             } else if (fobj != null && tobj != null) {
548                 
549                 // assignable if from type has to as a possible signature
550
String JavaDoc[] fsigs = (String JavaDoc[])fobj;
551                 String JavaDoc[] tsigs = (String JavaDoc[])tobj;
552                 if (tsigs.length == 1) {
553                     for (int i = 0; i < fsigs.length; i++) {
554                         if (fsigs[i] == tsigs[0]) {
555                             return true;
556                         }
557                     }
558                 }
559                 return false;
560                 
561             } else {
562                 
563                 // primitive and object types never assignable
564
return false;
565                 
566             }
567         }
568     }
569 }
Popular Tags