alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.src;

import java.util.StringTokenizer;
import java.util.HashMap;
import java.io.Serializable;

import org.openide.util.Utilities;
import org.openide.filesystems.FileObject;

/** Java types.
*
* @author Petr Hamernik, Ian Formanek
*/
public final class Type extends Object implements Cloneable, Serializable {
    /** Private constants for types */
    private static final int T_BOOLEAN  = 0x0001;
    private static final int T_INT      = 0x0002;
    private static final int T_CHAR     = 0x0003;
    private static final int T_BYTE     = 0x0004;
    private static final int T_SHORT    = 0x0005;
    private static final int T_LONG     = 0x0006;
    private static final int T_FLOAT    = 0x0007;
    private static final int T_DOUBLE   = 0x0008;
    private static final int T_VOID     = 0x0009;

    private static final int T_CLASS    = 0x0010;
    private static final int T_ARRAY    = 0x0020;

    private static final int T_PRIMITIVE= 0x000F;

    /** void primitive type. */
    public static final Type VOID = new Type(T_VOID);
    /** boolean primitive type. */
    public static final Type BOOLEAN = new Type(T_BOOLEAN);
    /** int primitive type. */
    public static final Type INT = new Type(T_INT);
    /** char primitive type. */
    public static final Type CHAR = new Type(T_CHAR);
    /** byte primitive type. */
    public static final Type BYTE = new Type(T_BYTE);
    /** short primitive type. */
    public static final Type SHORT = new Type(T_SHORT);
    /** long primitive type. */
    public static final Type LONG = new Type(T_LONG);
    /** float primitive type. */
    public static final Type FLOAT = new Type(T_FLOAT);
    /** double primitive type. */
    public static final Type DOUBLE = new Type(T_DOUBLE);

    /** Table where strings like "int" are keys and classes like INT are values */ // NOI18N
    private static HashMap text2type = new HashMap();

    private static final String L_VOID = "void"; // NOI18N
    private static final String L_BOOLEAN = "boolean"; // NOI18N
    private static final String L_INT = "int"; // NOI18N
    private static final String L_CHAR = "char"; // NOI18N
    private static final String L_BYTE = "byte"; // NOI18N
    private static final String L_SHORT = "short"; // NOI18N
    private static final String L_LONG = "long"; // NOI18N
    private static final String L_FLOAT = "float"; // NOI18N
    private static final String L_DOUBLE = "double"; // NOI18N

    private static final String[] PRIMITIVE_NAMES = {
        L_VOID, L_BOOLEAN, L_INT, L_CHAR, L_BYTE, L_SHORT, L_LONG, L_FLOAT, L_DOUBLE
    };

    static {
        text2type.put(L_VOID, VOID);
        text2type.put(L_BOOLEAN, BOOLEAN);
        text2type.put(L_INT, INT);
        text2type.put(L_CHAR, CHAR);
        text2type.put(L_BYTE, BYTE);
        text2type.put(L_SHORT, SHORT);
        text2type.put(L_LONG, LONG);
        text2type.put(L_FLOAT, FLOAT);
        text2type.put(L_DOUBLE, DOUBLE);
    }

    /** Kind of this instance of Type */
    private int kind;

    /** Element type if this type is array */
    private Type elementType = null;

    /** Identifier of the class if this type is ClassType */
    private Identifier classType =  null;

    static final long serialVersionUID =8997425134968958367L;
    /** Constructor for primitive type
    */
    private Type(int kind) {
        this.kind = kind;
    }

    /** Creates array of elements of given type.
    * @param type the element type
    */
    private Type(Type type) {
        this.kind = T_ARRAY;
        elementType = type;
    }

    private Type(Identifier id) {
        this.kind = T_CLASS;
        classType = id;
    }

