KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > src > Type


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

19
20 package org.openide.src;
21
22 import java.util.StringTokenizer JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.io.Serializable JavaDoc;
25
26 import org.openide.util.Utilities;
27 import org.openide.filesystems.FileObject;
28
29 /** Java types.
30 *
31 * @author Petr Hamernik, Ian Formanek
32 */

33 public final class Type extends Object JavaDoc implements Cloneable JavaDoc, Serializable JavaDoc {
34     /** Private constants for types */
35     private static final int T_BOOLEAN = 0x0001;
36     private static final int T_INT = 0x0002;
37     private static final int T_CHAR = 0x0003;
38     private static final int T_BYTE = 0x0004;
39     private static final int T_SHORT = 0x0005;
40     private static final int T_LONG = 0x0006;
41     private static final int T_FLOAT = 0x0007;
42     private static final int T_DOUBLE = 0x0008;
43     private static final int T_VOID = 0x0009;
44
45     private static final int T_CLASS = 0x0010;
46     private static final int T_ARRAY = 0x0020;
47
48     private static final int T_PRIMITIVE= 0x000F;
49
50     /** <code>void</code> primitive type. */
51     public static final Type VOID = new Type(T_VOID);
52     /** <code>boolean</code> primitive type. */
53     public static final Type BOOLEAN = new Type(T_BOOLEAN);
54     /** <code>int</code> primitive type. */
55     public static final Type INT = new Type(T_INT);
56     /** <code>char</code> primitive type. */
57     public static final Type CHAR = new Type(T_CHAR);
58     /** <code>byte</code> primitive type. */
59     public static final Type BYTE = new Type(T_BYTE);
60     /** <code>short</code> primitive type. */
61     public static final Type SHORT = new Type(T_SHORT);
62     /** <code>long</code> primitive type. */
63     public static final Type LONG = new Type(T_LONG);
64     /** <code>float</code> primitive type. */
65     public static final Type FLOAT = new Type(T_FLOAT);
66     /** <code>double</code> primitive type. */
67     public static final Type DOUBLE = new Type(T_DOUBLE);
68
69     /** Table where strings like "int" are keys and classes like INT are values */ // NOI18N
70
private static HashMap JavaDoc text2type = new HashMap JavaDoc();
71
72     private static final String JavaDoc L_VOID = "void"; // NOI18N
73
private static final String JavaDoc L_BOOLEAN = "boolean"; // NOI18N
74
private static final String JavaDoc L_INT = "int"; // NOI18N
75
private static final String JavaDoc L_CHAR = "char"; // NOI18N
76
private static final String JavaDoc L_BYTE = "byte"; // NOI18N
77
private static final String JavaDoc L_SHORT = "short"; // NOI18N
78
private static final String JavaDoc L_LONG = "long"; // NOI18N
79
private static final String JavaDoc L_FLOAT = "float"; // NOI18N
80
private static final String JavaDoc L_DOUBLE = "double"; // NOI18N
81

82     private static final String JavaDoc[] PRIMITIVE_NAMES = {
83         L_VOID, L_BOOLEAN, L_INT, L_CHAR, L_BYTE, L_SHORT, L_LONG, L_FLOAT, L_DOUBLE
84     };
85
86     static {
87         text2type.put(L_VOID, VOID);
88         text2type.put(L_BOOLEAN, BOOLEAN);
89         text2type.put(L_INT, INT);
90         text2type.put(L_CHAR, CHAR);
91         text2type.put(L_BYTE, BYTE);
92         text2type.put(L_SHORT, SHORT);
93         text2type.put(L_LONG, LONG);
94         text2type.put(L_FLOAT, FLOAT);
95         text2type.put(L_DOUBLE, DOUBLE);
96     }
97
98     /** Kind of this instance of Type */
99     private int kind;
100
101     /** Element type if this type is array */
102     private Type elementType = null;
103
104     /** Identifier of the class if this type is ClassType */
105     private Identifier classType = null;
106
107     static final long serialVersionUID =8997425134968958367L;
108     /** Constructor for primitive type
109     */

110     private Type(int kind) {
111         this.kind = kind;
112     }
113
114     /** Creates array of elements of given type.
115     * @param type the element type
116     */

117     private Type(Type type) {
118         this.kind = T_ARRAY;
119         elementType = type;
120     }
121
122     private Type(Identifier id) {
123         this.kind = T_CLASS;
124         classType = id;
125     }
126
127     private Object JavaDoc readResolve() {
128         switch (kind) {
129         case T_BOOLEAN: return BOOLEAN;
130         case T_INT: return INT;
131         case T_CHAR: return CHAR;
132         case T_BYTE: return BYTE;
133         case T_SHORT: return SHORT;
134         case T_LONG: return LONG;
135         case T_FLOAT: return FLOAT;
136         case T_DOUBLE: return DOUBLE;
137         case T_VOID: return VOID;
138         case T_CLASS: return createClass(classType);
139         case T_ARRAY: return createArray(elementType);
140         default: throw new InternalError JavaDoc();
141         }
142     }
143
144     /** Get the Java names of the primitive types.
145     * @return the names
146     */

147     public static String JavaDoc[] getTypesNames() {
148         return PRIMITIVE_NAMES;
149     }
150
151     /** Create an array type.
152     * @param elementType the element type
153     * @return the array type
154     */

155     public static Type createArray (Type elementType) {
156         return new Type(elementType);
157     }
158
159     /** Create a class type by name.
160     * @param id the class name
161     * @return the class type
162     */

163     public static Type createClass (Identifier id) {
164         //TODO: !!!! Don't know what to do with that.
165
//TODO: ClassElement instead of id???
166
return new Type(id);
167     }
168
169     /** Create a type from an existing class.
170     * @param cl the class
171     * @return the type
172     */

173     public static Type createFromClass (Class JavaDoc cl) {
174         if (cl.isArray ())
175             return createArray (createFromClass (cl.getComponentType ()));
176         else if (cl.isPrimitive ()) {
177             if (Void.TYPE.equals (cl)) return VOID;
178             if (Boolean.TYPE.equals (cl)) return BOOLEAN;
179             if (Integer.TYPE.equals (cl)) return INT;
180             if (Character.TYPE.equals (cl)) return CHAR;
181             if (Byte.TYPE.equals (cl)) return BYTE;
182             if (Short.TYPE.equals (cl)) return SHORT;
183             if (Long.TYPE.equals (cl)) return LONG;
184             if (Float.TYPE.equals (cl)) return FLOAT;
185             if (Double.TYPE.equals (cl)) return DOUBLE;
186             throw new InternalError JavaDoc (); // Unknown primitive type
187
}
188         else
189             return createClass (Identifier.create (getClassIdentifier(cl)));
190     }
191     
192     /**
193      * Creates an identifier from class' name. Since {@link Class#getName() Class.getName}
194      * uses $ as inner class delimiters, this method converts all those dollars to dots.
195      * Other dollar signs are preserved, if case they were made intentionally a part
196      * of the class name.
197      * @param cl class object
198      * @return identifier corresponding to the class.
199      */

200     private static String JavaDoc getClassIdentifier(Class JavaDoc cl) {
201         if (cl.getDeclaringClass() == null)
202             return cl.getName();
203         
204         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(cl.getName());
205         cl = cl.getDeclaringClass();
206         
207         do {
208             sb.setCharAt(cl.getName().length(), '.'); // NOI18N
209
cl = cl.getDeclaringClass();
210         } while (cl != null);
211         return sb.toString();
212     }
213
214     /** Create a type from its string representation.
215     * @param text the string representation, e.g. <code>"int[][]"</code>,
216     * <code>"java.awt.Button"</code>, etc.
217     * @return the type
218     * @exception InvalidArgumentException if the text cannot be parsed
219     */

220     public static Type parse(String JavaDoc text) throws IllegalArgumentException JavaDoc {
221         if (text.endsWith(".TYPE")) { // NOI18N
222
// could be one of the primive types
223
// extracts leading java.lang package and trailing TYPE and
224
// then compares with all primitive types to check whether this
225
// is not primitive type
226
int len = text.length ();
227             String JavaDoc v = text.startsWith("java.lang.") ? // NOI18N
228
text.substring (10, len - 5) :
229               text.substring (0, len - 5);
230
231             if ("Void".equals (v)) return VOID; // NOI18N
232
if ("Boolean".equals (v)) return BOOLEAN; // NOI18N
233
if ("Integer".equals (v)) return INT; // NOI18N
234
if ("Character".equals (v)) return CHAR; // NOI18N
235
if ("Byte".equals (v)) return BYTE; // NOI18N
236
if ("Short".equals (v)) return SHORT; // NOI18N
237
if ("Long".equals (v)) return LONG; // NOI18N
238
if ("Float".equals (v)) return FLOAT; // NOI18N
239
if ("Double".equals (v)) return DOUBLE; // NOI18N
240
}
241         
242         
243         StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(text, " []", true); // NOI18N
244
Type type = null;
245         int status = 0;
246         while (tok.hasMoreTokens()) {
247             String JavaDoc token = tok.nextToken();
248             if (token.equals(" ")) // NOI18N
249
continue;
250
251             switch (status) {
252             case 0:
253                 {
254                     type = (Type) text2type.get(token);
255                     if (type == null) {
256                       String JavaDoc localText=token;
257                       int offset;
258                       
259                       if (localText.length()==0)
260                           throw new IllegalArgumentException JavaDoc();
261                         do
262                       { String JavaDoc localToken;
263                           
264                           offset=localText.indexOf("."); // NOI18N
265
if (offset == -1)
266                               localToken=localText;
267                           else {
268                               localToken=localText.substring(0,offset);
269                               localText=localText.substring(offset+1,localText.length());
270                           }
271                           if (localToken.length()==0 || !Utilities.isJavaIdentifier(localToken)) {
272                                 throw new IllegalArgumentException JavaDoc();
273                             }
274                       }while (offset != -1);
275                       type = createClass(Identifier.create(token));
276                     }
277                     status = 1;
278                     break;
279                 }
280             case 1:
281                 if (!token.equals("[")) // NOI18N
282
throw new IllegalArgumentException JavaDoc();
283
284                 status = 2;
285                 break;
286             case 2:
287                 if (!token.equals("]")) // NOI18N
288
throw new IllegalArgumentException JavaDoc();
289
290                 type = createArray(type);
291                 status = 1;
292                 break;
293             }
294         }
295         // not able to parse
296
if (type == null)
297             throw new IllegalArgumentException JavaDoc();
298         return type;
299     }
300
301     /** Test if the type is primitive.
302     * @return <CODE>true</CODE> if so
303     */

304     public boolean isPrimitive () {
305         return ((kind & T_PRIMITIVE) != 0);
306     }
307
308     /** Test if the type is an array.
309     * @return <CODE>true</CODE> if so
310     */

311     public boolean isArray () {
312         return (kind == T_ARRAY);
313     }
314
315     /** Test if the type is a class or interface.
316     * @return <CODE>true</CODE> if so, <code>false</code> if an array or primitive type
317     */

318     public boolean isClass () {
319         return (kind == T_CLASS);
320     }
321
322     /** Get the element type of this array type.
323     * @return the element type
324     * @exception IllegalStateException if this type is not an array type
325     */

326     public Type getElementType () throws IllegalStateException JavaDoc {
327         if (isArray())
328             return elementType;
329         else
330             throw new IllegalStateException JavaDoc();
331     }
332
333     /** Get the (fully-qualified) name of this class type.
334     * @return the class name
335     * @exception IllegalStateException if this type is not a simple class or interface type
336     */

337     public Identifier getClassName () throws IllegalStateException JavaDoc {
338         if (isClass())
339             return classType;
340         else
341             throw new IllegalStateException JavaDoc();
342     }
343
344     /** Attempt to get the real class corresponding to this type, using the default class loader.
345     * @return the class
346     * @exception ClassNotFoundException if the class cannot be found
347     */

348     public Class JavaDoc toClass() throws ClassNotFoundException JavaDoc {
349         return toClass (null);
350     }
351
352     /** Attempt to get the real class corresponding to this type.
353     * @param loader class loader to use for loading classes
354     * @return the class
355     * @exception ClassNotFoundException if the class cannot be found
356     */

357     public Class JavaDoc toClass(ClassLoader JavaDoc loader) throws ClassNotFoundException JavaDoc {
358         if (isPrimitive()) {
359             switch (kind) {
360             case T_BOOLEAN : return Boolean.TYPE;
361             case T_INT : return Integer.TYPE;
362             case T_CHAR : return Character.TYPE;
363             case T_BYTE : return Byte.TYPE;
364             case T_SHORT : return Short.TYPE;
365             case T_LONG : return Long.TYPE;
366             case T_FLOAT : return Float.TYPE;
367             case T_DOUBLE : return Double.TYPE;
368             default : return Void.TYPE; //void
369
}
370         }
371
372         // if no given class loader then use own
373
if (loader == null) {
374             loader = getClass ().getClassLoader ();
375         }
376
377         if (isClass())
378             return Class.forName (classType.getFullName(), true, loader);
379         else {
380             // construct array
381
String JavaDoc name = ""; // NOI18N
382
Type t = this;
383             while (t.isArray ()) {
384                 name = name + "["; // NOI18N
385
t = t.getElementType ();
386             }
387             
388             if (t.isClass ()) name = name + "L" + t.classType.getFullName () + ";"; // NOI18N
389
else {
390         name = name + getPrimitiveCode(t.kind);
391             }
392
393             return Class.forName (name, true, loader);
394         }
395     }
396
397     /** Get this type as the string.
398     * @param appendTo The string buffer where to append to
399     * @param source true means getSourceName() will be used, otherwise getFullName()
400     * @return the same string buffer which was passed into
401     */

402     StringBuffer JavaDoc getAsString(StringBuffer JavaDoc appendTo, boolean source) {
403         if (isPrimitive()) {
404             switch (kind) {
405             case T_BOOLEAN : return appendTo.append("boolean"); // NOI18N
406
case T_INT : return appendTo.append("int"); // NOI18N
407
case T_CHAR : return appendTo.append("char"); // NOI18N
408
case T_BYTE : return appendTo.append("byte"); // NOI18N
409
case T_SHORT : return appendTo.append("short"); // NOI18N
410
case T_LONG : return appendTo.append("long"); // NOI18N
411
case T_FLOAT : return appendTo.append("float"); // NOI18N
412
case T_DOUBLE : return appendTo.append("double"); // NOI18N
413
default : return appendTo.append("void"); //void // NOI18N
414
}
415         }
416         else {
417             if (isClass())
418                 return appendTo.append(source ?
419                                        classType.getSourceName() :
420                                        classType.getFullName()
421                                       );
422             else {
423                 return elementType.getAsString(appendTo, source).append("[]"); // NOI18N
424
}
425         }
426     }
427
428     private static String JavaDoc getPrimitiveCode(int t) {
429                 switch (t) {
430                 case T_BOOLEAN : return "Z"; // NOI18N
431
case T_INT : return "I"; // NOI18N
432
case T_CHAR : return "C"; // NOI18N
433
case T_BYTE : return "B"; // NOI18N
434
case T_SHORT : return "S"; // NOI18N
435
case T_LONG : return "J"; // NOI18N
436
case T_FLOAT : return "F"; // NOI18N
437
case T_DOUBLE : return "D"; // NOI18N
438
default: return "V"; // NOI18N
439
}
440     }
441     /** Get a form of this type usable in Java source.
442     * @return the string representation
443     */

444     public String JavaDoc getSourceString() {
445         return getAsString(new StringBuffer JavaDoc(), true).toString();
446     }
447
448     /** Get a form of this type usable in Java source.
449     * @return the string representation
450     */

451     public String JavaDoc getFullString() {
452         return getAsString(new StringBuffer JavaDoc(), false).toString();
453     }
454
455     /** Get a form of this type usable in Java source.
456     * @return the string representation
457     */

458     public String JavaDoc toString() {
459         return getSourceString();
460     }
461
462     /**
463      * Constructs and returns name of a reference type that can be used for Class.forName(). If the type is
464      * a primitive one, the method raises UnsupportedOperationException since the
465      * operation is not supported for primitive types.
466      * If the type is an array, the returned signature will begin with one or more
467      * `[' chars (depending on the array depth), followed by LclassSignature; (L and ;
468      * are literals here; classSignature is obtained from ClassElement.getSignature()).
469      *
470      * @return name compatible with Class.forName()
471      * @throws UnsupportedOperationException
472      * @deprecated Use the Test.getVMClassName(final FileObject projectArtefact) method.
473      */

474     public final String JavaDoc getVMClassName() throws UnsupportedOperationException JavaDoc {
475         throw new UnsupportedOperationException JavaDoc("Operation is not more supported. Use Type.getVMClassName(FileObject)"); // NOI18N
476
}
477
478     /**
479      * Constructs and returns name of a reference type that can be used for Class.forName(). If the type is
480      * a primitive one, the method raises UnsupportedOperationException since the
481      * operation is not supported for primitive types.
482      * If the type is an array, the returned signature will begin with one or more
483      * `[' chars (depending on the array depth), followed by LclassSignature; (L and ;
484      * are literals here; classSignature is obtained from ClassElement.getSignature()).
485      * @param projectArtefact the FileObject which implies the project classpath to resolve the Type into ClassElement
486      * @return name compatible with Class.forName()
487      * @throws UnsupportedOperationException if the type is primitive.
488      */

489     public final String JavaDoc getVMClassName(final FileObject projectArtefact) throws UnsupportedOperationException JavaDoc {
490     if (isPrimitive()) {
491         throw new UnsupportedOperationException JavaDoc("Primitive types unsupported"); // NOI18N
492
}
493         return internalGetVMName(false, projectArtefact);
494     }
495
496     /**
497      * Returns the identifier of a class for a class-type. The operation is not supported
498      * for array types or primitive types.
499      * @return the identifier for the object type
500      */

501     public final Identifier getTypeIdentifier() throws UnsupportedOperationException JavaDoc {
502         if (isPrimitive() || isArray())
503             throw new UnsupportedOperationException JavaDoc("Only class types supported"); // NOI18N
504
return classType;
505     }
506
507     private String JavaDoc internalGetVMName(final boolean useSignature, final FileObject projectArtefact) {
508     if (!isArray()) {
509         String JavaDoc fqn = classType.getFullName();
510         ClassElement cls = ClassElement.forName(fqn, projectArtefact);
511             if (cls == null) {
512                 if (useSignature)
513                     return fqn.replace('.', '/');
514                 else
515             return fqn;
516             }
517         return useSignature ? cls.getSignature() : cls.getVMName() ;
518     }
519     
520     int depth = 0;
521     Type t = this;
522
523     do {
524         ++depth;
525         t = t.getElementType();
526     } while (t.isArray());
527     
528     StringBuffer JavaDoc sb = new StringBuffer JavaDoc(depth + 1);
529     for (int i = 0; i < depth; i++) {
530         sb.append('[');
531     }
532     if (t.isPrimitive()) {
533         sb.append(getPrimitiveCode(t.kind));
534     } else {
535         sb.append('L');
536             sb.append(t.internalGetVMName(useSignature, projectArtefact));
537         sb.append(';');
538     }
539     return sb.toString();
540     }
541
542     /**
543      * Returns a JVM-signature of the type. This operation is supported even for primitive
544      * types for which it returns one-char type code. For reference types, dots in
545      * fully qualified class names are replaced by slashes (/). Constructed signatures
546      * will exactly match those found in a compiled .class file.
547      * @return signature of the type
548      * @deprecated Use Type.getSignature (FileObject projectArtefact) method.
549      */

550     public final String JavaDoc getSignature () {
551         throw new UnsupportedOperationException JavaDoc("Operation is not more supported. Use Type.getSignature(FileObject)"); // NOI18N
552
}
553
554     /**
555      * Returns a JVM-signature of the type. This operation is supported even for primitive
556      * types for which it returns one-char type code. For reference types, dots in
557      * fully qualified class names are replaced by slashes (/). Constructed signatures
558      * will exactly match those found in a compiled .class file.
559      * @param projectArtefact the FileObject which implies the project ClassPath
560      * @return signature of the type
561      */

562      public final String JavaDoc getSignature (final FileObject projectArtefact) {
563          if (isPrimitive()) {
564              return getPrimitiveCode(this.kind);
565          }
566          if (isClass()) {
567              StringBuffer JavaDoc sb;
568              String JavaDoc fqn = classType.getFullName();
569              ClassElement el = ClassElement.forName(fqn, projectArtefact);
570              if (el != null)
571                  fqn = el.getSignature();
572              sb = new StringBuffer JavaDoc(fqn.length() + 2);
573              sb.append('L');
574              sb.append(fqn);
575              sb.append(';');
576              return sb.toString();
577          } else {
578              return internalGetVMName(true, projectArtefact);
579          }
580      }
581
582     /** Compare the specified Type with this Type for equality.
583     * @param type Type to be compared with this
584     * @param source Determine if the source name (for class types)
585     * should be also compared.
586     * If <CODE>false</CODE> only fully qualified name is compared.
587     * @return <CODE>true</CODE> if the specified object equals to
588     * specified Identifier otherwise <CODE>false</CODE>.
589     */

590     public boolean compareTo(Type type, boolean source) {
591         if (type.kind != kind)
592             return false;
593
594         switch (kind) {
595         case T_ARRAY:
596             return type.getElementType().compareTo(getElementType(), source);
597         case T_CLASS:
598             return type.getClassName().compareTo(getClassName(), source);
599         default:
600             return true;
601         }
602     }
603
604     /** Compare the specified object with this Type for equality.
605     * There are tested only full qualified name if the type is Class
606     * @param o Object to be compared with this
607     * @return <CODE>true</CODE> if the specified object represents the same type
608     * otherwise <CODE>false</CODE>.
609     */

610     public boolean equals(Object JavaDoc o) {
611         return (o instanceof Type) ? compareTo((Type) o, false) : false;
612     }
613
614     /** @return the hash code of full name String object.
615     */

616     public int hashCode() {
617         switch (kind) {
618         case T_ARRAY:
619             return getElementType().hashCode() << 1;
620         case T_CLASS:
621             return getClassName().hashCode();
622         default:
623             return System.identityHashCode(this);
624         }
625     }
626 }
627
Popular Tags