KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > TypeDesc


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.io.Serializable JavaDoc;
20 import java.io.Externalizable JavaDoc;
21 import java.io.ObjectOutput JavaDoc;
22 import java.io.ObjectInput JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.ObjectStreamException JavaDoc;
25 import java.lang.ref.SoftReference JavaDoc;
26 import java.lang.reflect.Array JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.Map JavaDoc;
29 import org.cojen.util.SoftValuedHashMap;
30 import org.cojen.util.WeakCanonicalSet;
31 import org.cojen.util.WeakIdentityMap;
32
33 /**
34  * This class is used to build field and return type descriptor strings as
35  * defined in <i>The Java Virtual Machine Specification</i>, section 4.3.2.
36  * TypeDesc instances are canonicalized and therefore "==" comparable.
37  *
38  * @author Brian S O'Neill
39  */

40 public abstract class TypeDesc extends Descriptor implements Serializable JavaDoc {
41     /**
42      * Type code returned from getTypeCode, which can be used with the
43      * newarray instruction.
44      */

45     public final static int
46         OBJECT_CODE = 0,
47         VOID_CODE = 1,
48         BOOLEAN_CODE = 4,
49         CHAR_CODE = 5,
50         FLOAT_CODE = 6,
51         DOUBLE_CODE = 7,
52         BYTE_CODE = 8,
53         SHORT_CODE = 9,
54         INT_CODE = 10,
55         LONG_CODE = 11;
56
57     /** Primitive type void */
58     public final static TypeDesc VOID;
59     /** Primitive type boolean */
60     public final static TypeDesc BOOLEAN;
61     /** Primitive type char */
62     public final static TypeDesc CHAR;
63     /** Primitive type byte */
64     public final static TypeDesc BYTE;
65     /** Primitive type short */
66     public final static TypeDesc SHORT;
67     /** Primitive type int */
68     public final static TypeDesc INT;
69     /** Primitive type long */
70     public final static TypeDesc LONG;
71     /** Primitive type float */
72     public final static TypeDesc FLOAT;
73     /** Primitive type double */
74     public final static TypeDesc DOUBLE;
75
76     /** Object type java.lang.Object, provided for convenience */
77     public final static TypeDesc OBJECT;
78     /** Object type java.lang.String, provided for convenience */
79     public final static TypeDesc STRING;
80
81     // Pool of all shared instances. Ensures identity comparison works.
82
final static WeakCanonicalSet cInstances;
83
84     // Cache that maps Classes to TypeDescs.
85
private final static Map JavaDoc cClassesToInstances;
86
87     // Cache that maps String names to TypeDescs.
88
private final static Map JavaDoc cNamesToInstances;
89
90     // Cache that maps String descriptors to TypeDescs.
91
private final static Map JavaDoc cDescriptorsToInstances;
92
93     static {
94         cInstances = new WeakCanonicalSet();
95
96         cClassesToInstances = Collections.synchronizedMap(new WeakIdentityMap());
97         cNamesToInstances = Collections.synchronizedMap(new SoftValuedHashMap());
98         cDescriptorsToInstances = Collections.synchronizedMap(new SoftValuedHashMap());
99
100         VOID = intern(new PrimitiveType("V", VOID_CODE));
101         BOOLEAN = intern(new PrimitiveType("Z", BOOLEAN_CODE));
102         CHAR = intern(new PrimitiveType("C", CHAR_CODE));
103         BYTE = intern(new PrimitiveType("B", BYTE_CODE));
104         SHORT = intern(new PrimitiveType("S", SHORT_CODE));
105         INT = intern(new PrimitiveType("I", INT_CODE));
106         LONG = intern(new PrimitiveType("J", LONG_CODE));
107         FLOAT = intern(new PrimitiveType("F", FLOAT_CODE));
108         DOUBLE = intern(new PrimitiveType("D", DOUBLE_CODE));
109
110         OBJECT = forClass("java.lang.Object");
111         STRING = forClass("java.lang.String");
112     }
113
114     static TypeDesc intern(TypeDesc type) {
115         return (TypeDesc)cInstances.put(type);
116     }
117
118     /**
119      * Acquire a TypeDesc from any class, including primitives and arrays.
120      */

121     public static TypeDesc forClass(final Class JavaDoc clazz) {
122         if (clazz == null) {
123             return null;
124         }
125
126         TypeDesc type = (TypeDesc)cClassesToInstances.get(clazz);
127
128         if (type == null || type.toClass() != clazz) {
129             if (clazz.isArray()) {
130                 type = forClass(clazz.getComponentType()).toArrayType();
131             } else if (clazz.isPrimitive()) {
132                 if (clazz == int.class) {
133                     type = INT;
134                 } else if (clazz == boolean.class) {
135                     type = BOOLEAN;
136                 } else if (clazz == char.class) {
137                     type = CHAR;
138                 } else if (clazz == byte.class) {
139                     type = BYTE;
140                 } else if (clazz == long.class) {
141                     type = LONG;
142                 } else if (clazz == float.class) {
143                     type = FLOAT;
144                 } else if (clazz == double.class) {
145                     type = DOUBLE;
146                 } else if (clazz == short.class) {
147                     type = SHORT;
148                 } else if (clazz == void.class) {
149                     type = VOID;
150                 }
151             } else {
152                 String JavaDoc name = clazz.getName();
153                 type = intern(new ObjectType(generateDescriptor(name), name));
154             }
155         
156             if (type.toClass() != clazz) {
157                 type = new ObjectType(type.getDescriptor(), clazz.getName());
158                 ((ObjectType) type).setClass(clazz);
159             }
160
161             synchronized (cClassesToInstances) {
162                 if (cClassesToInstances.containsKey(clazz)) {
163                     type = (TypeDesc)cClassesToInstances.get(clazz);
164                 } else {
165                     cClassesToInstances.put(clazz, type);
166                 }
167             }
168         }
169
170         return type;
171     }
172
173     /**
174      * Acquire a TypeDesc from any class name, including primitives and arrays.
175      * Primitive and array syntax matches Java declarations.
176      */

177     public static TypeDesc forClass(final String JavaDoc name) throws IllegalArgumentException JavaDoc {
178         if (name.length() < 1) {
179             throw invalidName(name);
180         }
181
182         // TODO: Support generics in name.
183

184         TypeDesc type = (TypeDesc)cNamesToInstances.get(name);
185         if (type != null) {
186             return type;
187         }
188
189         int index1 = name.lastIndexOf('[');
190         int index2 = name.lastIndexOf(']');
191         if (index2 >= 0) {
192             if (index2 + 1 != name.length() || index1 + 1 != index2) {
193                 throw invalidName(name);
194             }
195             try {
196                 type = forClass(name.substring(0, index1)).toArrayType();
197             } catch (IllegalArgumentException JavaDoc e) {
198                 throw invalidName(name);
199             }
200         } else if (index1 >= 0) {
201             throw invalidName(name);
202         } else {
203             setType: {
204                 switch (name.charAt(0)) {
205                 case 'v':
206                     if (name.equals("void")) {
207                         type = VOID;
208                         break setType;
209                     }
210                     break;
211                 case 'b':
212                     if (name.equals("boolean")) {
213                         type = BOOLEAN;
214                         break setType;
215                     } else if (name.equals("byte")) {
216                         type = BYTE;
217                         break setType;
218                     }
219                     break;
220                 case 'c':
221                     if (name.equals("char")) {
222                         type = CHAR;
223                         break setType;
224                     }
225                     break;
226                 case 's':
227                     if (name.equals("short")) {
228                         type = SHORT;
229                         break setType;
230                     }
231                     break;
232                 case 'i':
233                     if (name.equals("int")) {
234                         type = INT;
235                         break setType;
236                     }
237                     break;
238                 case 'l':
239                     if (name.equals("long")) {
240                         type = LONG;
241                         break setType;
242                     }
243                     break;
244                 case 'f':
245                     if (name.equals("float")) {
246                         type = FLOAT;
247                         break setType;
248                     }
249                     break;
250                 case 'd':
251                     if (name.equals("double")) {
252                         type = DOUBLE;
253                         break setType;
254                     }
255                     break;
256                 }
257
258                 String JavaDoc desc = generateDescriptor(name);
259                 if (name.indexOf('/') < 0) {
260                     type = new ObjectType(desc, name);
261                 } else {
262                     type = new ObjectType(desc, name.replace('/', '.'));
263                 }
264                 type = intern(type);
265             }
266         }
267
268         cNamesToInstances.put(name, type);
269         return type;
270     }
271
272     private static IllegalArgumentException JavaDoc invalidName(String JavaDoc name) {
273         return new IllegalArgumentException JavaDoc("Invalid name: " + name);
274     }
275
276     /**
277      * Acquire a TypeDesc from a type descriptor. This syntax is described in
278      * section 4.3.2, Field Descriptors.
279      */

280     public static TypeDesc forDescriptor(final String JavaDoc desc) throws IllegalArgumentException JavaDoc {
281         TypeDesc type = (TypeDesc)cDescriptorsToInstances.get(desc);
282         if (type != null) {
283             return type;
284         }
285
286         // TODO: Support generics in descriptor.
287

288         String JavaDoc rootDesc = desc;
289         int cursor = 0;
290         int dim = 0;
291         try {
292             char c;
293             while ((c = rootDesc.charAt(cursor++)) == '[') {
294                 dim++;
295             }
296
297             switch (c) {
298             case 'V':
299                 type = VOID;
300                 break;
301             case 'Z':
302                 type = BOOLEAN;
303                 break;
304             case 'C':
305                 type = CHAR;
306                 break;
307             case 'B':
308                 type = BYTE;
309                 break;
310             case 'S':
311                 type = SHORT;
312                 break;
313             case 'I':
314                 type = INT;
315                 break;
316             case 'J':
317                 type = LONG;
318                 break;
319             case 'F':
320                 type = FLOAT;
321                 break;
322             case 'D':
323                 type = DOUBLE;
324                 break;
325             case 'L':
326                 if (dim > 0) {
327                     rootDesc = rootDesc.substring(dim);
328                     cursor = 1;
329                 }
330                 StringBuffer JavaDoc name = new StringBuffer JavaDoc(rootDesc.length() - 2);
331                 while ((c = rootDesc.charAt(cursor++)) != ';') {
332                     if (c == '/') {
333                         c = '.';
334                     }
335                     name.append(c);
336                 }
337                 type = intern(new ObjectType(rootDesc, name.toString()));
338                 break;
339             default:
340                 throw invalidDescriptor(desc);
341             }
342         } catch (NullPointerException JavaDoc e) {
343             throw invalidDescriptor(desc);
344         } catch (IndexOutOfBoundsException JavaDoc e) {
345             throw invalidDescriptor(desc);
346         }
347
348         if (cursor != rootDesc.length()) {
349             throw invalidDescriptor(desc);
350         }
351
352         while (--dim >= 0) {
353             type = type.toArrayType();
354         }
355
356         cDescriptorsToInstances.put(desc, type);
357         return type;
358     }
359
360     private static IllegalArgumentException JavaDoc invalidDescriptor(String JavaDoc desc) {
361         return new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
362     }
363
364     private static String JavaDoc generateDescriptor(String JavaDoc classname) {
365         int length = classname.length();
366         char[] buf = new char[length + 2];
367         buf[0] = 'L';
368         classname.getChars(0, length, buf, 1);
369         int i;
370         for (i=1; i<=length; i++) {
371             char c = buf[i];
372             if (c == '.') {
373                 buf[i] = '/';
374             }
375         }
376         buf[i] = ';';
377         return new String JavaDoc(buf);
378     }
379
380     transient final String JavaDoc mDescriptor;
381
382     TypeDesc(String JavaDoc desc) {
383         mDescriptor = desc;
384     }
385
386     /**
387      * Returns a type descriptor string, excluding generics.
388      */

389     public final String JavaDoc getDescriptor() {
390         return mDescriptor;
391     }
392
393     /**
394      * Returns a type descriptor string, including any generics.
395      */

396     //public abstract String getGenericDescriptor();
397

398     /**
399      * Returns the class name for this descriptor. If the type is primitive,
400      * then the Java primitive type name is returned. If the type is an array,
401      * only the root component type name is returned.
402      */

403     public abstract String JavaDoc getRootName();
404
405     /**
406      * Returns the class name for this descriptor. If the type is primitive,
407      * then the Java primitive type name is returned. If the type is an array,
408      * "[]" is append at the end of the name for each dimension.
409      */

410     public abstract String JavaDoc getFullName();
411
412     // TODO
413
//public abstract String getGenericRootName();
414

415     // TODO
416
//public abstract String getGenericFullName();
417

418     /**
419      * Returns a type code for operating on primitive types in switches. If
420      * not primitive, OBJECT_CODE is returned.
421      */

422     public abstract int getTypeCode();
423
424     /**
425      * Returns true if this is a primitive type.
426      */

427     public abstract boolean isPrimitive();
428
429     /**
430      * Returns true if this is a primitive long or double type.
431      */

432     public abstract boolean isDoubleWord();
433
434     /**
435      * Returns true if this is an array type.
436      */

437     public abstract boolean isArray();
438
439     /**
440      * Returns the number of dimensions this array type has. If not an array,
441      * zero is returned.
442      */

443     public abstract int getDimensions();
444
445     /**
446      * Returns the component type of this array type. If not an array, null is
447      * returned.
448      */

449     public abstract TypeDesc getComponentType();
450
451     /**
452      * Returns the root component type of this array type. If not an array,
453      * null is returned.
454      */

455     public abstract TypeDesc getRootComponentType();
456
457     /**
458      * Convertes this type to an array type. If already an array, another
459      * dimension is added.
460      */

461     public abstract TypeDesc toArrayType();
462
463     /**
464      * Returns the object peer of this primitive type. For int, the object peer
465      * is java.lang.Integer. If this type is an object type, it is simply
466      * returned.
467      */

468     public abstract TypeDesc toObjectType();
469
470     /**
471      * Returns the primitive peer of this object type, if one exists. For
472      * java.lang.Integer, the primitive peer is int. If this type is a
473      * primitive type, it is simply returned. Arrays have no primitive peer,
474      * and so null is returned instead.
475      */

476     public abstract TypeDesc toPrimitiveType();
477
478     /**
479      * Returns this type as a class. If the class isn't found, null is
480      * returned.
481      */

482     public abstract Class JavaDoc toClass();
483
484     /**
485      * Returns this type as a class. If the class isn't found, null is
486      * returned.
487      * @param loader optional ClassLoader to load class from
488      */

489     public abstract Class JavaDoc toClass(ClassLoader JavaDoc loader);
490
491     public String JavaDoc toString() {
492         // TODO: Return generic descriptor
493
return mDescriptor;
494     }
495
496     public int hashCode() {
497         return mDescriptor.hashCode();
498     }
499
500     public boolean equals(Object JavaDoc other) {
501         if (this == other) {
502             return true;
503         }
504         if (other instanceof TypeDesc) {
505             return ((TypeDesc)other).mDescriptor.equals(mDescriptor);
506         }
507         return false;
508     }
509
510     Object JavaDoc writeReplace() throws ObjectStreamException JavaDoc {
511         return new External(mDescriptor);
512     }
513
514     private static class PrimitiveType extends TypeDesc {
515         private transient final int mCode;
516         private transient TypeDesc mArrayType;
517         private transient TypeDesc mObjectType;
518         
519         PrimitiveType(String JavaDoc desc, int code) {
520             super(desc);
521             mCode = code;
522         }
523
524         public String JavaDoc getRootName() {
525             switch (mCode) {
526             default:
527             case VOID_CODE:
528                 return "void";
529             case BOOLEAN_CODE:
530                 return "boolean";
531             case CHAR_CODE:
532                 return "char";
533             case BYTE_CODE:
534                 return "byte";
535             case SHORT_CODE:
536                 return "short";
537             case INT_CODE:
538                 return "int";
539             case LONG_CODE:
540                 return "long";
541             case FLOAT_CODE:
542                 return "float";
543             case DOUBLE_CODE:
544                 return "double";
545             }
546         }
547         
548         public String JavaDoc getFullName() {
549             return getRootName();
550         }
551
552         public int getTypeCode() {
553             return mCode;
554         }
555         
556         public boolean isPrimitive() {
557             return true;
558         }
559         
560         public boolean isDoubleWord() {
561             return mCode == DOUBLE_CODE || mCode == LONG_CODE;
562         }
563         
564         public boolean isArray() {
565             return false;
566         }
567         
568         public int getDimensions() {
569             return 0;
570         }
571         
572         public TypeDesc getComponentType() {
573             return null;
574         }
575         
576         public TypeDesc getRootComponentType() {
577             return null;
578         }
579         
580         public TypeDesc toArrayType() {
581             if (mArrayType == null) {
582                 char[] buf = new char[2];
583                 buf[0] = '[';
584                 buf[1] = mDescriptor.charAt(0);
585                 mArrayType = intern(new ArrayType(new String JavaDoc(buf), this));
586             }
587             return mArrayType;
588         }
589         
590         public TypeDesc toObjectType() {
591             if (mObjectType == null) {
592                 switch (mCode) {
593                 default:
594                 case VOID_CODE:
595                     mObjectType = forClass("java.lang.Void");
596                     break;
597                 case BOOLEAN_CODE:
598                     mObjectType = forClass("java.lang.Boolean");
599                     break;
600                 case CHAR_CODE:
601                     mObjectType = forClass("java.lang.Character");
602                     break;
603                 case BYTE_CODE:
604                     mObjectType = forClass("java.lang.Byte");
605                     break;
606                 case SHORT_CODE:
607                     mObjectType = forClass("java.lang.Short");
608                     break;
609                 case INT_CODE:
610                     mObjectType = forClass("java.lang.Integer");
611                     break;
612                 case LONG_CODE:
613                     mObjectType = forClass("java.lang.Long");
614                     break;
615                 case FLOAT_CODE:
616                     mObjectType = forClass("java.lang.Float");
617                     break;
618                 case DOUBLE_CODE:
619                     mObjectType = forClass("java.lang.Double");
620                     break;
621                 }
622             }
623             return mObjectType;
624         }
625         
626         public TypeDesc toPrimitiveType() {
627             return this;
628         }
629
630         public Class JavaDoc toClass() {
631             switch (mCode) {
632             default:
633             case VOID_CODE:
634                 return void.class;
635             case BOOLEAN_CODE:
636                 return boolean.class;
637             case CHAR_CODE:
638                 return char.class;
639             case BYTE_CODE:
640                 return byte.class;
641             case SHORT_CODE:
642                 return short.class;
643             case INT_CODE:
644                 return int.class;
645             case LONG_CODE:
646                 return long.class;
647             case FLOAT_CODE:
648                 return float.class;
649             case DOUBLE_CODE:
650                 return double.class;
651             }
652         }
653
654         public Class JavaDoc toClass(ClassLoader JavaDoc loader) {
655             return toClass();
656         }
657     }
658
659     private static class ObjectType extends TypeDesc {
660         private transient final String JavaDoc mName;
661         private transient TypeDesc mArrayType;
662         private transient TypeDesc mPrimitiveType;
663
664         // Since cClassesToInstances may reference this instance, softly
665
// reference back to class to allow it to be garbage collected.
666
private transient SoftReference JavaDoc mClassRef;
667
668         ObjectType(String JavaDoc desc, String JavaDoc name) {
669             super(desc);
670             mName = name;
671         }
672
673         public String JavaDoc getRootName() {
674             return mName;
675         }
676
677         public String JavaDoc getFullName() {
678             return mName;
679         }
680
681         public int getTypeCode() {
682             return OBJECT_CODE;
683         }
684
685         public boolean isPrimitive() {
686             return false;
687         }
688         
689         public boolean isDoubleWord() {
690             return false;
691         }
692         
693         public boolean isArray() {
694             return false;
695         }
696         
697         public int getDimensions() {
698             return 0;
699         }
700         
701         public TypeDesc getComponentType() {
702             return null;
703         }
704         
705         public TypeDesc getRootComponentType() {
706             return null;
707         }
708         
709         public TypeDesc toArrayType() {
710             if (mArrayType == null) {
711                 int length = mDescriptor.length();
712                 char[] buf = new char[length + 1];
713                 buf[0] = '[';
714                 mDescriptor.getChars(0, length, buf, 1);
715                 mArrayType = intern(new ArrayType(new String JavaDoc(buf), this));
716             }
717             return mArrayType;
718         }
719         
720         public TypeDesc toObjectType() {
721             return this;
722         }
723         
724         public TypeDesc toPrimitiveType() {
725             if (mPrimitiveType == null) {
726                 String JavaDoc name = mName;
727                 if (name.startsWith("java.lang.") && name.length() > 10) {
728                     switch (name.charAt(10)) {
729                     case 'V':
730                         if (name.equals("java.lang.Void")) {
731                             mPrimitiveType = VOID;
732                         }
733                         break;
734                     case 'B':
735                         if (name.equals("java.lang.Boolean")) {
736                             mPrimitiveType = BOOLEAN;
737                         } else if (name.equals("java.lang.Byte")) {
738                             mPrimitiveType = BYTE;
739                         }
740                         break;
741                     case 'C':
742                         if (name.equals("java.lang.Character")) {
743                             mPrimitiveType = CHAR;
744                         }
745                         break;
746                     case 'S':
747                         if (name.equals("java.lang.Short")) {
748                             mPrimitiveType = SHORT;
749                         }
750                         break;
751                     case 'I':
752                         if (name.equals("java.lang.Integer")) {
753                             mPrimitiveType = INT;
754                         }
755                         break;
756                     case 'L':
757                         if (name.equals("java.lang.Long")) {
758                             mPrimitiveType = LONG;
759                         }
760                         break;
761                     case 'F':
762                         if (name.equals("java.lang.Float")) {
763                             mPrimitiveType = FLOAT;
764                         }
765                         break;
766                     case 'D':
767                         if (name.equals("java.lang.Double")) {
768                             mPrimitiveType = DOUBLE;
769                         }
770                         break;
771                     }
772                 }
773             }
774
775             return mPrimitiveType;
776         }
777
778         public final synchronized Class JavaDoc toClass() {
779             Class JavaDoc clazz;
780             if (mClassRef != null) {
781                 clazz = (Class JavaDoc)mClassRef.get();
782                 if (clazz != null) {
783                     return clazz;
784                 }
785             }
786             clazz = toClass(null);
787             mClassRef = new SoftReference JavaDoc(clazz);
788             return clazz;
789         }
790
791         public Class JavaDoc toClass(ClassLoader JavaDoc loader) {
792             TypeDesc type = toPrimitiveType();
793             if (type != null) {
794                 switch (type.getTypeCode()) {
795                 default:
796                 case VOID_CODE:
797                     return Void JavaDoc.class;
798                 case BOOLEAN_CODE:
799                     return Boolean JavaDoc.class;
800                 case CHAR_CODE:
801                     return Character JavaDoc.class;
802                 case FLOAT_CODE:
803                     return Float JavaDoc.class;
804                 case DOUBLE_CODE:
805                     return Double JavaDoc.class;
806                 case BYTE_CODE:
807                     return Byte JavaDoc.class;
808                 case SHORT_CODE:
809                     return Short JavaDoc.class;
810                 case INT_CODE:
811                     return Integer JavaDoc.class;
812                 case LONG_CODE:
813                     return Long JavaDoc.class;
814                 }
815             }
816
817             try {
818                 if (loader == null) {
819                     return Class.forName(mName);
820                 } else {
821                     return loader.loadClass(mName);
822                 }
823             } catch (ClassNotFoundException JavaDoc e) {
824                 return null;
825             }
826         }
827
828         void setClass(Class JavaDoc clazz) {
829             mClassRef = new SoftReference JavaDoc(clazz);
830         }
831     }
832
833     private static class ArrayType extends ObjectType {
834         private transient final TypeDesc mComponent;
835         private transient final String JavaDoc mFullName;
836
837         ArrayType(String JavaDoc desc, TypeDesc component) {
838             super(desc, component.getRootName());
839             mComponent = component;
840             mFullName = component.getFullName().concat("[]");
841         }
842
843         public String JavaDoc getFullName() {
844             return mFullName;
845         }
846
847         public boolean isArray() {
848             return true;
849         }
850         
851         public int getDimensions() {
852             return mComponent.getDimensions() + 1;
853         }
854         
855         public TypeDesc getComponentType() {
856             return mComponent;
857         }
858         
859         public TypeDesc getRootComponentType() {
860             TypeDesc type = mComponent;
861             while (type.isArray()) {
862                 type = type.getComponentType();
863             }
864             return type;
865         }
866         
867         public TypeDesc toPrimitiveType() {
868             return null;
869         }
870
871         public Class JavaDoc toClass(ClassLoader JavaDoc loader) {
872             if (loader == null) {
873                 return arrayClass(getRootComponentType().toClass());
874             } else {
875                 return arrayClass(getRootComponentType().toClass(loader));
876             }
877         }
878
879         private Class JavaDoc arrayClass(Class JavaDoc clazz) {
880             if (clazz == null) {
881                 return null;
882             }
883             int dim = getDimensions();
884             try {
885                 if (dim == 1) {
886                     return Array.newInstance(clazz, 0).getClass();
887                 } else {
888                     return Array.newInstance(clazz, new int[dim]).getClass();
889                 }
890             } catch (IllegalArgumentException JavaDoc e) {
891                 return null;
892             }
893         }
894     }
895
896     private static class External implements Externalizable JavaDoc {
897         private String JavaDoc mDescriptor;
898
899         public External() {
900         }
901
902         public External(String JavaDoc desc) {
903             mDescriptor = desc;
904         }
905
906         public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
907             out.writeUTF(mDescriptor);
908         }
909
910         public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc {
911             mDescriptor = in.readUTF();
912         }
913
914         public Object JavaDoc readResolve() throws ObjectStreamException JavaDoc {
915             return forDescriptor(mDescriptor);
916         }
917     }
918 }
919
Popular Tags