    private Object readResolve() {
        switch (kind) {
        case T_BOOLEAN: return BOOLEAN;
        case T_INT: return INT;
        case T_CHAR: return CHAR;
        case T_BYTE: return BYTE;
        case T_SHORT: return SHORT;
        case T_LONG: return LONG;
        case T_FLOAT: return FLOAT;
        case T_DOUBLE: return DOUBLE;
        case T_VOID: return VOID;
        case T_CLASS: return createClass(classType);
        case T_ARRAY: return createArray(elementType);
        default: throw new InternalError();
        }
    }

    /** Get the Java names of the primitive types.
    * @return the names
    */
    public static String[] getTypesNames() {
        return PRIMITIVE_NAMES;
    }

    /** Create an array type.
    * @param elementType the element type
    * @return the array type
    */
    public static Type createArray (Type elementType) {
        return new Type(elementType);
    }

    /** Create a class type by name.
    * @param id the class name
    * @return the class type
    */
    public static Type createClass (Identifier id) {
        //TODO: !!!! Don't know what to do with that.
        //TODO: ClassElement instead of id???
        return new Type(id);
    }

    /** Create a type from an existing class.
    * @param cl the class
    * @return the type
    */
    public static Type createFromClass (Class cl) {
        if (cl.isArray ())
            return createArray (createFromClass (cl.getComponentType ()));
        else if (cl.isPrimitive ()) {
            if (Void.TYPE.equals (cl)) return VOID;
            if (Boolean.TYPE.equals (cl)) return BOOLEAN;
            if (Integer.TYPE.equals (cl)) return INT;
            if (Character.TYPE.equals (cl)) return CHAR;
            if (Byte.TYPE.equals (cl)) return BYTE;
            if (Short.TYPE.equals (cl)) return SHORT;
            if (Long.TYPE.equals (cl)) return LONG;
            if (Float.TYPE.equals (cl)) return FLOAT;
            if (Double.TYPE.equals (cl)) return DOUBLE;
            throw new InternalError (); // Unknown primitive type
        }
        else
            return createClass (Identifier.create (getClassIdentifier(cl)));
    }
    
    /**
     * Creates an identifier from class' name. Since {@link Class#getName() Class.getName}
     * uses $ as inner class delimiters, this method converts all those dollars to dots.
     * Other dollar signs are preserved, if case they were made intentionally a part
     * of the class name.
     * @param cl class object
     * @return identifier corresponding to the class.
     */
    private static String getClassIdentifier(Class cl) {
        if (cl.getDeclaringClass() == null)
            return cl.getName();
        
        StringBuffer sb = new StringBuffer(cl.getName());
        cl = cl.getDeclaringClass();
        
        do {
            sb.setCharAt(cl.getName().length(), '.'); // NOI18N
            cl = cl.getDeclaringClass();
        } while (cl != null);
        return sb.toString();
    }

