--- a/jdk/src/share/classes/com/sun/beans/TypeResolver.java Fri Jul 27 22:39:44 2012 -0700
+++ b/jdk/src/share/classes/com/sun/beans/TypeResolver.java Mon Jul 30 13:35:10 2012 +0400
@@ -1,5 +1,5 @@
/*
- * 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 @@
* @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 @@
* @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 @@
* @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 @@
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 @@
* 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,91 +303,25 @@
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.
* Bug <a href="http://bugs.sun.com/view_bug.do?bug_id=5041784">5041784</a>
--- a/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Fri Jul 27 22:39:44 2012 -0700
+++ b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Mon Jul 30 13:35:10 2012 +0400
@@ -164,8 +164,10 @@
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);
+ }
}
}
}
--- a/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java Fri Jul 27 22:39:44 2012 -0700
+++ b/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java Mon Jul 30 13:35:10 2012 +0400
@@ -181,20 +181,21 @@
// 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);
--- a/jdk/src/share/classes/java/beans/Introspector.java Fri Jul 27 22:39:44 2012 -0700
+++ b/jdk/src/share/classes/java/beans/Introspector.java Mon Jul 30 13:35:10 2012 +0400
@@ -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.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 @@
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 @@
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 @@
}
// 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;
}
}
}
--- a/jdk/src/share/classes/java/beans/PropertyDescriptor.java Fri Jul 27 22:39:44 2012 -0700
+++ b/jdk/src/share/classes/java/beans/PropertyDescriptor.java Mon Jul 30 13:35:10 2012 +0400
@@ -210,12 +210,13 @@
// 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 @@
// 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 {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Performance/Test7122740.java Mon Jul 30 13:35:10 2012 +0400
@@ -0,0 +1,57 @@
+/*
+ * 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> {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Performance/Test7184799.java Mon Jul 30 13:35:10 2012 +0400
@@ -0,0 +1,71 @@
+/*
+ * 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));
+ }
+}