|
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);
}
}
}
|