    /** Create a type from its string representation.
    * @param text the string representation, e.g. "int[][]",
    * "java.awt.Button", etc.
    * @return the type
    * @exception InvalidArgumentException if the text cannot be parsed
    */
    public static Type parse(String text) throws IllegalArgumentException {
        if (text.endsWith(".TYPE")) { // NOI18N
            // could be one of the primive types
            // extracts leading java.lang package and trailing TYPE and 
            // then compares with all primitive types to check whether this
            // is not primitive type
            int len = text.length ();
            String v = text.startsWith("java.lang.") ? // NOI18N
              text.substring (10, len - 5) :
              text.substring (0, len - 5);

            if ("Void".equals (v)) return VOID; // NOI18N
            if ("Boolean".equals (v)) return BOOLEAN; // NOI18N
            if ("Integer".equals (v)) return INT; // NOI18N
            if ("Character".equals (v)) return CHAR; // NOI18N
            if ("Byte".equals (v)) return BYTE; // NOI18N
            if ("Short".equals (v)) return SHORT; // NOI18N
            if ("Long".equals (v)) return LONG; // NOI18N
            if ("Float".equals (v)) return FLOAT; // NOI18N
            if ("Double".equals (v)) return DOUBLE; // NOI18N
        }
        
        
        StringTokenizer tok = new StringTokenizer(text, " []", true); // NOI18N
        Type type = null;
        int status = 0;
        while (tok.hasMoreTokens()) {
            String token = tok.nextToken();
            if (token.equals(" ")) // NOI18N
                continue;

            switch (status) {
            case 0:
                {
                    type = (Type) text2type.get(token);
                    if (type == null) {
                      String localText=token;
                      int offset;
                      
                      if (localText.length()==0)
                          throw new IllegalArgumentException();
                        do
                      {   String localToken;
                          
                          offset=localText.indexOf(".");  // NOI18N
                          if (offset == -1)
                              localToken=localText;
                          else {
                              localToken=localText.substring(0,offset);
                              localText=localText.substring(offset+1,localText.length());
                          }
                          if (localToken.length()==0 || !Utilities.isJavaIdentifier(localToken)) {
                                throw new IllegalArgumentException();
                            }
                      }while (offset != -1);
                      type = createClass(Identifier.create(token));
                    }
                    status = 1;
                    break;
                }
            case 1:
                if (!token.equals("[")) // NOI18N
                    throw new IllegalArgumentException();

                status = 2;
                break;
            case 2:
                if (!token.equals("]")) // NOI18N
                    throw new IllegalArgumentException();

                type = createArray(type);
                status = 1;
                break;
            }
        }
        // not able to parse
        if (type == null)
            throw new IllegalArgumentException();
        return type;
    }

    /** Test if the type is primitive.
    * @return true if so
    */
    public boolean isPrimitive () {
        return ((kind & T_PRIMITIVE) != 0);
    }

    /** Test if the type is an array.
    * @return true if so
    */
    public boolean isArray () {
        return (kind == T_ARRAY);
    }

    /** Test if the type is a class or interface.
    * @return true if so, false if an array or primitive type
    */
    public boolean isClass () {
        return (kind == T_CLASS);
    }

    /** Get the element type of this array type.
    * @return the element type
    * @exception IllegalStateException if this type is not an array type
    */
    public Type getElementType () throws IllegalStateException {
        if (isArray())
            return elementType;
        else
            throw new IllegalStateException();
    }

    /** Get the (fully-qualified) name of this class type.
    * @return the class name
    * @exception IllegalStateException if this type is not a simple class or interface type
    */
    public Identifier getClassName () throws IllegalStateException {
        if (isClass())
            return classType;
        else
            throw new IllegalStateException();
    }

    /** Attempt to get the real class corresponding to this type, using the default class loader.
    * @return the class
    * @exception ClassNotFoundException if the class cannot be found
    */
    public Class toClass() throws ClassNotFoundException {
        return toClass (null);
    }

    /** Attempt to get the real class corresponding to this type.
    * @param loader class loader to use for loading classes
    * @return the class
    * @exception ClassNotFoundException if the class cannot be found
    */
    public Class toClass(ClassLoader loader) throws ClassNotFoundException {
        if (isPrimitive()) {
            switch (kind) {
            case T_BOOLEAN : return Boolean.TYPE;
            case T_INT     : return Integer.TYPE;
            case T_CHAR    : return Character.TYPE;
            case T_BYTE    : return Byte.TYPE;
            case T_SHORT   : return Short.TYPE;
            case T_LONG    : return Long.TYPE;
            case T_FLOAT   : return Float.TYPE;
            case T_DOUBLE  : return Double.TYPE;
            default        : return Void.TYPE; //void
            }
        }

        // if no given class loader then use own
        if (loader == null) {
            loader = getClass ().getClassLoader ();
        }

        if (isClass())
            return Class.forName (classType.getFullName(), true, loader);
        else {
            // construct array
            String name = ""; // NOI18N
            Type t = this;
            while (t.isArray ()) {
                name = name + "["; // NOI18N
                t = t.getElementType ();
            }
            
            if (t.isClass ()) name = name + "L" + t.classType.getFullName () + ";"; // NOI18N
            else {
		name = name + getPrimitiveCode(t.kind);
            }

            return Class.forName (name, true, loader);
        }
    }

