--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/introspect/ClassInfo.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package com.sun.beans.introspect;
+
+import com.sun.beans.util.Cache;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import static sun.reflect.misc.ReflectUtil.checkPackageAccess;
+
+public final class ClassInfo {
+ private static final ClassInfo DEFAULT = new ClassInfo(null);
+ private static final Cache<Class<?>,ClassInfo> CACHE
+ = new Cache<Class<?>,ClassInfo>(Cache.Kind.SOFT, Cache.Kind.SOFT) {
+ @Override
+ public ClassInfo create(Class<?> type) {
+ return new ClassInfo(type);
+ }
+ };
+
+ public static ClassInfo get(Class<?> type) {
+ if (type == null) {
+ return DEFAULT;
+ }
+ try {
+ checkPackageAccess(type);
+ return CACHE.get(type);
+ } catch (SecurityException exception) {
+ return DEFAULT;
+ }
+ }
+
+ private final Object mutex = new Object();
+ private final Class<?> type;
+ private List<Method> methods;
+ private Map<String,PropertyInfo> properties;
+ private Map<String,EventSetInfo> eventSets;
+
+ private ClassInfo(Class<?> type) {
+ this.type = type;
+ }
+
+ public List<Method> getMethods() {
+ if (this.methods == null) {
+ synchronized (this.mutex) {
+ if (this.methods == null) {
+ this.methods = MethodInfo.get(this.type);
+ }
+ }
+ }
+ return this.methods;
+ }
+
+ public Map<String,PropertyInfo> getProperties() {
+ if (this.properties == null) {
+ synchronized (this.mutex) {
+ if (this.properties == null) {
+ this.properties = PropertyInfo.get(this.type);
+ }
+ }
+ }
+ return this.properties;
+ }
+
+ public Map<String,EventSetInfo> getEventSets() {
+ if (this.eventSets == null) {
+ synchronized (this.mutex) {
+ if (this.eventSets == null) {
+ this.eventSets = EventSetInfo.get(this.type);
+ }
+ }
+ }
+ return this.eventSets;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/introspect/EventSetInfo.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package com.sun.beans.introspect;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TooManyListenersException;
+import java.util.TreeMap;
+
+public final class EventSetInfo {
+ private MethodInfo add;
+ private MethodInfo remove;
+ private MethodInfo get;
+
+ private EventSetInfo() {
+ }
+
+ private boolean initialize() {
+ if ((this.add == null) || (this.remove == null) || (this.remove.type != this.add.type)) {
+ return false;
+ }
+ if ((this.get != null) && (this.get.type != this.add.type)) {
+ this.get = null;
+ }
+ return true;
+ }
+
+ public Class<?> getListenerType() {
+ return this.add.type;
+ }
+
+ public Method getAddMethod() {
+ return this.add.method;
+ }
+
+ public Method getRemoveMethod() {
+ return this.remove.method;
+ }
+
+ public Method getGetMethod() {
+ return (this.get == null) ? null : this.get.method;
+ }
+
+ public boolean isUnicast() {
+ // if the adder method throws the TooManyListenersException
+ // then it is an Unicast event source
+ return this.add.isThrow(TooManyListenersException.class);
+ }
+
+ private static MethodInfo getInfo(MethodInfo info, Method method, int prefix, int postfix) {
+ Class<?> type = (postfix > 0)
+ ? MethodInfo.resolve(method, method.getGenericReturnType()).getComponentType()
+ : MethodInfo.resolve(method, method.getGenericParameterTypes()[0]);
+
+ if ((type != null) && EventListener.class.isAssignableFrom(type)) {
+ String name = method.getName();
+ if (prefix + postfix < name.length()) {
+ if (type.getName().endsWith(name.substring(prefix, name.length() - postfix))) {
+ if ((info == null) || info.type.isAssignableFrom(type)) {
+ return new MethodInfo(method, type);
+ }
+ }
+ }
+ }
+ return info;
+ }
+
+ private static EventSetInfo getInfo(Map<String,EventSetInfo> map, String key) {
+ EventSetInfo info = map.get(key);
+ if (info == null) {
+ info = new EventSetInfo();
+ map.put(key, info);
+ }
+ return info;
+ }
+
+ public static Map<String,EventSetInfo> get(Class<?> type) {
+ List<Method> methods = ClassInfo.get(type).getMethods();
+ if (methods.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<String,EventSetInfo> map = new TreeMap<>();
+ for (Method method : ClassInfo.get(type).getMethods()) {
+ if (!Modifier.isStatic(method.getModifiers())) {
+ Class<?> returnType = method.getReturnType();
+ String name = method.getName();
+ switch (method.getParameterCount()) {
+ case 1:
+ if ((returnType == void.class) && name.endsWith("Listener")) {
+ if (name.startsWith("add")) {
+ EventSetInfo info = getInfo(map, name.substring(3, name.length() - 8));
+ info.add = getInfo(info.add, method, 3, 0);
+ } else if (name.startsWith("remove")) {
+ EventSetInfo info = getInfo(map, name.substring(6, name.length() - 8));
+ info.remove = getInfo(info.remove, method, 6, 0);
+ }
+ }
+ break;
+ case 0:
+ if (returnType.isArray() && name.startsWith("get") && name.endsWith("Listeners")) {
+ EventSetInfo info = getInfo(map, name.substring(3, name.length() - 9));
+ info.get = getInfo(info.get, method, 3, 1);
+ }
+ break;
+ }
+ }
+ }
+ Iterator<EventSetInfo> iterator = map.values().iterator();
+ while (iterator.hasNext()) {
+ if (!iterator.next().initialize()) {
+ iterator.remove();
+ }
+ }
+ return !map.isEmpty()
+ ? Collections.unmodifiableMap(map)
+ : Collections.emptyMap();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/introspect/MethodInfo.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package com.sun.beans.introspect;
+
+import com.sun.beans.TypeResolver;
+import com.sun.beans.finder.MethodFinder;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+final class MethodInfo {
+ final Method method;
+ final Class<?> type;
+
+ MethodInfo(Method method, Class<?> type) {
+ this.method = method;
+ this.type = type;
+ }
+
+ MethodInfo(Method method, Type type) {
+ this.method = method;
+ this.type = resolve(method, type);
+ }
+
+ boolean isThrow(Class<?> exception) {
+ for (Class<?> type : this.method.getExceptionTypes()) {
+ if (type == exception) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static Class<?> resolve(Method method, Type type) {
+ return TypeResolver.erase(TypeResolver.resolveInClass(method.getDeclaringClass(), type));
+ }
+
+ static List<Method> get(Class<?> type) {
+ List<Method> list = null;
+ if (type != null) {
+ boolean inaccessible = !Modifier.isPublic(type.getModifiers());
+ for (Method method : type.getMethods()) {
+ if (method.getDeclaringClass().equals(type)) {
+ if (inaccessible) {
+ try {
+ method = MethodFinder.findAccessibleMethod(method);
+ if (!method.getDeclaringClass().isInterface()) {
+ method = null; // ignore methods from superclasses
+ }
+ } catch (NoSuchMethodException exception) {
+ // commented out because of 6976577
+ // method = null; // ignore inaccessible methods
+ }
+ }
+ if (method != null) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ list.add(method);
+ }
+ }
+ }
+ }
+ return (list != null)
+ ? Collections.unmodifiableList(list)
+ : Collections.emptyList();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/introspect/PropertyInfo.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package com.sun.beans.introspect;
+
+import java.beans.BeanProperty;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import static com.sun.beans.finder.ClassFinder.findClass;
+
+public final class PropertyInfo {
+ public enum Name {bound, expert, hidden, preferred, visualUpdate, description, enumerationValues}
+
+ private static final String VETO_EXCEPTION_NAME = "java.beans.PropertyVetoException";
+ private static final Class<?> VETO_EXCEPTION;
+
+ static {
+ Class<?> type;
+ try {
+ type = Class.forName(VETO_EXCEPTION_NAME);
+ } catch (Exception exception) {
+ type = null;
+ }
+ VETO_EXCEPTION = type;
+ }
+
+ private Class<?> type;
+ private MethodInfo read;
+ private MethodInfo write;
+ private PropertyInfo indexed;
+ private List<MethodInfo> readList;
+ private List<MethodInfo> writeList;
+ private Map<Name,Object> map;
+
+ private PropertyInfo() {
+ }
+
+ private boolean initialize() {
+ if (this.read != null) {
+ this.type = this.read.type;
+ }
+ if (this.readList != null) {
+ for (MethodInfo info : this.readList) {
+ if ((this.read == null) || this.read.type.isAssignableFrom(info.type)) {
+ this.read = info;
+ this.type = info.type;
+ }
+ }
+ this.readList = null;
+ }
+ if (this.writeList != null) {
+ for (MethodInfo info : this.writeList) {
+ if (this.type == null) {
+ this.write = info;
+ this.type = info.type;
+ } else if (this.type.isAssignableFrom(info.type)) {
+ if ((this.write == null) || this.write.type.isAssignableFrom(info.type)) {
+ this.write = info;
+ }
+ }
+ }
+ this.writeList = null;
+ }
+ if (this.indexed != null) {
+ if ((this.type != null) && !this.type.isArray()) {
+ this.indexed = null; // property type is not an array
+ } else if (!this.indexed.initialize()) {
+ this.indexed = null; // cannot initialize indexed methods
+ } else if ((this.type != null) && (this.indexed.type != this.type.getComponentType())) {
+ this.indexed = null; // different property types
+ } else {
+ this.map = this.indexed.map;
+ this.indexed.map = null;
+ }
+ }
+ if ((this.type == null) && (this.indexed == null)) {
+ return false;
+ }
+ initialize(this.write);
+ initialize(this.read);
+ return true;
+ }
+
+ private void initialize(MethodInfo info) {
+ if (info != null) {
+ BeanProperty annotation = info.method.getAnnotation(BeanProperty.class);
+ if (annotation != null) {
+ if (!annotation.bound()) {
+ put(Name.bound, Boolean.FALSE);
+ }
+ put(Name.expert, annotation.expert());
+ put(Name.hidden, annotation.hidden());
+ put(Name.preferred, annotation.preferred());
+ put(Name.visualUpdate, annotation.visualUpdate());
+ put(Name.description, annotation.description());
+ String[] values = annotation.enumerationValues();
+ if (0 < values.length) {
+ try {
+ Object[] array = new Object[3 * values.length];
+ int index = 0;
+ for (String value : values) {
+ Class<?> type = info.method.getDeclaringClass();
+ String name = value;
+ int pos = value.lastIndexOf('.');
+ if (pos > 0) {
+ name = value.substring(0, pos);
+ if (name.indexOf('.') < 0) {
+ String pkg = type.getName();
+ name = pkg.substring(0, 1 + Math.max(
+ pkg.lastIndexOf('.'),
+ pkg.lastIndexOf('$'))) + name;
+ }
+ type = findClass(name);
+ name = value.substring(pos + 1);
+ }
+ Field field = type.getField(name);
+ if (Modifier.isStatic(field.getModifiers()) && info.type.isAssignableFrom(field.getType())) {
+ array[index++] = name;
+ array[index++] = field.get(null);
+ array[index++] = value;
+ }
+ }
+ if (index == array.length) {
+ put(Name.enumerationValues, array);
+ }
+ } catch (Exception ignored) {
+ ignored.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ public Class<?> getPropertyType() {
+ return this.type;
+ }
+
+ public Method getReadMethod() {
+ return (this.read == null) ? null : this.read.method;
+ }
+
+ public Method getWriteMethod() {
+ return (this.write == null) ? null : this.write.method;
+ }
+
+ public PropertyInfo getIndexed() {
+ return this.indexed;
+ }
+
+ public boolean isConstrained() {
+ if (this.write != null) {
+ if (VETO_EXCEPTION == null) {
+ for (Class<?> type : this.write.method.getExceptionTypes()) {
+ if (type.getName().equals(VETO_EXCEPTION_NAME)) {
+ return true;
+ }
+ }
+ } else if (this.write.isThrow(VETO_EXCEPTION)) {
+ return true;
+ }
+ }
+ return (this.indexed != null) && this.indexed.isConstrained();
+ }
+
+ public boolean is(Name name) {
+ Object value = get(name);
+ return (value instanceof Boolean)
+ ? (Boolean) value
+ : Name.bound.equals(name);
+ }
+
+ public Object get(Name name) {
+ return this.map == null ? null : this.map.get(name);
+ }
+
+ private void put(Name name, boolean value) {
+ if (value) {
+ put(name, Boolean.TRUE);
+ }
+ }
+
+ private void put(Name name, String value) {
+ if (0 < value.length()) {
+ put(name, (Object) value);
+ }
+ }
+
+ private void put(Name name, Object value) {
+ if (this.map == null) {
+ this.map = new EnumMap<>(Name.class);
+ }
+ this.map.put(name, value);
+ }
+
+ private static List<MethodInfo> add(List<MethodInfo> list, Method method, Type type) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ list.add(new MethodInfo(method, type));
+ return list;
+ }
+
+ private static boolean isPrefix(String name, String prefix) {
+ return name.length() > prefix.length() && name.startsWith(prefix);
+ }
+
+ private static PropertyInfo getInfo(Map<String,PropertyInfo> map, String key, boolean indexed) {
+ PropertyInfo info = map.get(key);
+ if (info == null) {
+ info = new PropertyInfo();
+ map.put(key, info);
+ }
+ if (!indexed) {
+ return info;
+ }
+ if (info.indexed == null) {
+ info.indexed = new PropertyInfo();
+ }
+ return info.indexed;
+ }
+
+ public static Map<String,PropertyInfo> get(Class<?> type) {
+ List<Method> methods = ClassInfo.get(type).getMethods();
+ if (methods.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<String,PropertyInfo> map = new TreeMap<>();
+ for (Method method : methods) {
+ if (!Modifier.isStatic(method.getModifiers())) {
+ Class<?> returnType = method.getReturnType();
+ String name = method.getName();
+ switch (method.getParameterCount()) {
+ case 0:
+ if (returnType.equals(boolean.class) && isPrefix(name, "is")) {
+ PropertyInfo info = getInfo(map, name.substring(2), false);
+ info.read = new MethodInfo(method, boolean.class);
+ } else if (!returnType.equals(void.class) && isPrefix(name, "get")) {
+ PropertyInfo info = getInfo(map, name.substring(3), false);
+ info.readList = add(info.readList, method, method.getGenericReturnType());
+ }
+ break;
+ case 1:
+ if (returnType.equals(void.class) && isPrefix(name, "set")) {
+ PropertyInfo info = getInfo(map, name.substring(3), false);
+ info.writeList = add(info.writeList, method, method.getGenericParameterTypes()[0]);
+ } else if (!returnType.equals(void.class) && method.getParameterTypes()[0].equals(int.class) && isPrefix(name, "get")) {
+ PropertyInfo info = getInfo(map, name.substring(3), true);
+ info.readList = add(info.readList, method, method.getGenericReturnType());
+ }
+ break;
+ case 2:
+ if (returnType.equals(void.class) && method.getParameterTypes()[0].equals(int.class) && isPrefix(name, "set")) {
+ PropertyInfo info = getInfo(map, name.substring(3), true);
+ info.writeList = add(info.writeList, method, method.getGenericParameterTypes()[1]);
+ }
+ break;
+ }
+ }
+ }
+ Iterator<PropertyInfo> iterator = map.values().iterator();
+ while (iterator.hasNext()) {
+ if (!iterator.next().initialize()) {
+ iterator.remove();
+ }
+ }
+ return !map.isEmpty()
+ ? Collections.unmodifiableMap(map)
+ : Collections.emptyMap();
+ }
+}
--- a/jdk/src/share/classes/java/beans/BeanDescriptor.java Wed Jul 02 23:03:27 2014 -0700
+++ b/jdk/src/share/classes/java/beans/BeanDescriptor.java Thu Jul 03 16:55:55 2014 +0400
@@ -22,10 +22,10 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package java.beans;
import java.lang.ref.Reference;
+import javax.swing.SwingContainer;
/**
* A BeanDescriptor provides global information about a "bean",
@@ -69,6 +69,23 @@
name = name.substring(name.indexOf('.')+1);
}
setName(name);
+
+ JavaBean annotation = beanClass.getAnnotation(JavaBean.class);
+ if (annotation != null) {
+ setPreferred(true);
+ String description = annotation.description();
+ if (!description.isEmpty()) {
+ setShortDescription(description);
+ }
+ }
+ SwingContainer container = beanClass.getAnnotation(SwingContainer.class);
+ if (container != null) {
+ setValue("isContainer", container.value());
+ String delegate = container.delegate();
+ if (!delegate.isEmpty()) {
+ setValue("containerDelegate", delegate);
+ }
+ }
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/beans/BeanProperty.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package java.beans;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * An annotation used to specify some property-related information
+ * for the automatically generated {@link BeanInfo} classes.
+ * This annotation is not used if the annotated class
+ * has a corresponding user-defined {@code BeanInfo} class,
+ * which does not imply the automatic analysis.
+ *
+ * @see BeanInfo#getPropertyDescriptors
+ * @since 1.9
+ *
+ * @author Sergey A. Malenkov
+ */
+@Documented
+@Target({METHOD})
+@Retention(RUNTIME)
+public @interface BeanProperty {
+ /**
+ * The value that indicates whether the annotated property can be
+ * a {@link PropertyDescriptor#isBound bound} property or not.
+ * This value applies only to the beans that have the
+ * {@link PropertyChangeListener propertyChange} event set.
+ *
+ * @return {@code true} if the annotated property can be a bound property;
+ * {@code false} otherwise.
+ */
+ boolean bound() default true;
+
+ /**
+ * The value that indicates whether the annotated property is
+ * an {@link PropertyDescriptor#isExpert expert} property or not.
+ *
+ * @return {@code true} if the annotated property is an expert property;
+ * {@code false} otherwise.
+ */
+ boolean expert() default false;
+
+ /**
+ * The value that indicates whether the annotated property is
+ * a {@link PropertyDescriptor#isHidden hidden} property or not.
+ *
+ * @return {@code true} if the annotated property is a hidden property;
+ * {@code false} otherwise.
+ */
+ boolean hidden() default false;
+
+ /**
+ * The value that indicates whether the annotated property is
+ * a {@link PropertyDescriptor#isPreferred preferred} property or not.
+ *
+ * @return {@code true} if the annotated property is a preferred property;
+ * {@code false} otherwise.
+ */
+ boolean preferred() default false;
+
+ /**
+ * The value that indicates whether the annotated property is
+ * a required property or not.
+ *
+ * @return {@code true} if the annotated property is a required property;
+ * {@code false} otherwise.
+ */
+ boolean required() default false;
+
+ /**
+ * The value that indicates whether the corresponding component
+ * is repainted after the annotated property got changed or not.
+ *
+ * @return {@code true} if the corresponding component is repainted;
+ * {@code false} otherwise.
+ */
+ boolean visualUpdate() default false;
+
+ /**
+ * The {@link PropertyDescriptor#getShortDescription short description}
+ * for the {@link BeanInfo#getPropertyDescriptors descriptor}
+ * of the annotated property.
+ *
+ * @return the property description,
+ * or an empty string if the description is not set.
+ */
+ String description() default "";
+
+ /**
+ * The array of names for the public static fields
+ * that contains the valid values of the annotated property.
+ * These names are used to generate the {@code enumerationValues}
+ * {@link java.beans.BeanDescriptor#getValue feature attribute}
+ * that must contain the following items per each property value:
+ * a displayable name for the property value, the actual property value,
+ * and a Java code piece used for the code generator.
+ *
+ * @return the names of the valid values of the annotated property,
+ * or an empty array if the names are not provided.
+ */
+ String[] enumerationValues() default {};
+}
--- a/jdk/src/share/classes/java/beans/EventSetDescriptor.java Wed Jul 02 23:03:27 2014 -0700
+++ b/jdk/src/share/classes/java/beans/EventSetDescriptor.java Thu Jul 03 16:55:55 2014 +0400
@@ -22,13 +22,14 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package java.beans;
import java.lang.ref.Reference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import com.sun.beans.introspect.EventSetInfo;
+
/**
* An EventSetDescriptor describes a group of events that a given Java
* bean fires.
@@ -255,6 +256,16 @@
setListenerType(listenerType);
}
+ EventSetDescriptor(String base, EventSetInfo info, Method... methods) {
+ setName(Introspector.decapitalize(base));
+ setListenerMethods(methods);
+ setAddListenerMethod(info.getAddMethod());
+ setRemoveListenerMethod(info.getRemoveMethod());
+ setGetListenerMethod(info.getGetMethod());
+ setListenerType(info.getListenerType());
+ setUnicast(info.isUnicast());
+ }
+
/**
* Creates an <TT>EventSetDescriptor</TT> from scratch using
* <TT>java.lang.reflect.MethodDescriptor</TT> and <TT>java.lang.Class</TT>
--- a/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java Wed Jul 02 23:03:27 2014 -0700
+++ b/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java Thu Jul 03 16:55:55 2014 +0400
@@ -22,11 +22,13 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package java.beans;
import java.lang.ref.Reference;
import java.lang.reflect.Method;
+import java.util.Map.Entry;
+
+import com.sun.beans.introspect.PropertyInfo;
/**
* An IndexedPropertyDescriptor describes a property that acts like an
@@ -143,27 +145,21 @@
}
/**
- * Creates <code>PropertyDescriptor</code> for the specified bean
- * with the specified name and methods to read/write the property value.
+ * Creates {@code IndexedPropertyDescriptor} from the specified property info.
*
- * @param bean the type of the target bean
- * @param base the base name of the property (the rest of the method name)
- * @param read the method used for reading the property value
- * @param write the method used for writing the property value
- * @param readIndexed the method used for reading an indexed property value
- * @param writeIndexed the method used for writing an indexed property value
- * @exception IntrospectionException if an exception occurs during introspection
+ * @param entry the key-value pair,
+ * where the {@code key} is the base name of the property (the rest of the method name)
+ * and the {@code value} is the automatically generated property info
+ * @param bound the flag indicating whether it is possible to treat this property as a bound property
*
- * @since 1.7
+ * @since 1.9
*/
- IndexedPropertyDescriptor(Class<?> bean, String base, Method read, Method write, Method readIndexed, Method writeIndexed) throws IntrospectionException {
- super(bean, base, read, write);
-
- setIndexedReadMethod0(readIndexed);
- setIndexedWriteMethod0(writeIndexed);
-
- // Type checking
- setIndexedPropertyType(findIndexedPropertyType(readIndexed, writeIndexed));
+ IndexedPropertyDescriptor(Entry<String,PropertyInfo> entry, boolean bound) {
+ super(entry, bound);
+ PropertyInfo info = entry.getValue().getIndexed();
+ setIndexedReadMethod0(info.getReadMethod());
+ setIndexedWriteMethod0(info.getWriteMethod());
+ setIndexedPropertyType(info.getPropertyType());
}
/**
--- a/jdk/src/share/classes/java/beans/Introspector.java Wed Jul 02 23:03:27 2014 -0700
+++ b/jdk/src/share/classes/java/beans/Introspector.java Thu Jul 03 16:55:55 2014 +0400
@@ -22,32 +22,30 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package java.beans;
import com.sun.beans.TypeResolver;
import com.sun.beans.WeakCache;
import com.sun.beans.finder.ClassFinder;
-import com.sun.beans.finder.MethodFinder;
+import com.sun.beans.introspect.ClassInfo;
+import com.sun.beans.introspect.EventSetInfo;
+import com.sun.beans.introspect.PropertyInfo;
import java.awt.Component;
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;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import java.util.TreeMap;
-import sun.misc.JavaBeansIntrospectorAccess;
import sun.misc.SharedSecrets;
import sun.reflect.misc.ReflectUtil;
@@ -122,7 +120,6 @@
private BeanInfo additionalBeanInfo[];
private boolean propertyChangeSource = false;
- private static Class<EventListener> eventListenerType = EventListener.class;
// These should be removed.
private String defaultEventName;
@@ -501,78 +498,15 @@
addPropertyDescriptors(explicitProperties);
} else {
-
// Apply some reflection to the current class.
-
- // First get an array of all the public methods at this level
- Method methodList[] = getPublicDeclaredMethods(beanClass);
-
- // Now analyze each method.
- for (int i = 0; i < methodList.length; i++) {
- Method method = methodList[i];
- if (method == null) {
- continue;
- }
- // skip static methods.
- int mods = method.getModifiers();
- if (Modifier.isStatic(mods)) {
- continue;
- }
- String name = method.getName();
- Class<?>[] argTypes = method.getParameterTypes();
- Class<?> resultType = method.getReturnType();
- int argCount = argTypes.length;
- PropertyDescriptor pd = null;
-
- if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
- // Optimization. Don't bother with invalid propertyNames.
- continue;
- }
-
- try {
-
- if (argCount == 0) {
- if (name.startsWith(GET_PREFIX)) {
- // Simple getter
- pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);
- } else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {
- // Boolean getter
- pd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);
- }
- } else if (argCount == 1) {
- if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
- pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
- } else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
- // Simple setter
- pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
- if (throwsException(method, PropertyVetoException.class)) {
- pd.setConstrained(true);
- }
- }
- } else if (argCount == 2) {
- if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {
- pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);
- if (throwsException(method, PropertyVetoException.class)) {
- pd.setConstrained(true);
- }
- }
- }
- } catch (IntrospectionException ex) {
- // This happens if a PropertyDescriptor or IndexedPropertyDescriptor
- // constructor fins that the method violates details of the deisgn
- // pattern, e.g. by having an empty name, or a getter returning
- // void , or whatever.
- pd = null;
- }
-
- if (pd != null) {
- // If this class or one of its base classes is a PropertyChange
- // source, then we assume that any properties we discover are "bound".
- if (propertyChangeSource) {
- pd.setBound(true);
- }
- addPropertyDescriptor(pd);
- }
+ for (Map.Entry<String,PropertyInfo> entry : ClassInfo.get(this.beanClass).getProperties().entrySet()) {
+ addPropertyDescriptor(null != entry.getValue().getIndexed()
+ ? new IndexedPropertyDescriptor(entry, this.propertyChangeSource)
+ : new PropertyDescriptor(entry, this.propertyChangeSource));
+ }
+ JavaBean annotation = this.beanClass.getAnnotation(JavaBean.class);
+ if ((annotation != null) && !annotation.defaultProperty().isEmpty()) {
+ this.defaultPropertyName = annotation.defaultProperty();
}
}
processPropertyDescriptors();
@@ -589,7 +523,6 @@
}
}
}
-
return result;
}
@@ -1003,143 +936,24 @@
}
} else {
-
// Apply some reflection to the current class.
-
- // Get an array of all the public beans methods at this level
- Method methodList[] = getPublicDeclaredMethods(beanClass);
-
- // Find all suitable "add", "remove" and "get" Listener methods
- // The name of the listener type is the key for these hashtables
- // i.e, ActionListener
- Map<String, Method> adds = null;
- Map<String, Method> removes = null;
- Map<String, Method> gets = null;
-
- for (int i = 0; i < methodList.length; i++) {
- Method method = methodList[i];
- if (method == null) {
- continue;
- }
- // skip static methods.
- int mods = method.getModifiers();
- if (Modifier.isStatic(mods)) {
- continue;
- }
- String name = method.getName();
- // Optimization avoid getParameterTypes
- if (!name.startsWith(ADD_PREFIX) && !name.startsWith(REMOVE_PREFIX)
- && !name.startsWith(GET_PREFIX)) {
- continue;
- }
-
- 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);
- }
- }
- }
- }
- }
- 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);
- }
- }
- }
+ for (Map.Entry<String,EventSetInfo> entry : ClassInfo.get(this.beanClass).getEventSets().entrySet()) {
+ // generate a list of Method objects for each of the target methods:
+ List<Method> methods = new ArrayList<>();
+ for (Method method : ClassInfo.get(entry.getValue().getListenerType()).getMethods()) {
+ if (isEventHandler(method)) {
+ methods.add(method);
}
}
- 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);
- }
- }
- }
- }
- }
+ addEvent(new EventSetDescriptor(
+ entry.getKey(),
+ entry.getValue(),
+ methods.toArray(new Method[methods.size()])));
}
-
- if (adds != null && removes != null) {
- // Now look for matching addFooListener+removeFooListener pairs.
- // Bonus if there is a matching getFooListeners method as well.
- Iterator<String> keys = adds.keySet().iterator();
- while (keys.hasNext()) {
- String listenerName = keys.next();
- // Skip any "add" which doesn't have a matching "remove" or
- // a listener name that doesn't end with Listener
- if (removes.get(listenerName) == null || !listenerName.endsWith("Listener")) {
- continue;
- }
- String eventName = decapitalize(listenerName.substring(0, listenerName.length()-8));
- Method addMethod = adds.get(listenerName);
- Method removeMethod = removes.get(listenerName);
- Method getMethod = null;
- if (gets != null) {
- getMethod = gets.get(listenerName);
- }
- Class<?> argType = FeatureDescriptor.getParameterTypes(beanClass, addMethod)[0];
-
- // generate a list of Method objects for each of the target methods:
- Method allMethods[] = getPublicDeclaredMethods(argType);
- List<Method> validMethods = new ArrayList<>(allMethods.length);
- for (int i = 0; i < allMethods.length; i++) {
- if (allMethods[i] == null) {
- continue;
- }
-
- if (isEventHandler(allMethods[i])) {
- validMethods.add(allMethods[i]);
- }
- }
- Method[] methods = validMethods.toArray(new Method[validMethods.size()]);
-
- EventSetDescriptor esd = new EventSetDescriptor(eventName, argType,
- methods, addMethod,
- removeMethod,
- getMethod);
-
- // If the adder method throws the TooManyListenersException then it
- // is a Unicast event source.
- if (throwsException(addMethod,
- java.util.TooManyListenersException.class)) {
- esd.setUnicast(true);
- }
- addEvent(esd);
- }
- } // if (adds != null ...
+ JavaBean annotation = this.beanClass.getAnnotation(JavaBean.class);
+ if ((annotation != null) && !annotation.defaultEventSet().isEmpty()) {
+ this.defaultEventName = annotation.defaultEventSet();
+ }
}
EventSetDescriptor[] result;
if (events.size() == 0) {
@@ -1148,7 +962,6 @@
// Allocate and populate the result array.
result = new EventSetDescriptor[events.size()];
result = events.values().toArray(result);
-
// Set the default index.
if (defaultEventName != null) {
for (int i = 0; i < result.length; i++) {
@@ -1215,20 +1028,9 @@
}
} else {
-
// Apply some reflection to the current class.
-
- // First get an array of all the beans methods at this level
- Method methodList[] = getPublicDeclaredMethods(beanClass);
-
- // Now analyze each method.
- for (int i = 0; i < methodList.length; i++) {
- Method method = methodList[i];
- if (method == null) {
- continue;
- }
- MethodDescriptor md = new MethodDescriptor(method);
- addMethod(md);
+ for (Method method : ClassInfo.get(this.beanClass).getMethods()) {
+ addMethod(new MethodDescriptor(method));
}
}
@@ -1346,44 +1148,6 @@
return isSubclass(TypeResolver.erase(TypeResolver.resolveInClass(beanClass, argTypes[0])), EventObject.class);
}
- /*
- * Internal method to return *public* methods within a class.
- */
- private static Method[] getPublicDeclaredMethods(Class<?> clz) {
- // Looking up Class.getDeclaredMethods is relatively expensive,
- // so we cache the results.
- if (!ReflectUtil.isPackageAccessible(clz)) {
- return new Method[0];
- }
- synchronized (declaredMethodCache) {
- Method[] result = declaredMethodCache.get(clz);
- if (result == null) {
- result = clz.getMethods();
- for (int i = 0; i < result.length; i++) {
- Method method = result[i];
- if (!method.getDeclaringClass().equals(clz)) {
- result[i] = null; // ignore methods declared elsewhere
- }
- else {
- try {
- method = MethodFinder.findAccessibleMethod(method);
- Class<?> type = method.getDeclaringClass();
- result[i] = type.equals(clz) || type.isInterface()
- ? method
- : null; // ignore methods from superclasses
- }
- catch (NoSuchMethodException exception) {
- // commented out because of 6976577
- // result[i] = null; // ignore inaccessible methods
- }
- }
- }
- declaredMethodCache.put(clz, result);
- }
- return result;
- }
- }
-
//======================================================================
// Package private support methods.
//======================================================================
@@ -1396,17 +1160,8 @@
int argCount, Class<?> args[]) {
// For overriden methods we need to find the most derived version.
// So we start with the given class and walk up the superclass chain.
-
- Method method = null;
-
for (Class<?> cl = start; cl != null; cl = cl.getSuperclass()) {
- Method methods[] = getPublicDeclaredMethods(cl);
- for (int i = 0; i < methods.length; i++) {
- method = methods[i];
- if (method == null) {
- continue;
- }
-
+ for (Method method : ClassInfo.get(cl).getMethods()) {
// make sure method signature matches.
if (method.getName().equals(methodName)) {
Type[] params = method.getGenericParameterTypes();
@@ -1430,8 +1185,6 @@
}
}
}
- method = null;
-
// Now check any inherited interfaces. This is necessary both when
// the argument class is itself an interface, and when the argument
// class is an abstract class.
@@ -1440,12 +1193,12 @@
// Note: The original implementation had both methods calling
// the 3 arg method. This is preserved but perhaps it should
// pass the args array instead of null.
- method = internalFindMethod(ifcs[i], methodName, argCount, null);
+ Method method = internalFindMethod(ifcs[i], methodName, argCount, null);
if (method != null) {
- break;
+ return method;
}
}
- return method;
+ return null;
}
/**
@@ -1508,19 +1261,6 @@
}
/**
- * Return true iff the given method throws the given exception.
- */
- private boolean throwsException(Method method, Class<?> exception) {
- Class<?>[] exs = method.getExceptionTypes();
- for (int i = 0; i < exs.length; i++) {
- if (exs[i] == exception) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Try to create an instance of a named class.
* First try the classloader of "sibling", then try the system
* classloader then the class loader of the current Thread.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/beans/JavaBean.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package java.beans;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * An annotation used to specify some class-related information
+ * for the automatically generated {@link BeanInfo} classes.
+ * This annotation is not used if the annotated class
+ * has a corresponding user-defined {@code BeanInfo} class,
+ * which does not imply the automatic analysis.
+ *
+ * @see BeanInfo#getBeanDescriptor
+ * @since 1.9
+ *
+ * @author Sergey A. Malenkov
+ */
+@Documented
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface JavaBean {
+ /**
+ * The {@link BeanDescriptor#getShortDescription short description}
+ * for the {@link BeanInfo#getBeanDescriptor bean descriptor}
+ * of the annotated class.
+ *
+ * @return the bean description,
+ * or an empty string if the description is not set.
+ */
+ String description() default "";
+
+ /**
+ * The name of the default property is used to calculate its
+ * {@link BeanInfo#getDefaultPropertyIndex index} in the
+ * {@link BeanInfo#getPropertyDescriptors array} of properties
+ * defined in the annotated class. If the name is not set or
+ * the annotated class does not define a property
+ * with the specified name, the default property index
+ * will be calculated automatically by the
+ * {@link Introspector} depending on its state.
+ *
+ * @return the name of the default property,
+ * or an empty string if the name is not set.
+ */
+ String defaultProperty() default "";
+
+ /**
+ * The name of the default event set is used to calculate its
+ * {@link BeanInfo#getDefaultEventIndex index} in the
+ * {@link BeanInfo#getEventSetDescriptors array} of event sets
+ * defined in the annotated class. If the name is not set or
+ * the annotated class does not define an event set
+ * with the specified name, the default event set index
+ * will be calculated automatically by the
+ * {@link Introspector} depending on its state.
+ *
+ * @return the name of the default event set,
+ * or an empty string if the name is not set.
+ */
+ String defaultEventSet() default "";
+}
--- a/jdk/src/share/classes/java/beans/PropertyDescriptor.java Wed Jul 02 23:03:27 2014 -0700
+++ b/jdk/src/share/classes/java/beans/PropertyDescriptor.java Thu Jul 03 16:55:55 2014 +0400
@@ -22,12 +22,14 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package java.beans;
import java.lang.ref.Reference;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
+import java.util.Map.Entry;
+
+import com.sun.beans.introspect.PropertyInfo;
/**
* A PropertyDescriptor describes one property that a Java Bean
@@ -140,25 +142,47 @@
}
/**
- * Creates <code>PropertyDescriptor</code> for the specified bean
- * with the specified name and methods to read/write the property value.
+ * Creates {@code PropertyDescriptor} from the specified property info.
*
- * @param bean the type of the target bean
- * @param base the base name of the property (the rest of the method name)
- * @param read the method used for reading the property value
- * @param write the method used for writing the property value
- * @exception IntrospectionException if an exception occurs during introspection
+ * @param entry the pair of values,
+ * where the {@code key} is the base name of the property (the rest of the method name)
+ * and the {@code value} is the automatically generated property info
+ * @param bound the flag indicating whether it is possible to treat this property as a bound property
*
- * @since 1.7
+ * @since 1.9
*/
- PropertyDescriptor(Class<?> bean, String base, Method read, Method write) throws IntrospectionException {
- if (bean == null) {
- throw new IntrospectionException("Target Bean class is null");
+ PropertyDescriptor(Entry<String,PropertyInfo> entry, boolean bound) {
+ String base = entry.getKey();
+ PropertyInfo info = entry.getValue();
+ setName(Introspector.decapitalize(base));
+ setReadMethod0(info.getReadMethod());
+ setWriteMethod0(info.getWriteMethod());
+ setPropertyType(info.getPropertyType());
+ setConstrained(info.isConstrained());
+ setBound(bound && info.is(PropertyInfo.Name.bound));
+ if (info.is(PropertyInfo.Name.expert)) {
+ setValue(PropertyInfo.Name.expert.name(), Boolean.TRUE); // compatibility
+ setExpert(true);
}
- setClass0(bean);
- setName(Introspector.decapitalize(base));
- setReadMethod(read);
- setWriteMethod(write);
+ if (info.is(PropertyInfo.Name.hidden)) {
+ setValue(PropertyInfo.Name.hidden.name(), Boolean.TRUE); // compatibility
+ setHidden(true);
+ }
+ if (info.is(PropertyInfo.Name.preferred)) {
+ setPreferred(true);
+ }
+ Object visual = info.get(PropertyInfo.Name.visualUpdate);
+ if (visual != null) {
+ setValue(PropertyInfo.Name.visualUpdate.name(), visual);
+ }
+ Object description = info.get(PropertyInfo.Name.description);
+ if (description != null) {
+ setShortDescription(description.toString());
+ }
+ Object values = info.get(PropertyInfo.Name.enumerationValues);
+ if (values != null) {
+ setValue(PropertyInfo.Name.enumerationValues.name(), values);
+ }
this.baseName = base;
}
@@ -249,13 +273,17 @@
*/
public synchronized void setReadMethod(Method readMethod)
throws IntrospectionException {
+ // The property type is determined by the read method.
+ setPropertyType(findPropertyType(readMethod, this.writeMethodRef.get()));
+ setReadMethod0(readMethod);
+ }
+
+ private void setReadMethod0(Method readMethod) {
this.readMethodRef.set(readMethod);
if (readMethod == null) {
readMethodName = null;
return;
}
- // The property type is determined by the read method.
- setPropertyType(findPropertyType(readMethod, this.writeMethodRef.get()));
setClass0(readMethod.getDeclaringClass());
readMethodName = readMethod.getName();
@@ -320,13 +348,17 @@
*/
public synchronized void setWriteMethod(Method writeMethod)
throws IntrospectionException {
+ // Set the property type - which validates the method
+ setPropertyType(findPropertyType(getReadMethod(), writeMethod));
+ setWriteMethod0(writeMethod);
+ }
+
+ private void setWriteMethod0(Method writeMethod) {
this.writeMethodRef.set(writeMethod);
if (writeMethod == null) {
writeMethodName = null;
return;
}
- // Set the property type - which validates the method
- setPropertyType(findPropertyType(getReadMethod(), writeMethod));
setClass0(writeMethod.getDeclaringClass());
writeMethodName = writeMethod.getName();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/swing/SwingContainer.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package javax.swing;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * An annotation used to specify some swing-related information
+ * for the automatically generated {@code BeanInfo} classes.
+ * This annotation is not used if the annotated class
+ * has a corresponding user-defined {@code BeanInfo} class,
+ * which does not imply the automatic analysis.
+ * <p>
+ * The {@code isContainer} {@link java.beans.BeanDescriptor#getValue
+ * feature attribute} was introduced primarily for the Swing library.
+ * All Swing components extend the {@link java.awt.Container Container}
+ * class by design, so the builder tool assumes that all Swing components
+ * are containers. The {@link java.beans.BeanInfo BeanInfo} classes
+ * with the {@code isContainer} attribute allow to directly specify
+ * whether a Swing component is a container or not.
+ *
+ * @since 1.9
+ *
+ * @author Sergey A. Malenkov
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface SwingContainer {
+ /**
+ * The value that indicates whether the annotated class can be used
+ * as a container for other Swing components or not.
+ *
+ * @return {@code true} if the annotated class is a Swing container;
+ * {@code false} otherwise.
+ */
+ boolean value() default true;
+
+ /**
+ * The name of the getter method in the annotated class,
+ * which returns the corresponding Swing container,
+ * if it is not recommended to add subcomponents
+ * to the annotated class directly.
+ *
+ * @return the name of the getter method in the annotated class,
+ * which returns the corresponding Swing container,
+ * or an empty string if the method name is not set.
+ */
+ String delegate() default "";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/4058433/TestBeanProperty.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+import java.beans.BeanProperty;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyDescriptor;
+import java.util.Arrays;
+/*
+ * @test
+ * @bug 4058433
+ * @summary Tests the BeanProperty annotation
+ * @author Sergey Malenkov
+ * @library ..
+ */
+public class TestBeanProperty {
+ public static void main(String[] args) throws Exception {
+ Class<?>[] types = {B.class, BL.class, BLF.class, E.class, H.class, P.class, VU.class, D.class, EV.class, EVL.class, EVX.class};
+ for (Class<?> type : types) {
+ PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(type, "value");
+ if (((B.class == type) || (BLF.class == type)) && pd.isBound()) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("not bound");
+ }
+ if ((BL.class == type) == !pd.isBound()) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("bound");
+ }
+ if ((E.class == type) == !pd.isExpert()) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("expert");
+ }
+ if ((H.class == type) == !pd.isHidden()) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("hidden");
+ }
+ if ((P.class == type) == !pd.isPreferred()) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("preferred");
+ }
+ if ((R.class == type) == !Boolean.TRUE.equals(pd.getValue("required"))) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("required");
+ }
+ if ((VU.class == type) == !Boolean.TRUE.equals(pd.getValue("visualUpdate"))) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("visualUpdate");
+ }
+ if ((EV.class == type) == !isEV(pd, "LEFT", 2, "javax.swing.SwingConstants.LEFT", "RIGHT", 4, "javax.swing.SwingConstants.RIGHT")) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("enumerationValues from another package");
+ }
+ if ((EVL.class == type) == !isEV(pd, "ZERO", 0, "ZERO", "ONE", 1, "ONE")) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("enumerationValues from another package");
+ }
+ if ((EVX.class == type) == !isEV(pd, "ZERO", 0, "X.ZERO", "ONE", 1, "X.ONE")) {
+ BeanUtils.reportPropertyDescriptor(pd);
+ throw new Error("enumerationValues from another package");
+ }
+ }
+ }
+
+ private static boolean isEV(PropertyDescriptor pd, Object... expected) {
+ Object value = pd.getValue("enumerationValues");
+ return value instanceof Object[] && Arrays.equals((Object[]) value, expected);
+ }
+
+ public static class B {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class BL {
+ private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ this.pcs.addPropertyChangeListener(listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ this.pcs.removePropertyChangeListener(listener);
+ }
+ }
+
+ public static class BLF {
+ private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(bound = false)
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ this.pcs.addPropertyChangeListener(listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ this.pcs.removePropertyChangeListener(listener);
+ }
+ }
+
+ public static class E {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(expert = true)
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class H {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(hidden = true)
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class P {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(preferred = true)
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class R {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(required = true)
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class VU {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(visualUpdate = true)
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class D {
+ private int value;
+
+ @BeanProperty(description = "getter")
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(description = "setter")
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class EV {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(enumerationValues = {
+ "javax.swing.SwingConstants.LEFT",
+ "javax.swing.SwingConstants.RIGHT"})
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class EVL {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(enumerationValues = {"ZERO", "ONE"})
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public static int ZERO = 0;
+ public static int ONE = 1;
+ }
+
+ public static class EVX {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ @BeanProperty(enumerationValues = {
+ "X.ZERO",
+ "X.ONE"})
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static interface X {
+ int ZERO = 0;
+ int ONE = 1;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/4058433/TestJavaBean.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+import java.awt.event.ActionListener;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.JavaBean;
+/*
+ * @test
+ * @bug 4058433
+ * @summary Tests the JavaBean annotation
+ * @author Sergey Malenkov
+ */
+public class TestJavaBean {
+ public static void main(String[] args) throws Exception {
+ test(X.class);
+ test(D.class);
+ test(DP.class);
+ test(DES.class);
+ }
+
+ private static void test(Class<?> type) throws Exception {
+ System.out.println(type);
+ BeanInfo info = Introspector.getBeanInfo(type);
+ BeanDescriptor bd = info.getBeanDescriptor();
+
+ String description = bd.getShortDescription();
+ System.out.println("description = " + description);
+
+ int dp = info.getDefaultPropertyIndex();
+ System.out.println("property index = " + dp);
+ if (0 <= dp) {
+ String name = info.getPropertyDescriptors()[dp].getName();
+ System.out.println("property name = " + name);
+ }
+ int des = info.getDefaultEventIndex();
+ System.out.println("event set index = " + des);
+ if (0 <= des) {
+ String name = info.getPropertyDescriptors()[des].getName();
+ System.out.println("event set name = " + name);
+ }
+
+ if ((D.class == type) == bd.getName().equals(description)) {
+ throw new Error("unexpected description of the bean");
+ }
+ if ((DP.class == type) == (dp < 0)) {
+ throw new Error("unexpected index of the default property");
+ }
+ if ((DES.class == type) == (des < 0)) {
+ throw new Error("unexpected index of the default event set");
+ }
+ }
+
+ public static class X {
+ }
+
+ @JavaBean(description = "description")
+ public static class D {
+ }
+
+ @JavaBean(defaultProperty = "value")
+ public static class DP {
+ private int value;
+
+ public int getValue() {
+ return this.value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ @JavaBean(defaultEventSet = "action")
+ public static class DES {
+ public void addActionListener(ActionListener listener) {
+ }
+
+ public void removeActionListener(ActionListener listener) {
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/4058433/TestSwingContainer.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.util.Objects;
+import javax.swing.SwingContainer;
+/*
+ * @test
+ * @bug 4058433
+ * @summary Tests the SwingContainer annotation
+ * @author Sergey Malenkov
+ */
+public class TestSwingContainer {
+ public static void main(String[] args) throws Exception {
+ test(X.class, null, null);
+ test(T.class, true, null);
+ test(D.class, true, "method");
+ test(F.class, false, null);
+ test(A.class, false, "method");
+ }
+
+ private static void test(Class<?> type, Object iC, Object cD) throws Exception {
+ System.out.println(type);
+ BeanInfo info = Introspector.getBeanInfo(type);
+ BeanDescriptor bd = info.getBeanDescriptor();
+ test(bd, "isContainer", iC);
+ test(bd, "containerDelegate", cD);
+ }
+
+ private static void test(BeanDescriptor bd, String name, Object expected) {
+ Object value = bd.getValue(name);
+ System.out.println(name + " = " + value);
+ if (!Objects.equals(value, expected)) {
+ throw new Error(name + ": expected = " + expected + "; actual = " + value);
+ }
+ }
+
+ public static class X {
+ }
+
+ @SwingContainer()
+ public static class T {
+ }
+
+ @SwingContainer(delegate = "method")
+ public static class D {
+ }
+
+ @SwingContainer(false)
+ public static class F {
+ }
+
+ @SwingContainer(value = false, delegate = "method")
+ public static class A {
+ }
+}
--- a/jdk/test/java/beans/Introspector/7084904/Test7084904.java Wed Jul 02 23:03:27 2014 -0700
+++ b/jdk/test/java/beans/Introspector/7084904/Test7084904.java Thu Jul 03 16:55:55 2014 +0400
@@ -27,6 +27,7 @@
* @bug 7084904
* @summary Compares reflection and bean introspection
* @author Sergey Malenkov
+ * @library ..
*/
public class Test7084904 {
public static void main(String[] args) throws Exception {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Performance/Test4058433.java Thu Jul 03 16:55:55 2014 +0400
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import java.awt.Image;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.beans.EventSetDescriptor;
+import java.beans.FeatureDescriptor;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.Introspector;
+import java.beans.MethodDescriptor;
+import java.beans.ParameterDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/*
+ * @test
+ * @bug 4058433
+ * @summary Generates BeanInfo for public classes in AWT, Accessibility, and Swing
+ * @author Sergey Malenkov
+ * @run main/manual Test4058433
+ */
+
+public class Test4058433 implements Comparator<Object> {
+ @Override
+ public int compare(Object one, Object two) {
+ if (one instanceof Method && two instanceof Method) {
+ Method oneMethod = (Method) one;
+ Method twoMethod = (Method) two;
+ int result = oneMethod.getName().compareTo(twoMethod.getName());
+ if (result != 0) {
+ return result;
+ }
+ }
+ if (one instanceof FeatureDescriptor && two instanceof FeatureDescriptor) {
+ FeatureDescriptor oneFD = (FeatureDescriptor) one;
+ FeatureDescriptor twoFD = (FeatureDescriptor) two;
+ int result = oneFD.getName().compareTo(twoFD.getName());
+ if (result != 0) {
+ return result;
+ }
+ }
+ return one.toString().compareTo(two.toString());
+ }
+
+ public static void main(String[] args) throws Exception {
+ String resource = ClassLoader.getSystemResource("java/lang/Object.class").toString();
+
+ Pattern pattern = Pattern.compile("jar:file:(.*)!.*");
+ Matcher matcher = pattern.matcher(resource);
+ matcher.matches();
+ resource = matcher.group(1);
+
+ TreeSet<Class<?>> types = new TreeSet<>(new Test4058433());
+ try (JarFile jarFile = new JarFile(resource.replaceAll("%20", " "))) {
+ Enumeration<JarEntry> entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ String name = entries.nextElement().getName();
+ if (name.startsWith("java/awt/") || name.startsWith("javax/accessibility/") || name.startsWith("javax/swing/")) {
+ if (name.endsWith(".class")) {
+ name = name.substring(0, name.indexOf(".")).replace('/', '.');
+ Class<?> type = Class.forName(name);
+ if (!type.isInterface() && !type.isEnum() && !type.isAnnotation() && !type.isAnonymousClass()) {
+ if (null == type.getDeclaringClass()) {
+ types.add(type);
+ }
+ }
+ }
+ }
+ }
+ }
+ System.out.println("found " + types.size() + " classes");
+ long time = -System.currentTimeMillis();
+ for (Class<?> type : types) {
+ System.out.println("========================================");
+ BeanInfo info = Introspector.getBeanInfo(type);
+
+ BeanDescriptor bd = info.getBeanDescriptor();
+ System.out.println(bd.getBeanClass());
+ print("customizer", bd.getCustomizerClass());
+ print(bd);
+ print("mono 16x16", info.getIcon(BeanInfo.ICON_MONO_16x16));
+ print("mono 32x32", info.getIcon(BeanInfo.ICON_MONO_32x32));
+ print("color 16x16", info.getIcon(BeanInfo.ICON_COLOR_16x16));
+ print("color 32x32", info.getIcon(BeanInfo.ICON_COLOR_32x32));
+
+ PropertyDescriptor[] pds = info.getPropertyDescriptors();
+ PropertyDescriptor dpd = getDefault(pds, info.getDefaultPropertyIndex());
+ System.out.println(pds.length + " property descriptors");
+ Arrays.sort(pds, new Test4058433());
+ for (PropertyDescriptor pd : pds) {
+ print(pd);
+ if (dpd == pd) {
+ System.out.println("default property");
+ }
+ print("bound", pd.isBound());
+ print("constrained", pd.isConstrained());
+ print("property editor", pd.getPropertyEditorClass());
+ print("property type", pd.getPropertyType());
+ print("read method", pd.getReadMethod());
+ print("write method", pd.getWriteMethod());
+ if (pd instanceof IndexedPropertyDescriptor) {
+ IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
+ print("indexed property type", ipd.getIndexedPropertyType());
+ print("indexed read method", ipd.getIndexedReadMethod());
+ print("indexed write method", ipd.getIndexedWriteMethod());
+ }
+ }
+ EventSetDescriptor[] esds = info.getEventSetDescriptors();
+ EventSetDescriptor desd = getDefault(esds, info.getDefaultEventIndex());
+ System.out.println(esds.length + " event set descriptors");
+ Arrays.sort(esds, new Test4058433());
+ for (EventSetDescriptor esd : esds) {
+ print(esd);
+ if (desd == esd) {
+ System.out.println("default event set");
+ }
+ print("in default", esd.isInDefaultEventSet());
+ print("unicast", esd.isUnicast());
+ print("listener type", esd.getListenerType());
+ print("get listener method", esd.getGetListenerMethod());
+ print("add listener method", esd.getAddListenerMethod());
+ print("remove listener method", esd.getRemoveListenerMethod());
+ Method[] methods = esd.getListenerMethods();
+ Arrays.sort(methods, new Test4058433());
+ for (Method method : methods) {
+ print("listener method", method);
+ }
+ print(esd.getListenerMethodDescriptors());
+ }
+ print(info.getMethodDescriptors());
+ }
+ time += System.currentTimeMillis();
+ System.out.println("DONE IN " + time + " MS");
+ }
+
+ private static <T> T getDefault(T[] array, int index) {
+ return (index == -1) ? null : array[index];
+ }
+
+ private static void print(MethodDescriptor[] mds) {
+ System.out.println(mds.length + " method descriptors");
+ Arrays.sort(mds, new Test4058433());
+ for (MethodDescriptor md : mds) {
+ print(md);
+ print("method", md.getMethod());
+ ParameterDescriptor[] pds = md.getParameterDescriptors();
+ if (pds != null) {
+ System.out.println(pds.length + " parameter descriptors");
+ for (ParameterDescriptor pd : pds) {
+ print(pd);
+ }
+ }
+ }
+ }
+
+ private static void print(FeatureDescriptor descriptor) {
+ String name = descriptor.getName();
+ String display = descriptor.getDisplayName();
+ String description = descriptor.getShortDescription();
+ System.out.println("name: " + name);
+ if (!Objects.equals(name, display)) {
+ System.out.println("display name: " + display);
+ }
+ if (!Objects.equals(display, description)) {
+ System.out.println("description: " + description.trim());
+ }
+ print("expert", descriptor.isExpert());
+ print("hidden", descriptor.isHidden());
+ print("preferred", descriptor.isPreferred());
+ TreeMap<String,Object> map = new TreeMap<>();
+ Enumeration<String> enumeration = descriptor.attributeNames();
+ while (enumeration.hasMoreElements()) {
+ String id = enumeration.nextElement();
+ Object value = descriptor.getValue(id);
+ if (value.getClass().isArray()) {
+ TreeSet<String> set = new TreeSet<>();
+ int index = 0;
+ int length = Array.getLength(value);
+ while (index < length) {
+ set.add(Array.get(value, index++) + ", " +
+ Array.get(value, index++) + ", " +
+ Array.get(value, index++));
+ }
+ value = set.toString();
+ }
+ map.put(id, value);
+ }
+ for (Entry<String,Object> entry : map.entrySet()) {
+ System.out.println(entry.getKey() + ": " + entry.getValue());
+ }
+ }
+
+ private static void print(String id, boolean flag) {
+ if (flag) {
+ System.out.println(id + " is set");
+ }
+ }
+
+ private static void print(String id, Class<?> type) {
+ if (type != null) {
+ System.out.println(id + ": " + type.getName());
+ }
+ }
+
+ private static void print(String id, Method method) {
+ if (method != null) {
+ System.out.println(id + ": " + method);
+ }
+ }
+
+ private static void print(String name, Image image) {
+ if (image != null) {
+ System.out.println(name + " icon is exist");
+ }
+ }
+}