提交 dcf852bf 编写于 作者: M malenkov

7187618: PropertyDescriptor Performance Slow

Reviewed-by: rupashka
上级 2c21cf4c
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, 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
......@@ -45,6 +45,9 @@ import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
* @author Sergey Malenkov
*/
public final class TypeResolver {
private static final WeakCache<Type, Map<Type, Type>> CACHE = new WeakCache<>();
/**
* Replaces the given {@code type} in an inherited method
* with the actual type it has in the given {@code inClass}.
......@@ -149,12 +152,55 @@ public final class TypeResolver {
* @param formal the type where occurrences of the variables
* in {@code actual} will be replaced by the corresponding bound values
* @return a resolved type
*
* @see #TypeResolver(Type)
* @see #resolve(Type)
*/
public static Type resolve(Type actual, Type formal) {
return getTypeResolver(actual).resolve(formal);
if (formal instanceof Class) {
return formal;
}
if (formal instanceof GenericArrayType) {
Type comp = ((GenericArrayType) formal).getGenericComponentType();
comp = resolve(actual, comp);
return (comp instanceof Class)
? Array.newInstance((Class<?>) comp, 0).getClass()
: GenericArrayTypeImpl.make(comp);
}
if (formal instanceof ParameterizedType) {
ParameterizedType fpt = (ParameterizedType) formal;
Type[] actuals = resolve(actual, fpt.getActualTypeArguments());
return ParameterizedTypeImpl.make(
(Class<?>) fpt.getRawType(), actuals, fpt.getOwnerType());
}
if (formal instanceof WildcardType) {
WildcardType fwt = (WildcardType) formal;
Type[] upper = resolve(actual, fwt.getUpperBounds());
Type[] lower = resolve(actual, fwt.getLowerBounds());
return new WildcardTypeImpl(upper, lower);
}
if (formal instanceof TypeVariable) {
Map<Type, Type> map;
synchronized (CACHE) {
map = CACHE.get(actual);
if (map == null) {
map = new HashMap<>();
prepare(map, actual);
CACHE.put(actual, map);
}
}
Type result = map.get(formal);
if (result == null || result.equals(formal)) {
return formal;
}
result = fixGenericArray(result);
// A variable can be bound to another variable that is itself bound
// to something. For example, given:
// class Super<T> {...}
// class Mid<X> extends Super<T> {...}
// class Sub extends Mid<String>
// the variable T is bound to X, which is in turn bound to String.
// So if we have to resolve T, we need the tail recursion here.
return resolve(actual, result);
}
throw new IllegalArgumentException("Bad Type kind: " + formal.getClass());
}
/**
......@@ -164,12 +210,14 @@ public final class TypeResolver {
* @param actual the type that supplies bindings for type variables
* @param formals the array of types to resolve
* @return an array of resolved types
*
* @see #TypeResolver(Type)
* @see #resolve(Type[])
*/
public static Type[] resolve(Type actual, Type[] formals) {
return getTypeResolver(actual).resolve(formals);
int length = formals.length;
Type[] actuals = new Type[length];
for (int i = 0; i < length; i++) {
actuals[i] = resolve(actual, formals[i]);
}
return actuals;
}
/**
......@@ -228,32 +276,6 @@ public final class TypeResolver {
return classes;
}
public static TypeResolver getTypeResolver(Type type) {
synchronized (CACHE) {
TypeResolver resolver = CACHE.get(type);
if (resolver == null) {
resolver = new TypeResolver(type);
CACHE.put(type, resolver);
}
return resolver;
}
}
private static final WeakCache<Type, TypeResolver> CACHE = new WeakCache<>();
private final Map<TypeVariable<?>, Type> map = new HashMap<>();
/**
* Constructs the type resolver for the given actual type.
*
* @param actual the type that supplies bindings for type variables
*
* @see #prepare(Type)
*/
private TypeResolver(Type actual) {
prepare(actual);
}
/**
* Fills the map from type parameters
* to types as seen by the given {@code type}.
......@@ -265,9 +287,10 @@ public final class TypeResolver {
* to a {@link ParameterizedType ParameterizedType} with no parameters,
* or it represents the erasure of a {@link ParameterizedType ParameterizedType}.
*
* @param map the mappings of all type variables
* @param type the next type in the hierarchy
*/
private void prepare(Type type) {
private static void prepare(Map<Type, Type> map, Type type) {
Class<?> raw = (Class<?>)((type instanceof Class<?>)
? type
: ((ParameterizedType)type).getRawType());
......@@ -280,90 +303,24 @@ public final class TypeResolver {
assert formals.length == actuals.length;
for (int i = 0; i < formals.length; i++) {
this.map.put(formals[i], actuals[i]);
map.put(formals[i], actuals[i]);
}
Type gSuperclass = raw.getGenericSuperclass();
if (gSuperclass != null) {
prepare(gSuperclass);
prepare(map, gSuperclass);
}
for (Type gInterface : raw.getGenericInterfaces()) {
prepare(gInterface);
prepare(map, gInterface);
}
// If type is the raw version of a parameterized class, we type-erase
// all of its type variables, including inherited ones.
if (type instanceof Class<?> && formals.length > 0) {
for (Map.Entry<TypeVariable<?>, Type> entry : this.map.entrySet()) {
for (Map.Entry<Type, Type> entry : map.entrySet()) {
entry.setValue(erase(entry.getValue()));
}
}
}
/**
* Replaces the given {@code formal} type
* with the type it stand for in this type resolver.
*
* @param formal the array of types to resolve
* @return a resolved type
*/
private Type resolve(Type formal) {
if (formal instanceof Class) {
return formal;
}
if (formal instanceof GenericArrayType) {
Type comp = ((GenericArrayType)formal).getGenericComponentType();
comp = resolve(comp);
return (comp instanceof Class)
? Array.newInstance((Class<?>)comp, 0).getClass()
: GenericArrayTypeImpl.make(comp);
}
if (formal instanceof ParameterizedType) {
ParameterizedType fpt = (ParameterizedType)formal;
Type[] actuals = resolve(fpt.getActualTypeArguments());
return ParameterizedTypeImpl.make(
(Class<?>)fpt.getRawType(), actuals, fpt.getOwnerType());
}
if (formal instanceof WildcardType) {
WildcardType fwt = (WildcardType)formal;
Type[] upper = resolve(fwt.getUpperBounds());
Type[] lower = resolve(fwt.getLowerBounds());
return new WildcardTypeImpl(upper, lower);
}
if (!(formal instanceof TypeVariable)) {
throw new IllegalArgumentException("Bad Type kind: " + formal.getClass());
}
Type actual = this.map.get((TypeVariable) formal);
if (actual == null || actual.equals(formal)) {
return formal;
}
actual = fixGenericArray(actual);
return resolve(actual);
// A variable can be bound to another variable that is itself bound
// to something. For example, given:
// class Super<T> {...}
// class Mid<X> extends Super<T> {...}
// class Sub extends Mid<String>
// the variable T is bound to X, which is in turn bound to String.
// So if we have to resolve T, we need the tail recursion here.
}
/**
* Replaces all formal types in the given array
* with the types they stand for in this type resolver.
*
* @param formals the array of types to resolve
* @return an array of resolved types
*
* @see #resolve(Type)
*/
private Type[] resolve(Type[] formals) {
int length = formals.length;
Type[] actuals = new Type[length];
for (int i = 0; i < length; i++) {
actuals[i] = resolve(formals[i]);
}
return actuals;
}
/**
* Replaces a {@link GenericArrayType GenericArrayType}
* with plain array class where it is possible.
......
......@@ -164,8 +164,10 @@ public final class MethodFinder extends AbstractFinder<Method> {
return findAccessibleMethod(m);
}
Type[] gpts = m.getGenericParameterTypes();
if (Arrays.equals(params, TypeResolver.erase(TypeResolver.resolve(pt, gpts)))) {
return findAccessibleMethod(m);
if (params.length == gpts.length) {
if (Arrays.equals(params, TypeResolver.erase(TypeResolver.resolve(pt, gpts)))) {
return findAccessibleMethod(m);
}
}
}
}
......
......@@ -181,20 +181,21 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor {
// the Indexed readMethod was explicitly set to null.
return null;
}
String nextMethodName = Introspector.GET_PREFIX + getBaseName();
if (indexedReadMethodName == null) {
Class<?> type = getIndexedPropertyType0();
if (type == boolean.class || type == null) {
indexedReadMethodName = Introspector.IS_PREFIX + getBaseName();
} else {
indexedReadMethodName = Introspector.GET_PREFIX + getBaseName();
indexedReadMethodName = nextMethodName;
}
}
Class<?>[] args = { int.class };
indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args);
if (indexedReadMethod == null) {
if ((indexedReadMethod == null) && !indexedReadMethodName.equals(nextMethodName)) {
// no "is" method, so look for a "get" method.
indexedReadMethodName = Introspector.GET_PREFIX + getBaseName();
indexedReadMethodName = nextMethodName;
indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args);
}
setIndexedReadMethod0(indexedReadMethod);
......
......@@ -25,6 +25,7 @@
package java.beans;
import com.sun.beans.TypeResolver;
import com.sun.beans.WeakCache;
import com.sun.beans.finder.ClassFinder;
......@@ -34,6 +35,7 @@ import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.ArrayList;
......@@ -951,44 +953,61 @@ public class Introspector {
continue;
}
Class<?>[] argTypes = FeatureDescriptor.getParameterTypes(beanClass, method);
Class<?> resultType = FeatureDescriptor.getReturnType(beanClass, method);
if (name.startsWith(ADD_PREFIX) && argTypes.length == 1 &&
resultType == Void.TYPE &&
Introspector.isSubclass(argTypes[0], eventListenerType)) {
String listenerName = name.substring(3);
if (listenerName.length() > 0 &&
argTypes[0].getName().endsWith(listenerName)) {
if (adds == null) {
adds = new HashMap<>();
if (name.startsWith(ADD_PREFIX)) {
Class<?> returnType = method.getReturnType();
if (returnType == void.class) {
Type[] parameterTypes = method.getGenericParameterTypes();
if (parameterTypes.length == 1) {
Class<?> type = TypeResolver.erase(TypeResolver.resolveInClass(beanClass, parameterTypes[0]));
if (Introspector.isSubclass(type, eventListenerType)) {
String listenerName = name.substring(3);
if (listenerName.length() > 0 &&
type.getName().endsWith(listenerName)) {
if (adds == null) {
adds = new HashMap<>();
}
adds.put(listenerName, method);
}
}
}
adds.put(listenerName, method);
}
}
else if (name.startsWith(REMOVE_PREFIX) && argTypes.length == 1 &&
resultType == Void.TYPE &&
Introspector.isSubclass(argTypes[0], eventListenerType)) {
String listenerName = name.substring(6);
if (listenerName.length() > 0 &&
argTypes[0].getName().endsWith(listenerName)) {
if (removes == null) {
removes = new HashMap<>();
else if (name.startsWith(REMOVE_PREFIX)) {
Class<?> returnType = method.getReturnType();
if (returnType == void.class) {
Type[] parameterTypes = method.getGenericParameterTypes();
if (parameterTypes.length == 1) {
Class<?> type = TypeResolver.erase(TypeResolver.resolveInClass(beanClass, parameterTypes[0]));
if (Introspector.isSubclass(type, eventListenerType)) {
String listenerName = name.substring(6);
if (listenerName.length() > 0 &&
type.getName().endsWith(listenerName)) {
if (removes == null) {
removes = new HashMap<>();
}
removes.put(listenerName, method);
}
}
}
removes.put(listenerName, method);
}
}
else if (name.startsWith(GET_PREFIX) && argTypes.length == 0 &&
resultType.isArray() &&
Introspector.isSubclass(resultType.getComponentType(),
eventListenerType)) {
String listenerName = name.substring(3, name.length() - 1);
if (listenerName.length() > 0 &&
resultType.getComponentType().getName().endsWith(listenerName)) {
if (gets == null) {
gets = new HashMap<>();
else if (name.startsWith(GET_PREFIX)) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
Class<?> returnType = FeatureDescriptor.getReturnType(beanClass, method);
if (returnType.isArray()) {
Class<?> type = returnType.getComponentType();
if (Introspector.isSubclass(type, eventListenerType)) {
String listenerName = name.substring(3, name.length() - 1);
if (listenerName.length() > 0 &&
type.getName().endsWith(listenerName)) {
if (gets == null) {
gets = new HashMap<>();
}
gets.put(listenerName, method);
}
}
}
gets.put(listenerName, method);
}
}
}
......@@ -1240,11 +1259,11 @@ public class Introspector {
private boolean isEventHandler(Method m) {
// We assume that a method is an event handler if it has a single
// argument, whose type inherit from java.util.Event.
Class argTypes[] = FeatureDescriptor.getParameterTypes(beanClass, m);
Type argTypes[] = m.getGenericParameterTypes();
if (argTypes.length != 1) {
return false;
}
return isSubclass(argTypes[0], EventObject.class);
return isSubclass(TypeResolver.erase(TypeResolver.resolveInClass(beanClass, argTypes[0])), EventObject.class);
}
/*
......@@ -1296,24 +1315,25 @@ public class Introspector {
}
// make sure method signature matches.
Class params[] = FeatureDescriptor.getParameterTypes(start, method);
if (method.getName().equals(methodName) &&
params.length == argCount) {
if (args != null) {
boolean different = false;
if (argCount > 0) {
for (int j = 0; j < argCount; j++) {
if (params[j] != args[j]) {
different = true;
if (method.getName().equals(methodName)) {
Type[] params = method.getGenericParameterTypes();
if (params.length == argCount) {
if (args != null) {
boolean different = false;
if (argCount > 0) {
for (int j = 0; j < argCount; j++) {
if (TypeResolver.erase(TypeResolver.resolveInClass(start, params[j])) != args[j]) {
different = true;
continue;
}
}
if (different) {
continue;
}
}
if (different) {
continue;
}
}
return method;
}
return method;
}
}
}
......
......@@ -210,12 +210,13 @@ public class PropertyDescriptor extends FeatureDescriptor {
// The read method was explicitly set to null.
return null;
}
String nextMethodName = Introspector.GET_PREFIX + getBaseName();
if (readMethodName == null) {
Class<?> type = getPropertyType0();
if (type == boolean.class || type == null) {
readMethodName = Introspector.IS_PREFIX + getBaseName();
} else {
readMethodName = Introspector.GET_PREFIX + getBaseName();
readMethodName = nextMethodName;
}
}
......@@ -225,8 +226,8 @@ public class PropertyDescriptor extends FeatureDescriptor {
// methods. If an "is" method exists, this is the official
// reader method so look for this one first.
readMethod = Introspector.findMethod(cls, readMethodName, 0);
if (readMethod == null) {
readMethodName = Introspector.GET_PREFIX + getBaseName();
if ((readMethod == null) && !readMethodName.equals(nextMethodName)) {
readMethodName = nextMethodName;
readMethod = Introspector.findMethod(cls, readMethodName, 0);
}
try {
......
/*
* Copyright (c) 2012, 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 7122740
* @summary Tests just a benchmark of PropertyDescriptor(String, Class) performance
* @author Sergey Malenkov
* @run main/manual Test7122740
*/
import java.beans.PropertyDescriptor;
public class Test7122740 {
public static void main(String[] args) throws Exception {
long time = System.nanoTime();
for (int i = 0; i < 1000; i++) {
new PropertyDescriptor("name", PropertyDescriptor.class);
new PropertyDescriptor("value", Concrete.class);
}
time -= System.nanoTime();
System.out.println("Time (ms): " + (-time / 1000000));
}
public static class Abstract<T> {
private T value;
public T getValue() {
return this.value;
}
public void setValue(T value) {
this.value = value;
}
}
private static class Concrete extends Abstract<String> {
}
}
/*
* Copyright (c) 2012, 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 7184799
* @summary Tests just a benchmark of Introspector.getBeanInfo(Class) performance
* @author Sergey Malenkov
* @run main/manual Test7184799
*/
import java.beans.Introspector;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Test7184799 {
private static final Class[] TYPES = {
Class.class,
String.class,
Character.class,
Boolean.class,
Byte.class,
Short.class,
Integer.class,
Long.class,
Float.class,
Double.class,
Collection.class,
Set.class,
HashSet.class,
TreeSet.class,
LinkedHashSet.class,
Map.class,
HashMap.class,
TreeMap.class,
LinkedHashMap.class,
WeakHashMap.class,
ConcurrentHashMap.class,
Dictionary.class,
Exception.class,
};
public static void main(String[] args) throws Exception {
long time = System.nanoTime();
for (Class type : TYPES) {
Introspector.getBeanInfo(type);
}
time -= System.nanoTime();
System.out.println("Time (ms): " + (-time / 1000000));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册