    /** Get this type as the string.
    * @param appendTo The string buffer where to append to
    * @param source true means getSourceName() will be used, otherwise getFullName()
    * @return the same string buffer which was passed into
    */
    StringBuffer getAsString(StringBuffer appendTo, boolean source) {
        if (isPrimitive()) {
            switch (kind) {
            case T_BOOLEAN : return appendTo.append("boolean"); // NOI18N
            case T_INT     : return appendTo.append("int"); // NOI18N
            case T_CHAR    : return appendTo.append("char"); // NOI18N
            case T_BYTE    : return appendTo.append("byte"); // NOI18N
            case T_SHORT   : return appendTo.append("short"); // NOI18N
            case T_LONG    : return appendTo.append("long"); // NOI18N
            case T_FLOAT   : return appendTo.append("float"); // NOI18N
            case T_DOUBLE  : return appendTo.append("double"); // NOI18N
            default        : return appendTo.append("void"); //void // NOI18N
            }
        }
        else {
            if (isClass())
                return appendTo.append(source ?
                                       classType.getSourceName() :
                                       classType.getFullName()
                                      );
            else {
                return elementType.getAsString(appendTo, source).append("[]"); // NOI18N
            }
        }
    }

    private static String getPrimitiveCode(int t) {
                switch (t) {
                case T_BOOLEAN : return "Z"; // NOI18N
                case T_INT     : return "I"; // NOI18N
                case T_CHAR    : return "C"; // NOI18N
                case T_BYTE    : return "B"; // NOI18N
                case T_SHORT   : return "S"; // NOI18N
                case T_LONG    : return "J"; // NOI18N
                case T_FLOAT   : return "F"; // NOI18N
                case T_DOUBLE  : return "D"; // NOI18N
		default: return "V"; // NOI18N
                }
    }
    /** Get a form of this type usable in Java source.
    * @return the string representation
    */
    public String getSourceString() {
        return getAsString(new StringBuffer(), true).toString();
    }

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

    /** Get a form of this type usable in Java source.
    * @return the string representation
    */
    public String toString() {
        return getSourceString();
    }

    /**
     * Constructs and returns name of a reference type that can be used for Class.forName(). If the type is
     * a primitive one, the method raises UnsupportedOperationException since the
     * operation is not supported for primitive types.
     * If the type is an array, the returned signature will begin with one or more
     * `[' chars (depending on the array depth), followed by LclassSignature; (L and ;
     * are literals here; classSignature is obtained from ClassElement.getSignature()).
     *
     * @return name compatible with Class.forName()
     * @throws UnsupportedOperationException
     * @deprecated Use the Test.getVMClassName(final FileObject projectArtefact) method.
     */
    public final String getVMClassName() throws UnsupportedOperationException {
        throw new UnsupportedOperationException("Operation is not more supported. Use Type.getVMClassName(FileObject)");
    }

    /**
     * Constructs and returns name of a reference type that can be used for Class.forName(). If the type is
     * a primitive one, the method raises UnsupportedOperationException since the
     * operation is not supported for primitive types.
     * If the type is an array, the returned signature will begin with one or more
     * `[' chars (depending on the array depth), followed by LclassSignature; (L and ;
     * are literals here; classSignature is obtained from ClassElement.getSignature()).
     * @param projectArtefact the FileObject which implies the project classpath to resolve the Type into ClassElement
     * @return name compatible with Class.forName()
     * @throws UnsupportedOperationException if the type is primitive.
     */
    public final String getVMClassName(final FileObject projectArtefact) throws UnsupportedOperationException {
	if (isPrimitive()) {
	    throw new UnsupportedOperationException("Primitive types unsupported"); // NOI18N
	}
        return internalGetVMName(false, projectArtefact);
    }	

