| /******************************************************************************* |
| * Copyright (c) 2005, 2010 Oracle. All rights reserved. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0, which accompanies this distribution |
| * and is available at http://www.eclipse.org/legal/epl-v10.html. |
| * |
| * Contributors: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.utility.internal; |
| |
| /** |
| * Convenience methods related to Java class names as returned by |
| * {@link java.lang.Class#getName()}. |
| */ |
| public class ClassName { |
| |
| public static final String VOID_CLASS_NAME = ReflectionTools.VOID_CLASS.getName(); |
| public static final String VOID_WRAPPER_CLASS_NAME = ReflectionTools.VOID_WRAPPER_CLASS.getName(); |
| |
| public static final char REFERENCE_CLASS_CODE = 'L'; |
| public static final char REFERENCE_CLASS_NAME_DELIMITER = ';'; |
| |
| /** |
| * Return whether the specified class is an array type. |
| * @see java.lang.Class#getName() |
| */ |
| public static boolean isArray(String className) { |
| return className.charAt(0) == '['; |
| } |
| |
| /** |
| * Return the "element type" of the specified class. |
| * The element type is the base type held by an array type. |
| * Non-array types simply return themselves. |
| * @see java.lang.Class#getName() |
| */ |
| public static String getElementTypeName(String className) { |
| int depth = getArrayDepth(className); |
| if (depth == 0) { |
| // the name is in the form: "java.lang.Object" or "int" |
| return className; |
| } |
| return getElementTypeName_(className, depth); |
| } |
| |
| /** |
| * pre-condition: array depth is not zero |
| */ |
| private static String getElementTypeName_(String className, int arrayDepth) { |
| int last = className.length() - 1; |
| if (className.charAt(arrayDepth) == REFERENCE_CLASS_CODE) { |
| // the name is in the form: "[[[Ljava.lang.Object;" |
| return className.substring(arrayDepth + 1, last); // drop the trailing ';' |
| } |
| // the name is in the form: "[[[I" |
| return forCode(className.charAt(last)); |
| } |
| |
| /** |
| * Return the "array depth" of the specified class. |
| * The depth is the number of dimensions for an array type. |
| * Non-array types have a depth of zero. |
| * @see java.lang.Class#getName() |
| */ |
| public static int getArrayDepth(String className) { |
| int depth = 0; |
| while (className.charAt(depth) == '[') { |
| depth++; |
| } |
| return depth; |
| } |
| |
| /** |
| * Return the specified class's component type. |
| * Return <code>null</code> if the specified class is not an array type. |
| * @see java.lang.Class#getName() |
| */ |
| public static String getComponentTypeName(String className) { |
| switch (getArrayDepth(className)) { |
| case 0: |
| return null; |
| case 1: |
| return getElementTypeName_(className, 1); |
| default: |
| return className.substring(1); |
| } |
| } |
| |
| /** |
| * Return the specified class's simple name. |
| * Return an empty string if the specified class is anonymous. |
| * <p> |
| * The simple name of an array type is the simple name of the |
| * component type with <code>"[]"</code> appended. In particular, |
| * the simple name of an array type whose component type is |
| * anonymous is simply <code>"[]"</code>. |
| * @see java.lang.Class#getSimpleName() |
| */ |
| public static String getSimpleName(String className) { |
| return isArray(className) ? |
| getSimpleName(getComponentTypeName(className)) + "[]" : //$NON-NLS-1$ |
| getSimpleName_(className); |
| } |
| |
| /** |
| * pre-condition: specified class is not an array type |
| */ |
| private static String getSimpleName_(String className) { |
| int index = className.lastIndexOf('$'); |
| if (index == -1) { // "top-level" class - strip package name |
| return className.substring(className.lastIndexOf('.') + 1); |
| } |
| |
| int len = className.length(); |
| for (int i = ++index; i < len; i++) { |
| if ( ! charIsAsciiDigit(className.charAt(i))) { |
| return className.substring(i); // "member" or "local" class |
| } |
| } |
| // all the characters past the '$' are ASCII digits ("anonymous" class) |
| return ""; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Return the specified class's package name (e.g. |
| * <code>"java.lang.Object"</code> returns |
| * <code>"java.lang"</code>). |
| * Return an empty string if the specified class is:<ul> |
| * <li>in the "default" package |
| * <li>an array class |
| * <li>a primtive class |
| * </ul> |
| * @see java.lang.Class#getPackage() |
| * @see java.lang.Package#getName() |
| */ |
| public static String getPackageName(String className) { |
| if (isArray(className)) { |
| return ""; //$NON-NLS-1$ |
| } |
| int lastPeriod = className.lastIndexOf('.'); |
| return (lastPeriod == -1) ? "" : className.substring(0, lastPeriod); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Return whether the specified class is a "top-level" class, |
| * as opposed to a "member", "local", or "anonymous" class, |
| * using the standard JDK naming conventions (i.e. the class |
| * name does NOT contain a <code>'$'</code>). |
| * A "top-level" class can be either the "primary" (public) class defined |
| * in a file/compilation unit (i.e. the class with the same name as its |
| * file's simple base name) or a "non-primary" (package visible) class |
| * (i.e. the other top-level classes defined in a file). |
| * A "top-level" class can contain any of the other types of classes. |
| * @see java.lang.Class#getName() |
| */ |
| public static boolean isTopLevel(String className) { |
| if (isArray(className)) { |
| return false; |
| } |
| return className.lastIndexOf('$') == -1; |
| } |
| |
| /** |
| * Return whether the specified class is a "member" class, |
| * as opposed to a "top-level", "local", or "anonymous" class, |
| * using the standard JDK naming convention (i.e. the class |
| * name ends with a <code>'$'</code> followed by a legal class name; e.g. |
| * <code>"TopLevelClass$1LocalClass$MemberClass"</code>). |
| * A "member" class can be either "nested" (static) or "inner"; |
| * but there is no way to determine which from the class's name. |
| * A "member" class can contain "local", "anonymous", or other |
| * "member" classes; and vice-versa. |
| * @see java.lang.Class#getName() |
| */ |
| public static boolean isMember(String className) { |
| if (isArray(className)) { |
| return false; |
| } |
| int index = className.lastIndexOf('$'); |
| if (index == -1) { |
| return false; // "top-level" class |
| } |
| // the character immediately after the dollar sign cannot be an ASCII digit |
| return ! charIsAsciiDigit(className.charAt(++index)); |
| } |
| |
| /** |
| * Return whether the specified class is a "local" class, |
| * as opposed to a "top-level", "member", or "anonymous" class, |
| * using the standard JDK naming convention (i.e. the class name |
| * ends with <code>"$nnnXXX"</code>, |
| * where the <code>'$'</code> is |
| * followed by a series of numeric digits which are followed by the |
| * local class name; e.g. <code>"TopLevelClass$1LocalClass"</code>). |
| * A "local" class can contain "member", "anonymous", or other |
| * "local" classes; and vice-versa. |
| * @see java.lang.Class#getName() |
| */ |
| public static boolean isLocal(String className) { |
| if (isArray(className)) { |
| return false; |
| } |
| int index = className.lastIndexOf('$'); |
| if (index == -1) { |
| return false; // "top-level" class |
| } |
| if ( ! charIsAsciiDigit(className.charAt(++index))) { |
| return false; // "member" class |
| } |
| int len = className.length(); |
| for (int i = ++index; i < len; i++) { |
| if ( ! charIsAsciiDigit(className.charAt(i))) { |
| return true; |
| } |
| } |
| // all the characters past the '$' are ASCII digits ("anonymous" class) |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is an "anonymous" class, |
| * as opposed to a "top-level", "member", or "local" class, |
| * using the standard JDK naming convention (i.e. the class |
| * name ends with <code>"$nnn"</code> where all the characters past the |
| * last <code>'$'</code> are ASCII numeric digits; |
| * e.g. <code>"TopLevelClass$1"</code>). |
| * An "anonymous" class can contain "member", "local", or other |
| * "anonymous" classes; and vice-versa. |
| * @see java.lang.Class#getName() |
| */ |
| public static boolean isAnonymous(String className) { |
| if (isArray(className)) { |
| return false; |
| } |
| int index = className.lastIndexOf('$'); |
| if (index == -1) { |
| return false; // "top-level" class |
| } |
| if ( ! charIsAsciiDigit(className.charAt(++index))) { |
| return false; // "member" class |
| } |
| int len = className.length(); |
| for (int i = ++index; i < len; i++) { |
| if ( ! charIsAsciiDigit(className.charAt(i))) { |
| return false; // "local" class |
| } |
| } |
| // all the characters past the '$' are ASCII digits ("anonymous" class) |
| return true; |
| } |
| |
| /** |
| * {@link Character#isDigit(char)} returns <code>true</code> for some non-ASCII |
| * digits. This method does not. |
| */ |
| private static boolean charIsAsciiDigit(char c) { |
| return ('0' <= c) && (c <= '9'); |
| } |
| |
| /** |
| * Return whether the specified class is a "reference" |
| * class (i.e. neither <code>void</code> nor one of the primitive variable classes, |
| * <code>boolean</code>, <code>int</code>, <code>float</code>, etc.). |
| * <p> |
| * <strong>NB:</strong> <code>void.class.isPrimitive() == true</code> |
| */ |
| public static boolean isReference(String className) { |
| return ! isPrimitive(className); |
| } |
| |
| /** |
| * Return whether the specified class is a primitive |
| * class (i.e. <code>void</code> or one of the primitive variable classes, |
| * <code>boolean</code>, <code>int</code>, <code>float</code>, etc.). |
| * <p> |
| * <strong>NB:</strong> <code>void.class.isPrimitive() == true</code> |
| */ |
| public static boolean isPrimitive(String className) { |
| if (isArray(className) || (className.length() > ReflectionTools.MAX_PRIMITIVE_CLASS_NAME_LENGTH)) { |
| return false; // performance tweak |
| } |
| for (ReflectionTools.Primitive primitive : ReflectionTools.PRIMITIVES) { |
| if (className.equals(primitive.javaClass.getName())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is a primitive wrapper |
| * class (i.e. <code>java.lang.Void</code> or one of the primitive |
| * variable wrapper classes, <code>java.lang.Boolean</code>, |
| * <code>java.lang.Integer</code>, <code>java.lang.Float</code>, etc.). |
| * <p> |
| * <strong>NB:</strong> <code>void.class.isPrimitive() == true</code> |
| */ |
| public static boolean isPrimitiveWrapper(String className) { |
| if (isArray(className) || (className.length() > ReflectionTools.MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH)) { |
| return false; // performance tweak |
| } |
| for (ReflectionTools.Primitive primitive : ReflectionTools.PRIMITIVES) { |
| if (className.equals(primitive.wrapperClass.getName())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return whether the specified class is a "variable" primitive |
| * class (i.e. <code>boolean</code>, <code>int</code>, <code>float</code>, etc., |
| * but not <code>void</code>). |
| * <p> |
| * <strong>NB:</strong> <code>void.class.isPrimitive() == true</code> |
| */ |
| public static boolean isVariablePrimitive(String className) { |
| return isPrimitive(className) |
| && ( ! className.equals(VOID_CLASS_NAME)); |
| } |
| |
| /** |
| * Return whether the specified class is a "variable" primitive wrapper |
| * class (i.e. <code>java.lang.Boolean</code>, |
| * <code>java.lang.Integer</code>, <code>java.lang.Float</code>, etc., |
| * but not <code>java.lang.Void</code>). |
| * <p> |
| * <strong>NB:</strong> <code>void.class.isPrimitive() == true</code> |
| */ |
| public static boolean isVariablePrimitiveWrapper(String className) { |
| return isPrimitiveWrapper(className) |
| && ( ! className.equals(VOID_WRAPPER_CLASS_NAME)); |
| } |
| |
| /** |
| * Return the name of the primitive wrapper class corresponding to the specified |
| * primitive class. Return <code>null</code> if the specified class is not a primitive. |
| */ |
| public static String getWrapperClassName(String primitiveClassName) { |
| for (ReflectionTools.Primitive primitive : ReflectionTools.PRIMITIVES) { |
| if (primitive.javaClass.getName().equals(primitiveClassName)) { |
| return primitive.wrapperClass.getName(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return the name of the primitive class corresponding to the specified |
| * primitive wrapper class. Return <code>null</code> if the specified class |
| * is not a primitive wrapper. |
| */ |
| public static String getPrimitiveClassName(String primitiveWrapperClassName) { |
| for (ReflectionTools.Primitive primitive : ReflectionTools.PRIMITIVES) { |
| if (primitive.wrapperClass.getName().equals(primitiveWrapperClassName)) { |
| return primitive.javaClass.getName(); |
| } |
| } |
| return null; |
| } |
| |
| |
| // ********** primitive codes ********** |
| |
| /** |
| * Return the primitive class name for the specified primitive class code. |
| * Return <code>null</code> if the specified code |
| * is not a primitive class code. |
| * @see java.lang.Class#getName() |
| */ |
| public static String forCode(int classCode) { |
| return forCode((char) classCode); |
| } |
| |
| /** |
| * Return the primitive class name for the specified primitive class code. |
| * Return <code>null</code> if the specified code |
| * is not a primitive class code. |
| * @see java.lang.Class#getName() |
| */ |
| public static String forCode(char classCode) { |
| Class<?> primitiveClass = ReflectionTools.getClassForCode(classCode); |
| return (primitiveClass == null) ? null : primitiveClass.getName(); |
| } |
| |
| /** |
| * Return the class code for the specified primitive class. |
| * Return <code>0</code> if the specified class |
| * is not a primitive class. |
| * @see java.lang.Class#getName() |
| */ |
| public static char getCodeForClassName(String primitiveClassName) { |
| if (( ! isArray(primitiveClassName)) && (primitiveClassName.length() <= ReflectionTools.MAX_PRIMITIVE_CLASS_NAME_LENGTH)) { |
| for (ReflectionTools.Primitive primitive : ReflectionTools.PRIMITIVES) { |
| if (primitive.javaClass.getName().equals(primitiveClassName)) { |
| return primitive.code; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| static void append(String className, StringBuilder sb) { |
| sb.append(REFERENCE_CLASS_CODE); |
| sb.append(className); |
| sb.append(REFERENCE_CLASS_NAME_DELIMITER); |
| } |
| |
| |
| // ********** suppressed constructor ********** |
| |
| /** |
| * Suppress default constructor, ensuring non-instantiability. |
| */ |
| private ClassName() { |
| super(); |
| throw new UnsupportedOperationException(); |
| } |
| |
| } |