/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.dev.util; import java.util.regex.Pattern; /** * Utility methods for dealing with the various types of Java names. */ public class Name { /** * Represents a Java class name in binary form, for example: * {@code org.example.Foo$Bar}. * * See {@link "http://java.sun.com/docs/books/jls/third_edition/html/binaryComp.html#59892"} */ public static class BinaryName { public static String getClassName(String binaryName) { assert isBinaryName(binaryName); int lastDot = binaryName.lastIndexOf('.'); if (lastDot < 0) { return binaryName; } return binaryName.substring(lastDot + 1); } /** * Construct the fully qualified name of an inner class. * * @param outerClassBinaryName binary name of outer class, ie * {@code org.test.Foo} * @param innerClassShortName short name of inner class, ie {@code Bar} * @return fully qualified binary name of the inner class */ public static String getInnerClassName(String outerClassBinaryName, String innerClassShortName) { assert isBinaryName(outerClassBinaryName); return outerClassBinaryName + '$' + innerClassShortName; } public static String getOuterClassName(String binaryName) { assert isBinaryName(binaryName); int lastDollar = binaryName.lastIndexOf('$'); if (lastDollar < 0) { return null; } return binaryName.substring(0, lastDollar); } public static String getPackageName(String binaryName) { assert isBinaryName(binaryName); int lastDot = binaryName.lastIndexOf('.'); if (lastDot < 0) { return ""; } return binaryName.substring(0, lastDot); } public static String getShortClassName(String binaryName) { assert isBinaryName(binaryName); String className = getClassName(binaryName); int lastDollar = className.lastIndexOf('$', className.length() - 2); if (lastDollar < 0) { return className; } return className.substring(lastDollar + 1); } public static String toInternalName(String binaryName) { assert isBinaryName(binaryName); return binaryName.replace('.', '/'); } public static String toSourceName(String binaryName) { assert isBinaryName(binaryName); // don't change a trailing $ to a . return NON_TRAILING_DOLLAR.matcher(binaryName).replaceAll(".$1"); } private BinaryName() { } } /** * Represents a Java class name in internal form, for example: * {@code org/example/Foo$Bar}. * * See {@link "http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#14757"} */ public static class InternalName { public static String getClassName(String name) { assert isInternalName(name); int lastSlash = name.lastIndexOf('/'); if (lastSlash < 0) { return name; } return name.substring(lastSlash + 1); } /** * Construct the fully qualified name of an inner class. * * @param outerClassInternalName internal name of outer class, * ie {@code org.test.Foo} * @param innerClassShortName short name of inner class, ie {@code Bar} * @return fully qualified internal name of the inner class */ public static String getInnerClassName(String outerClassInternalName, String innerClassShortName) { assert isInternalName(outerClassInternalName); return outerClassInternalName + '$' + innerClassShortName; } /** * Return the outer class name of an inner class, or null if this is not * an inner class. * * @param name internal name which might be an inner class * @return an internal name of the enclosing class or null if none */ public static String getOuterClassName(String name) { int lastDollar = name.lastIndexOf('$'); if (lastDollar < 0) { return null; } return name.substring(0, lastDollar); } public static String getPackageName(String name) { assert isInternalName(name); int lastSlash = name.lastIndexOf('/'); if (lastSlash < 0) { return ""; } return name.substring(0, lastSlash); } public static String getShortClassName(String internalName) { assert isInternalName(internalName); String className = getClassName(internalName); int lastDollar = className.lastIndexOf('$', className.length() - 2); if (lastDollar < 0) { return className; } return className.substring(lastDollar + 1); } public static String toBinaryName(String internalName) { assert isInternalName(internalName); return internalName.replace('/', '.'); } public static String toSourceName(String internalName) { assert isInternalName(internalName); // don't change a trailing $ or slash to a . return NON_TRAILING_DOLLAR_SLASH.matcher(internalName).replaceAll(".$1"); } private InternalName() { } } /** * Represents a Java class name in source form, for example: * {@code org.example.Foo.Bar}. * * See {@link "http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#20207"} */ public static class SourceName { /** * Construct the fully qualified name of an inner class. * * @param outerClassSourceName source name of outer class, ie * {@code org.test.Foo} * @param innerClassShortName short name of inner class, ie {@code Bar} * @return fully qualified source name of the inner class */ public static String getInnerClassName(String outerClassSourceName, String innerClassShortName) { assert isSourceName(outerClassSourceName); return outerClassSourceName + '.' + innerClassShortName; } public static String getShortClassName(String sourceName) { assert isSourceName(sourceName); int lastDollar = sourceName.lastIndexOf('.'); if (lastDollar < 0) { return sourceName; } return sourceName.substring(lastDollar + 1); } private SourceName() { } } /** * Represents a Java class name in either source or binary form, for example: * {@code org.example.Foo.Bar or org.example.Foo$Bar}. * * See {@link "http://java.sun.com/docs/books/jls/third_edition/html/binaryComp.html#59892"} */ public static class SourceOrBinaryName { public static String toSourceName(String dottedName) { // don't change a trailing $ to a . return NON_TRAILING_DOLLAR.matcher(dottedName).replaceAll(".$1"); } } // Non-trailing $ private static final Pattern NON_TRAILING_DOLLAR = Pattern.compile("[$](\\p{javaJavaIdentifierStart})"); // Non-trailing $ or / private static final Pattern NON_TRAILING_DOLLAR_SLASH = Pattern.compile("[$/](\\p{javaJavaIdentifierStart})"); /** * Get the binary name for a Java class. * * @param clazz class literal * @return binary name for the class */ public static String getBinaryNameForClass(Class<?> clazz) { return clazz.getName(); } /** * Get the internal name for a Java class. * * @param clazz class literal * @return internal name for the class */ public static String getInternalNameForClass(Class<?> clazz) { return BinaryName.toInternalName(getBinaryNameForClass(clazz)); } /** * Get the source name for a Java class. * * @param clazz class literal * @return source name for the class */ public static String getSourceNameForClass(Class<?> clazz) { return clazz.getCanonicalName(); } /** * @return true if name could be a valid binary name. * * Note that many invalid names might pass this test -- in particular, source * names cannot be verified to know they are not valid binary names without * being able to tell the package name part of the name. * * @param name class name to test */ public static boolean isBinaryName(String name) { return name == null || !name.contains("/"); } /** * @return true if name could be a valid internal name. * * Note that many invalid names might pass this test. * * @param name class name to test */ public static boolean isInternalName(String name) { return name == null || !name.contains("."); } /** * @return true if name could be a valid source name. * * Note that many invalid names might pass this test. * * @param name class name to test */ public static boolean isSourceName(String name) { if (name == null) { return true; } int dollar = name.indexOf('$'); return !name.contains("/") && (dollar < 0 || dollar == name.length() - 1); } /** * @return true if name could be a valid source or binary name. * * Note that many invalid names might pass this test. * * @param name class name to test */ public static boolean isSourceOrBinaryName(String name) { return name == null || !name.contains("/"); } private Name() { } }