| /* |
| * 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); |
| } |
| |
| 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('.', '/'); |
| } |
| |
| /** |
| * @deprecated BinaryName to SourceName transformation is ambiguous in rare circumstances |
| * (for example when the name of a top level class includes a $, like "Foo$Bar"). |
| * Instead use some source of SourceName that has been accurately preserved since |
| * initial compilation. |
| */ |
| @Deprecated |
| 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); |
| } |
| |
| public static String toBinaryName(String internalName) { |
| assert isInternalName(internalName); |
| return internalName.replace('/', '.'); |
| } |
| |
| /** |
| * @deprecated InternalName to SourceName transformation is ambiguous in rare circumstances |
| * (for example when the name of a top level class includes a $, like "Foo$Bar"). |
| * Instead use some source of SourceName that has been accurately preserved since |
| * initial compilation. |
| */ |
| @Deprecated |
| 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 |
| */ |
| // TODO(stalcup): improve validation using Character.isJavaIdentifierStart() and |
| // Character.isJavaIdentifierPart(). |
| public static boolean isSourceName(String name) { |
| return name == null || !name.contains("/"); |
| } |
| |
| private Name() { |
| } |
| } |