    /**
     * Returns the identifier of a class for a class-type. The operation is not supported
     * for array types or primitive types.
     * @return the identifier for the object type
     */
    public final Identifier getTypeIdentifier() throws UnsupportedOperationException {
        if (isPrimitive() || isArray())
            throw new UnsupportedOperationException("Only class types supported"); // NOI18N
        return classType;
    }

    private String internalGetVMName(final boolean useSignature, final FileObject projectArtefact) {
	if (!isArray()) {
	    String fqn = classType.getFullName();
	    ClassElement cls = ClassElement.forName(fqn, projectArtefact);
            if (cls == null) {
                if (useSignature)
                    return fqn.replace('.', '/');
                else
		    return fqn;
            }
	    return useSignature ? cls.getSignature() : cls.getVMName() ;
	}
	
	int depth = 0;
	Type t = this;

	do {
	    ++depth;
	    t = t.getElementType();
	} while (t.isArray());		
	
	StringBuffer sb = new StringBuffer(depth + 1);
	for (int i = 0; i < depth; i++) {
	    sb.append('[');
	}
	if (t.isPrimitive()) {
	    sb.append(getPrimitiveCode(t.kind));
	} else {
	    sb.append('L');
            sb.append(t.internalGetVMName(useSignature, projectArtefact));
	    sb.append(';');
	}
	return sb.toString();
    }

    /**
     * Returns a JVM-signature of the type. This operation is supported even for primitive
     * types for which it returns one-char type code. For reference types, dots in
     * fully qualified class names are replaced by slashes (/). Constructed signatures
     * will exactly match those found in a compiled .class file.
     * @return signature of the type
     * @deprecated Use Type.getSignature (FileObject projectArtefact) method.
     */
    public final String getSignature () {
        throw new UnsupportedOperationException("Operation is not more supported. Use Type.getSignature(FileObject)");
    }

    /**
     * Returns a JVM-signature of the type. This operation is supported even for primitive
     * types for which it returns one-char type code. For reference types, dots in
     * fully qualified class names are replaced by slashes (/). Constructed signatures
     * will exactly match those found in a compiled .class file.
     * @param projectArtefact the FileObject which implies the project ClassPath
     * @return signature of the type
     */
     public final String getSignature (final FileObject projectArtefact) {
         if (isPrimitive()) {
             return getPrimitiveCode(this.kind);
         }
         if (isClass()) {
             StringBuffer sb;
             String fqn = classType.getFullName();
             ClassElement el = ClassElement.forName(fqn, projectArtefact);
             if (el != null)
                 fqn = el.getSignature();
             sb = new StringBuffer(fqn.length() + 2);
             sb.append('L');
             sb.append(fqn);
             sb.append(';');
             return sb.toString();
         } else {
             return internalGetVMName(true, projectArtefact);
         }
     }

    /** Compare the specified Type with this Type for equality.
    * @param type Type to be compared with this
    * @param source Determine if the source name (for class types)
    *       should be also compared.
    *       If false only fully qualified name is compared.
    * @return true if the specified object equals to
    *         specified Identifier otherwise false.
    */
    public boolean compareTo(Type type, boolean source) {
        if (type.kind != kind)
            return false;

        switch (kind) {
        case T_ARRAY:
            return type.getElementType().compareTo(getElementType(), source);
        case T_CLASS:
            return type.getClassName().compareTo(getClassName(), source);
        default:
            return true;
        }
    }

    /** Compare the specified object with this Type for equality.
    * There are tested only full qualified name if the type is Class
    * @param o Object to be compared with this
    * @return true if the specified object represents the same type
    *         otherwise false.
    */
    public boolean equals(Object o) {
        return (o instanceof Type) ? compareTo((Type) o, false) : false;
    }

    /** @return the hash code of full name String object.
    */
    public int hashCode() {
        switch (kind) {
        case T_ARRAY:
            return getElementType().hashCode() << 1;
        case T_CLASS:
            return getClassName().hashCode();
        default:
            return System.identityHashCode(this);
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.