KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > vladium > jcd > lib > Types


1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2  *
3  * This program and the accompanying materials are made available under
4  * the terms of the Common Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
6  *
7  * $Id: Types.java,v 1.1.1.1 2004/05/09 16:57:50 vlad_r Exp $
8  */

9 package com.vladium.jcd.lib;
10
11 import java.io.IOException JavaDoc;
12 import java.lang.reflect.*;
13
14 import com.vladium.jcd.cls.IAccessFlags;
15
16 // ----------------------------------------------------------------------------
17
/**
18  * Utility methods for manipulating type signatures and descriptors.
19  *
20  * TODO: fix usage of chars in parsers
21  *
22  * @author (C) 2001, Vlad Roubtsov
23  */

24 public abstract class Types
25 {
26     // public: ................................................................
27

28     /**
29      * Returns 'c''s package name [does not include trailing '.'] or ""
30      * if 'c' is in the default package.
31      */

32     public static String JavaDoc getClassPackageName (final Class JavaDoc c)
33     {
34         // TODO: handle array and other types
35

36         final String JavaDoc className = c.getName ();
37         final int lastDot = className.lastIndexOf ('.');
38         return lastDot >= 0 ? className.substring (0, lastDot) : "";
39     }
40     
41     
42     public static String JavaDoc accessFlagsToString (final int flags, final boolean isClass)
43     {
44         final StringBuffer JavaDoc result = new StringBuffer JavaDoc ();
45       
46         boolean first = true;
47         
48         if (isClass)
49         {
50             for (int f = 0; f < IAccessFlags.ALL_ACC.length; ++ f)
51             {
52                 final int bit = IAccessFlags.ALL_ACC [f];
53                 
54                 if ((flags & bit) != 0)
55                 {
56                     if (first)
57                         first = false;
58                     else
59                         result.append (" ");
60                     
61                     if (bit == IAccessFlags.ACC_SUPER)
62                         result.append ("super");
63                     else
64                         result.append (IAccessFlags.ALL_ACC_NAMES [f]);
65                 }
66             }
67         }
68         else
69         {
70             for (int f = 0; f < IAccessFlags.ALL_ACC.length; ++ f)
71             {
72                 final int bit = IAccessFlags.ALL_ACC [f];
73                 
74                 if ((flags & bit) != 0)
75                 {
76                     if (first)
77                         first = false;
78                     else
79                         result.append (" ");
80                         
81                     result.append (IAccessFlags.ALL_ACC_NAMES [f]);
82                 }
83             }
84         }
85         
86         return result.toString ();
87     }
88
89     
90     /**
91      * Converts Java-styled package/class name to how it would be
92      * represented in the VM.<P>
93      *
94      * Example:<BR>
95      * javaNameToVMName("java.lang.Object") = "java/lang/Object"
96      *
97      * @see #vmNameToJavaName
98      */

99     public static String JavaDoc javaNameToVMName (final String JavaDoc javaName)
100     {
101         if (javaName == null) return null;
102         return javaName.replace ('.', '/');
103     }
104     
105     
106     /**
107      * Converts a VM-styled package/class name to how it would be
108      * represented in Java.<P>
109      *
110      * Example:<BR>
111      * vmNameToJavaName("java/lang/Object") = "java.lang.Object"
112      *
113      * @see #javaNameToVMName
114      */

115     public static String JavaDoc vmNameToJavaName (final String JavaDoc vmName)
116     {
117         if (vmName == null) return null;
118         return vmName.replace ('/', '.');
119     }
120     
121     
122     /**
123      * Converts a method signature to its VM descriptor representation.
124      * See $4.3 of the VM spec 1.0 for the descriptor grammar.<P>
125      *
126      * Example:<BR>
127      * signatureToDescriptor(new Object().getClass().getMethod("equals" ,new Class[0])) = "(Ljava/lang/Object;)Z"
128      * <P>
129      *
130      * Equivalent to
131      * <CODE>signatureToDescriptor(method.getParameterTypes (), method.getReturnType ())</CODE>.
132      */

133     public static String JavaDoc signatureToDescriptor (Method method)
134     {
135         if (method == null) throw new IllegalArgumentException JavaDoc ("null input: method");
136         return signatureToDescriptor (method.getParameterTypes (), method.getReturnType ());
137     }
138     
139     
140     /**
141      * Converts a method signature (parameter types + return type) to its VM descriptor
142      * representation. See $4.3 of the VM spec 1.0 for the descriptor grammar.<P>
143      */

144     public static String JavaDoc signatureToDescriptor (Class JavaDoc [] parameterTypes, Class JavaDoc returnType)
145     {
146         return new signatureCompiler ().signatureDescriptor (parameterTypes, returnType);
147     }
148     
149     
150     /**
151      * Converts a type (a Class) to its VM descriptor representation.<P>
152      *
153      * Example:<BR>
154      * typeToDescriptor(Object.class) = "Ljava/lang/Object;" <BR>
155      * typeToDescriptor(boolean.class) = "Z"
156      * <P>
157      * Note the invariant typeToDescriptor(descriptorToType(desc)) == desc.
158      *
159      * @see #descriptorToType
160      */

161     public static String JavaDoc typeToDescriptor (Class JavaDoc type)
162     {
163         return new signatureCompiler ().typeDescriptor (type);
164     }
165     
166     
167     /**
168      * Converts a VM descriptor to the corresponding type.<P>
169      *
170      * Example:<BR>
171      * descriptorToType("[[I") = int[][].class <BR>
172      * descriptorToType("B") = byte.class
173      * <P>
174      * Note the invariant descriptorToType(typeToDescriptor(c)) == c.
175      *
176      * @see #descriptorToType
177      */

178     public static Class JavaDoc descriptorToType (String JavaDoc typedescriptor) throws ClassNotFoundException JavaDoc
179     {
180         return new typeDescriptorCompiler ().descriptorToClass (typedescriptor);
181     }
182     
183     
184     
185     public static String JavaDoc descriptorToReturnType (String JavaDoc methoddescriptor)
186     {
187         final int i1 = methoddescriptor.indexOf ('(');
188         final int i2 = methoddescriptor.lastIndexOf (')');
189         
190         if ((i1 < 0) || (i2 <= 0) || (i1 >= i2) || (i2 >= methoddescriptor.length () - 1))
191             throw new IllegalArgumentException JavaDoc ("malformed method descriptor: [" + methoddescriptor + "]");
192
193         return methoddescriptor.substring (i2 + 1);
194     }
195     
196     
197     public static String JavaDoc [] descriptorToParameterTypes (String JavaDoc methoddescriptor)
198     {
199         //System.out.println ("METHOD DESCRIPTOR: [" + methoddescriptor + "]");
200

201         try
202         {
203             final methodDescriptorCompiler compiler = new methodDescriptorCompiler (methoddescriptor);
204             compiler.methodDescriptor ();
205             return compiler.getResult ();
206         }
207         catch (IOException JavaDoc e)
208         {
209             throw new IllegalArgumentException JavaDoc ("error parsing [" + methoddescriptor + "]: " + e.toString ());
210         }
211         
212         /*
213         final java.util.Vector _result = new java.util.Vector ();
214         final StringBuffer token = new StringBuffer ();
215
216         char c = '*';
217         int scan = 0;
218         
219         for (int state = 0; state != 4; )
220         {
221             try
222             {
223                 switch (state)
224                 {
225                 case 0:
226                     c = methoddescriptor.charAt (scan++);
227                     if (c == '(')
228                         state = 1;
229                     else
230                         throw new IllegalArgumentException ("malformed method descriptor: [" + methoddescriptor + "]");
231                     break;
232                     
233                 case 1:
234                     c = methoddescriptor.charAt (scan);
235                     switch (c)
236                     {
237                     case 'B':
238                     case 'C':
239                     case 'D':
240                     case 'F':
241                     case 'I':
242                     case 'J':
243                     case 'S':
244                     case 'Z':
245                         token.append (c);
246                         _result.addElement (token.toString ());
247                         token.setLength (0);
248                         scan++;
249                         break;
250                         
251                     case 'L':
252                         state = 2;
253                         token.append (c);
254                         scan++;
255                         break;
256                         
257                     case '[':
258                         state = 3;
259                         token.append (c);
260                         scan++;
261                         break;
262                         
263                     case ')':
264                         if (token.length () > 0)
265                         {
266                             _result.addElement (token.toString ());
267                             token.setLength (0);
268                         }
269                         state = 4;
270                         break;
271                             
272                         
273                     default:
274                         throw new IllegalArgumentException ("[state = " + state + ", c = " + c + "] malformed method descriptor: [" + methoddescriptor + "]");
275                         
276                     } // end of nested switch
277                     break;
278                     
279                 case 2:
280                     c = methoddescriptor.charAt (scan++);
281                     token.append (c);
282                     if (c == ';')
283                     {
284                         _result.addElement (token.toString ());
285                         token.setLength (0);
286                         state = 1;
287                     }
288                     break;
289                     
290                 case 3:
291                     c = methoddescriptor.charAt (scan++);
292                     token.append (c);
293                     if (c != '[')
294                     {
295                         state = 1;
296                     }
297                     break;
298                     
299                 } // end of switch
300                 
301                 //System.out.println ("[state = " + state + ", c = " + c + "]");
302             }
303             catch (StringIndexOutOfBoundsException e)
304             {
305                 throw new IllegalArgumentException ("malformed method descriptor: [" + methoddescriptor + "]");
306             }
307         }
308         
309         String [] result = new String [_result.size ()];
310         _result.copyInto (result);
311         
312         return result;
313         */

314     }
315     
316     
317     public static String JavaDoc signatureToMethodDescriptor (final String JavaDoc [] parameterTypeDescriptors, final String JavaDoc returnTypeDescriptor)
318     {
319         final StringBuffer JavaDoc result = new StringBuffer JavaDoc ("(");
320         
321         for (int p = 0; p < parameterTypeDescriptors.length; p++)
322         {
323             result.append (parameterTypeDescriptors [p]);
324         }
325         
326         result.append (')');
327         result.append (returnTypeDescriptor);
328         
329         return result.toString ();
330     }
331     
332     
333     public static String JavaDoc typeDescriptorToUserName (final String JavaDoc typedescriptor)
334     {
335         return new typeDescriptorCompiler2 ().descriptorToClass (typedescriptor);
336     }
337     
338     public static String JavaDoc methodDescriptorToUserName (final String JavaDoc methoddescriptor)
339     {
340         final String JavaDoc [] parameterTypes = descriptorToParameterTypes (methoddescriptor);
341         
342         final StringBuffer JavaDoc result = new StringBuffer JavaDoc ("(");
343         
344         for (int p = 0; p < parameterTypes.length; p++)
345         {
346             //System.out.println ("DESCRIPTOR: [" + parameterTypes [p] + "]");
347

348             if (p > 0) result.append (", ");
349             
350             final String JavaDoc typeUserName = typeDescriptorToUserName (parameterTypes [p]);
351             int lastDot = typeUserName.lastIndexOf ('.');
352             
353             if ((lastDot < 0) || ! "java.lang.".equals (typeUserName.substring (0, lastDot + 1)))
354                 result.append (typeUserName);
355             else
356                 result.append (typeUserName.substring (lastDot + 1));
357         }
358         
359         result.append (')');
360         return result.toString ();
361     }
362     
363     public static String JavaDoc fullMethodDescriptorToUserName (final String JavaDoc classJavaName, String JavaDoc methodName, final String JavaDoc methoddescriptor)
364     {
365         if ("<init>".equals (methodName))
366             methodName = simpleClassName (classJavaName);
367         if ("<clinit>".equals (methodName))
368             methodName = "<static class initializer>";
369         
370         return methodName + ' ' + methodDescriptorToUserName (methoddescriptor);
371     }
372     
373     // TODO: added most recently
374
public static String JavaDoc fullMethodDescriptorToFullUserName (final String JavaDoc classJavaName, String JavaDoc methodName, final String JavaDoc methoddescriptor)
375     {
376         if ("<init>".equals (methodName))
377             methodName = simpleClassName (classJavaName);
378         if ("<clinit>".equals (methodName))
379             methodName = "<static class initializer>";
380         
381         return classJavaName + '.' + methodName + ' ' + methodDescriptorToUserName (methoddescriptor);
382     }
383     
384     // protected: .............................................................
385

386     // package: ...............................................................
387

388     // private: ...............................................................
389

390     
391     private static String JavaDoc simpleClassName (final String JavaDoc classJavaName)
392     {
393         int lastDot = classJavaName.lastIndexOf ('.');
394         
395         if (lastDot < 0)
396             return classJavaName;
397         else
398             return classJavaName.substring (lastDot + 1);
399     }
400                                      
401     
402     
403     private static final class signatureCompiler
404     {
405         String JavaDoc signatureDescriptor (Class JavaDoc [] _parameterTypes, Class JavaDoc _returnType)
406         {
407             emit ('('); parameterTypes (_parameterTypes); emit (')'); returnType (_returnType);
408             
409             return m_desc.toString ();
410         }
411         
412         String JavaDoc typeDescriptor (Class JavaDoc type)
413         {
414             parameterType (type);
415             
416             return m_desc.toString ();
417         }
418         
419         
420         private void parameterTypes (Class JavaDoc [] _parameterTypes)
421         {
422             if (_parameterTypes != null)
423             {
424                 for (int p = 0; p < _parameterTypes.length; p++)
425                 {
426                     parameterType (_parameterTypes [p]);
427                 }
428             }
429         }
430         
431         
432         private void returnType (Class JavaDoc _returnType)
433         {
434             if ((_returnType == null) || (_returnType == Void.TYPE))
435                 emit ('V');
436             else
437                 parameterType (_returnType);
438         }
439         
440         
441         private void parameterType (Class JavaDoc _parameterType)
442         {
443             if (_parameterType != null)
444             {
445                 if (_parameterType.isPrimitive ()) // base type:
446
{
447                     if (byte.class == _parameterType) emit ('B');
448                     else if (char.class == _parameterType) emit ('C');
449                     else if (double.class == _parameterType) emit ('D');
450                     else if (float.class == _parameterType) emit ('F');
451                     else if (int.class == _parameterType) emit ('I');
452                     else if (long.class == _parameterType) emit ('J');
453                     else if (short.class == _parameterType) emit ('S');
454                     else if (boolean.class == _parameterType) emit ('Z');
455                 }
456                 else if (_parameterType.isArray ()) // array type:
457
{
458                     emit ('['); parameterType (_parameterType.getComponentType ());
459                 }
460                 else // object type:
461
{
462                     emit ('L'); emit (javaNameToVMName (_parameterType.getName ())); emit (';');
463                 }
464             }
465         }
466         
467         
468         private void emit (String JavaDoc s)
469         {
470             m_desc.append (s);
471         }
472         
473         private void emit (char c)
474         {
475             m_desc.append (c);
476         }
477         
478         
479         private StringBuffer JavaDoc m_desc = new StringBuffer JavaDoc ();
480         
481     } // end of static class
482

483     
484     
485     private static class typeDescriptorCompiler
486     {
487         /*
488         NOTE: the following would be a very simple solution to this problem
489         
490             Class.forName ('[' + descriptor).getComponentType ();
491         
492         except it only works in MS VM.
493         */

494         
495         Class JavaDoc descriptorToClass (String JavaDoc typedescriptor) throws ClassNotFoundException JavaDoc
496         {
497             char first = typedescriptor.charAt (0);
498             
499             if (first == '[')
500                 // array type:
501
return arrayOf (typedescriptor.substring (1));
502             else if (first == 'L')
503                 // object type:
504
return Class.forName (vmNameToJavaName (typedescriptor.substring (1, typedescriptor.length() - 1)));
505             else // primitive type
506
{
507                 return primitive (first);
508             }
509         }
510         
511         
512         Class JavaDoc arrayOf (String JavaDoc typedescriptor) throws ClassNotFoundException JavaDoc
513         {
514             char first = typedescriptor.charAt (0);
515             Class JavaDoc component;
516             
517             if (first == '[')
518                 // array type:
519
component = arrayOf (typedescriptor.substring (1));
520             else if (first == 'L')
521                 // object type:
522
component = Class.forName (vmNameToJavaName (typedescriptor.substring (1, typedescriptor.length() - 1)));
523             else // primitive type
524
{
525                 component = primitive (first);
526             }
527             
528             Object JavaDoc array = Array.newInstance (component, 0);
529             return array.getClass ();
530         }
531         
532         
533         Class JavaDoc primitive (char c) throws ClassNotFoundException JavaDoc
534         {
535             if (c == 'B') return byte.class;
536             else if (c == 'C') return char.class;
537             else if (c == 'D') return double.class;
538             else if (c == 'F') return float.class;
539             else if (c == 'I') return int.class;
540             else if (c == 'J') return long.class;
541             else if (c == 'S') return short.class;
542             else if (c == 'Z') return boolean.class;
543             else throw new ClassNotFoundException JavaDoc ("unknown base type: " + c);
544         }
545         
546     } // end of static class
547

548     
549     private static class typeDescriptorCompiler2
550     {
551         String JavaDoc descriptorToClass (String JavaDoc typedescriptor)
552         {
553             //System.out.println ("typedesc1 -> " + typedescriptor);
554

555             char first = typedescriptor.charAt (0);
556             
557             if (first == '[')
558                 // array type:
559
return arrayOf (typedescriptor.substring (1));
560             else if (first == 'L')
561                 // object type:
562
return vmNameToJavaName (typedescriptor.substring (1, typedescriptor.length() - 1));
563             else // primitive type
564
return primitive (first);
565         }
566         
567         
568         String JavaDoc arrayOf (String JavaDoc typedescriptor)
569         {
570             //System.out.println ("typedesc2 -> " + typedescriptor);
571

572             char first = typedescriptor.charAt (0);
573             String JavaDoc component;
574             
575             if (first == '[')
576                 // array type:
577
component = arrayOf (typedescriptor.substring (1));
578             else if (first == 'L')
579                 // object type:
580
component = vmNameToJavaName (typedescriptor.substring (1, typedescriptor.length() - 1));
581             else // primitive type
582
component = primitive (first);
583             
584             String JavaDoc array = component + " []";
585             return array;
586         }
587         
588         
589         String JavaDoc primitive (char c)
590         {
591             switch (c)
592             {
593             case 'B': return "byte";
594             case 'C': return "char";
595             case 'D': return "double";
596             case 'F': return "float";
597             case 'I': return "int";
598             case 'J': return "long";
599             case 'S': return "short";
600             case 'Z': return "boolean";
601             default:
602                 throw new IllegalArgumentException JavaDoc ("unknown primitive: " + c);
603             }
604         }
605         
606     } // end of static class
607

608     
609     private static class methodDescriptorCompiler
610     {
611         methodDescriptorCompiler (String JavaDoc methoddescriptor)
612         {
613             m_in = new java.io.PushbackReader JavaDoc (new java.io.StringReader JavaDoc (methoddescriptor));
614         }
615         
616         String JavaDoc [] getResult ()
617         {
618             final String JavaDoc [] result = new String JavaDoc [m_result.size ()];
619             m_result.toArray (result);
620             
621             return result;
622         }
623         
624         void methodDescriptor () throws IOException JavaDoc
625         {
626             consume ('(');
627             
628             char c;
629             while ((c = (char) m_in.read ()) != ')')
630             {
631                 m_in.unread (c);
632                 parameterDescriptor ();
633             }
634             returnDescriptor ();
635         }
636         
637         void parameterDescriptor () throws IOException JavaDoc
638         {
639             fieldType ();
640             newToken ();
641         }
642         
643         void returnDescriptor () throws IOException JavaDoc
644         {
645             char c = (char) m_in.read ();
646             
647             switch (c)
648             {
649             case 'V':
650                 m_token.append (c);
651                 break;
652                 
653             default:
654                 m_in.unread (c);
655                 fieldType ();
656                 
657             }
658             // ignore return type for now: newToken ();
659
}
660         
661         void componentType () throws IOException JavaDoc
662         {
663             fieldType ();
664         }
665         
666         void objectType () throws IOException JavaDoc
667         {
668             consume ('L');
669             m_token.append ('L');
670             
671             char c;
672             while ((c = (char) m_in.read ()) != ';')
673             {
674                 m_token.append (c);
675             }
676             m_token.append (';');
677         }
678         
679         void arrayType () throws IOException JavaDoc
680         {
681             consume ('[');
682             m_token.append ('[');
683         
684             componentType ();
685         }
686         
687         void fieldType () throws IOException JavaDoc
688         {
689             char c = (char) m_in.read ();
690             m_in.unread (c);
691             
692             switch (c)
693             {
694             case 'L':
695                 objectType ();
696                 break;
697                 
698             case '[':
699                 arrayType ();
700                 break;
701                 
702             default:
703                 baseType ();
704                 break;
705             }
706         }
707
708         
709         void baseType () throws IOException JavaDoc
710         {
711             char c = (char) m_in.read ();
712             
713             switch (c)
714             {
715             case 'B':
716             case 'C':
717             case 'D':
718             case 'F':
719             case 'I':
720             case 'J':
721             case 'S':
722             case 'Z':
723                 m_token.append (c);
724                 break;
725                 
726             default:
727                 throw new IllegalArgumentException JavaDoc ("unknown base type: " + c);
728             }
729         }
730         
731         
732         private void consume (char expected) throws IOException JavaDoc
733         {
734             char c = (char) m_in.read ();
735             
736             if (c != expected)
737                 throw new IllegalArgumentException JavaDoc ("consumed '" + c + "' while expecting '" + expected + "'");
738         }
739         
740         
741         
742         private void newToken ()
743         {
744             //System.out.println ("NEW TOKEN [" + m_token.toString () + "]");
745

746             m_result.add (m_token.toString ());
747             m_token.setLength (0);
748         }
749     
750         final java.util.List JavaDoc m_result = new java.util.ArrayList JavaDoc ();
751         private StringBuffer JavaDoc m_token = new StringBuffer JavaDoc ();
752         private java.io.PushbackReader JavaDoc m_in;
753     } // end of nested class
754

755 } // end of class
756
// ----------------------------------------------------------------------------
757
Popular Tags