提交 8efcbe9d 编写于 作者: D darcy

6298888: Add toGenericString to j.l.Class and getTypeName to j.l.reflect.Type

6992705: Include modifiers in Class.toGenericString()
Summary: Class.toGenericString and supporting changes; additional reviews by Peter Levart
Reviewed-by: alanb
上级 c1f26c32
......@@ -113,8 +113,7 @@ import sun.reflect.misc.ReflectUtil;
* @see java.lang.ClassLoader#defineClass(byte[], int, int)
* @since JDK1.0
*/
public final
class Class<T> implements java.io.Serializable,
public final class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
......@@ -150,6 +149,75 @@ public final
+ getName();
}
/**
* Returns a string describing this {@code Class}, including
* information about modifiers and type parameters.
*
* The string is formatted as a list of type modifiers, if any,
* followed by the kind of type (empty string for primitive types
* and {@code class}, {@code enum}, {@code interface}, or {@code
* &#64;interface}, as appropriate), followed by the type's name,
* followed by an angle-bracketed comma-separated list of the
* type's type parameters, if any.
*
* A space is used to separate modifiers from one another and to
* separate any modifiers from the kind of type. The modifiers
* occur in canonical order. If there are no type parameters, the
* type parameter list is elided.
*
* <p>Note that since information about the runtime representation
* of a type is being generated, modifiers not present on the
* originating source code or illegal on the originating source
* code may be present.
*
* @return a string describing this {@code Class}, including
* information about modifiers and type parameters
*
* @since 1.8
*/
public String toGenericString() {
if (isPrimitive()) {
return toString();
} else {
StringBuilder sb = new StringBuilder();
// Class modifiers are a superset of interface modifiers
int modifiers = getModifiers() & Modifier.classModifiers();
if (modifiers != 0) {
sb.append(Modifier.toString(modifiers));
sb.append(' ');
}
if (isAnnotation()) {
sb.append('@');
}
if (isInterface()) { // Note: all annotation types are interfaces
sb.append("interface");
} else {
if (isEnum())
sb.append("enum");
else
sb.append("class");
}
sb.append(' ');
sb.append(getName());
TypeVariable<?>[] typeparms = getTypeParameters();
if (typeparms.length > 0) {
boolean first = true;
sb.append('<');
for(TypeVariable<?> typeparm: typeparms) {
if (!first)
sb.append(',');
sb.append(typeparm.getTypeName());
first = false;
}
sb.append('>');
}
return sb.toString();
}
}
/**
* Returns the {@code Class} object associated with the class or
......@@ -1163,6 +1231,32 @@ public final
return simpleName.substring(index);
}
/**
* Return an informative string for the name of this type.
*
* @return an informative string for the name of this type
* @since 1.8
*/
public String getTypeName() {
if (isArray()) {
try {
Class<?> cl = this;
int dimensions = 0;
while (cl.isArray()) {
dimensions++;
cl = cl.getComponentType();
}
StringBuilder sb = new StringBuilder();
sb.append(cl.getName());
for (int i = 0; i < dimensions; i++) {
sb.append("[]");
}
return sb.toString();
} catch (Throwable e) { /*FALLTHRU*/ }
}
return getName();
}
/**
* Character.isDigit answers {@code true} to some non-ascii
* digits. This one does not.
......
......@@ -297,7 +297,7 @@ public final class Constructor<T> extends Executable {
@Override
void specificToStringHeader(StringBuilder sb) {
sb.append(Field.getTypeName(getDeclaringClass()));
sb.append(getDeclaringClass().getTypeName());
}
/**
......
......@@ -82,7 +82,7 @@ public abstract class Executable extends AccessibleObject
void separateWithCommas(Class<?>[] types, StringBuilder sb) {
for (int j = 0; j < types.length; j++) {
sb.append(Field.getTypeName(types[j]));
sb.append(types[j].getTypeName());
if (j < (types.length - 1))
sb.append(",");
}
......@@ -161,9 +161,7 @@ public abstract class Executable extends AccessibleObject
sb.append('(');
Type[] params = getGenericParameterTypes();
for (int j = 0; j < params.length; j++) {
String param = (params[j] instanceof Class)?
Field.getTypeName((Class)params[j]):
(params[j].toString());
String param = params[j].getTypeName();
if (isVarArgs() && (j == params.length - 1)) // replace T[] with T...
param = param.replaceFirst("\\[\\]$", "...");
sb.append(param);
......
......@@ -295,8 +295,8 @@ class Field extends AccessibleObject implements Member {
public String toString() {
int mod = getModifiers();
return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
+ getTypeName(getType()) + " "
+ getTypeName(getDeclaringClass()) + "."
+ getType().getTypeName() + " "
+ getDeclaringClass().getTypeName() + "."
+ getName());
}
......@@ -324,9 +324,8 @@ class Field extends AccessibleObject implements Member {
int mod = getModifiers();
Type fieldType = getGenericType();
return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
+ ((fieldType instanceof Class) ?
getTypeName((Class)fieldType): fieldType.toString())+ " "
+ getTypeName(getDeclaringClass()) + "."
+ fieldType.getTypeName() + " "
+ getDeclaringClass().getTypeName() + "."
+ getName());
}
......@@ -996,29 +995,6 @@ class Field extends AccessibleObject implements Member {
}
}
/*
* Utility routine to paper over array type names
*/
static String getTypeName(Class<?> type) {
if (type.isArray()) {
try {
Class<?> cl = type;
int dimensions = 0;
while (cl.isArray()) {
dimensions++;
cl = cl.getComponentType();
}
StringBuffer sb = new StringBuffer();
sb.append(cl.getName());
for (int i = 0; i < dimensions; i++) {
sb.append("[]");
}
return sb.toString();
} catch (Throwable e) { /*FALLTHRU*/ }
}
return type.getName();
}
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.5
......
......@@ -342,9 +342,8 @@ public final class Method extends Executable {
* specified by "The Java Language Specification". This is
* {@code public}, {@code protected} or {@code private} first,
* and then other modifiers in the following order:
* {@code abstract}, {@code static}, {@code final},
* {@code synchronized}, {@code native}, {@code strictfp},
* {@code default}.
* {@code abstract}, {@code default}, {@code static}, {@code final},
* {@code synchronized}, {@code native}, {@code strictfp}.
*
* @return a string describing this {@code Method}
*
......@@ -359,8 +358,8 @@ public final class Method extends Executable {
@Override
void specificToStringHeader(StringBuilder sb) {
sb.append(Field.getTypeName(getReturnType())).append(' ');
sb.append(Field.getTypeName(getDeclaringClass())).append('.');
sb.append(getReturnType().getTypeName()).append(' ');
sb.append(getDeclaringClass().getTypeName()).append('.');
sb.append(getName());
}
......@@ -387,16 +386,14 @@ public final class Method extends Executable {
* class name. If the method is declared to throw exceptions, the
* parameter list is followed by a space, followed by the word
* throws followed by a comma-separated list of the generic thrown
* exception types. If there are no type parameters, the type
* parameter list is elided.
* exception types.
*
* <p>The access modifiers are placed in canonical order as
* specified by "The Java Language Specification". This is
* {@code public}, {@code protected} or {@code private} first,
* and then other modifiers in the following order:
* {@code abstract}, {@code static}, {@code final},
* {@code synchronized}, {@code native}, {@code strictfp},
* {@code default}.
* {@code abstract}, {@code default}, {@code static}, {@code final},
* {@code synchronized}, {@code native}, {@code strictfp}.
*
* @return a string describing this {@code Method},
* include type parameters
......@@ -413,11 +410,8 @@ public final class Method extends Executable {
@Override
void specificToGenericStringHeader(StringBuilder sb) {
Type genRetType = getGenericReturnType();
sb.append( ((genRetType instanceof Class<?>)?
Field.getTypeName((Class<?>)genRetType):genRetType.toString()))
.append(' ');
sb.append(Field.getTypeName(getDeclaringClass())).append('.');
sb.append(genRetType.getTypeName()).append(' ');
sb.append(getDeclaringClass().getTypeName()).append('.');
sb.append(getName());
}
......
......@@ -43,8 +43,7 @@ import sun.reflect.ReflectionFactory;
* @author Nakul Saraiya
* @author Kenneth Russell
*/
public
class Modifier {
public class Modifier {
/*
* Bootstrapping protocol between java.lang and java.lang.reflect
......@@ -233,7 +232,7 @@ class Modifier {
* represented by {@code mod}
*/
public static String toString(int mod) {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
......@@ -393,7 +392,7 @@ class Modifier {
*
*/
static final int ACCESS_MODIFIERS =
Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
/**
* Return an {@code int} value OR-ing together the source language
......
......@@ -110,21 +110,19 @@ public final class Parameter implements AnnotatedElement {
public String toString() {
final StringBuilder sb = new StringBuilder();
final Type type = getParameterizedType();
final String typename = (type instanceof Class)?
Field.getTypeName((Class)type):
(type.toString());
final String typename = type.getTypeName();
sb.append(Modifier.toString(getModifiers()));
if(0 != modifiers)
sb.append(" ");
sb.append(' ');
if(isVarArgs())
sb.append(typename.replaceFirst("\\[\\]$", "..."));
else
sb.append(typename);
sb.append(" ");
sb.append(' ');
sb.append(getName());
return sb.toString();
......
......@@ -32,6 +32,17 @@ package java.lang.reflect;
*
* @since 1.5
*/
public interface Type {
/**
* Returns a string describing this type, including information
* about any type parameters.
*
* @implSpec The default implementation calls {@code toString}.
*
* @return a string describing this type
* @since 1.8
*/
default String getTypeName() {
return toString();
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6298888 6992705
* @summary Check Class.toGenericString()
* @author Joseph D. Darcy
*/
import java.lang.reflect.*;
import java.lang.annotation.*;
import java.util.*;
@ExpectedGenericString("public class GenericStringTest")
public class GenericStringTest {
public static void main(String... args){
int failures = 0;
failures += checkToGenericString(int.class, "int");
Class<?>[] types = {
GenericStringTest.class,
AnInterface.class,
LocalMap.class,
AnEnum.class,
AnotherEnum.class,
};
for(Class<?> clazz : types) {
failures += checkToGenericString(clazz, clazz.getAnnotation(ExpectedGenericString.class).value());
}
if (failures > 0) {
throw new RuntimeException();
}
}
private static int checkToGenericString(Class<?> clazz, String expected) {
String genericString = clazz.toGenericString();
if (!genericString.equals(expected)) {
System.err.printf("Unexpected Class.toGenericString output; expected '%s', got '%s'.%n",
expected,
genericString);
return 1;
} else
return 0;
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface ExpectedGenericString {
String value();
}
@ExpectedGenericString("abstract interface AnInterface")
strictfp interface AnInterface {}
@ExpectedGenericString("abstract interface LocalMap<K,V>")
interface LocalMap<K,V> {}
@ExpectedGenericString("final enum AnEnum")
enum AnEnum {
FOO;
}
@ExpectedGenericString("enum AnotherEnum")
enum AnotherEnum {
BAR{};
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册