8038343: Eliminate use of reflection to access JavaBeans Introspector
authoralanb
Wed, 26 Mar 2014 12:25:09 +0000
changeset 23581 0ca496340112
parent 23580 1055a611c69b
child 23582 d5fa3327ab3a
8038343: Eliminate use of reflection to access JavaBeans Introspector Reviewed-by: mchung, malenkov
jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java
jdk/src/share/classes/java/beans/Introspector.java
jdk/src/share/classes/sun/misc/JavaBeansIntrospectorAccess.java
jdk/src/share/classes/sun/misc/SharedSecrets.java
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Wed Mar 26 15:58:37 2014 +0400
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Wed Mar 26 12:25:09 2014 +0000
@@ -55,6 +55,9 @@
 import java.security.AccessController;
 import javax.management.AttributeNotFoundException;
 import javax.management.openmbean.CompositeData;
+
+import sun.misc.JavaBeansIntrospectorAccess;
+import sun.misc.SharedSecrets;
 import sun.reflect.misc.MethodUtil;
 import sun.reflect.misc.ReflectUtil;
 
@@ -549,16 +552,9 @@
                 // Java Beans introspection
                 //
                 Class<?> clazz = complex.getClass();
-                Method readMethod = null;
-                if (BeansHelper.isAvailable()) {
-                    Object bi = BeansHelper.getBeanInfo(clazz);
-                    Object[] pds = BeansHelper.getPropertyDescriptors(bi);
-                    for (Object pd: pds) {
-                        if (BeansHelper.getPropertyName(pd).equals(element)) {
-                            readMethod = BeansHelper.getReadMethod(pd);
-                            break;
-                        }
-                    }
+                Method readMethod;
+                if (BeansIntrospector.isAvailable()) {
+                    readMethod = BeansIntrospector.getReadMethod(clazz, element);
                 } else {
                     // Java Beans not available so use simple introspection
                     // to locate method
@@ -584,6 +580,30 @@
     }
 
     /**
+     * Provides access to java.beans.Introspector if available.
+     */
+    private static class BeansIntrospector {
+        private static final JavaBeansIntrospectorAccess JBIA;
+        static {
+            // ensure that java.beans.Introspector is initialized (if present)
+            try {
+                Class.forName("java.beans.Introspector", true,
+                              BeansIntrospector.class.getClassLoader());
+            } catch (ClassNotFoundException ignore) { }
+
+            JBIA = SharedSecrets.getJavaBeansIntrospectorAccess();
+        }
+
+        static boolean isAvailable() {
+            return JBIA != null;
+        }
+
+        static Method getReadMethod(Class<?> clazz, String property) throws Exception {
+            return JBIA.getReadMethod(clazz, property);
+        }
+    }
+
+    /**
      * A simple introspector that uses reflection to analyze a class and
      * identify its "getter" methods. This class is intended for use only when
      * Java Beans is not present (which implies that there isn't explicit
@@ -696,121 +716,4 @@
             return null;
         }
     }
-
-    /**
-     * A class that provides access to the JavaBeans Introspector and
-     * PropertyDescriptors without creating a static dependency on java.beans.
-     */
-    private static class BeansHelper {
-        private static final Class<?> introspectorClass =
-            getClass("java.beans.Introspector");
-        private static final Class<?> beanInfoClass =
-            (introspectorClass == null) ? null : getClass("java.beans.BeanInfo");
-        private static final Class<?> getPropertyDescriptorClass =
-            (beanInfoClass == null) ? null : getClass("java.beans.PropertyDescriptor");
-
-        private static final Method getBeanInfo =
-            getMethod(introspectorClass, "getBeanInfo", Class.class);
-        private static final Method getPropertyDescriptors =
-            getMethod(beanInfoClass, "getPropertyDescriptors");
-        private static final Method getPropertyName =
-            getMethod(getPropertyDescriptorClass, "getName");
-        private static final Method getReadMethod =
-            getMethod(getPropertyDescriptorClass, "getReadMethod");
-
-        private static Class<?> getClass(String name) {
-            try {
-                return Class.forName(name, true, null);
-            } catch (ClassNotFoundException e) {
-                return null;
-            }
-        }
-        private static Method getMethod(Class<?> clazz,
-                                        String name,
-                                        Class<?>... paramTypes)
-        {
-            if (clazz != null) {
-                try {
-                    return clazz.getMethod(name, paramTypes);
-                } catch (NoSuchMethodException e) {
-                    throw new AssertionError(e);
-                }
-            } else {
-                return null;
-            }
-        }
-
-        private BeansHelper() { }
-
-        /**
-         * Returns {@code true} if java.beans is available.
-         */
-        static boolean isAvailable() {
-            return introspectorClass != null;
-        }
-
-        /**
-         * Invokes java.beans.Introspector.getBeanInfo(Class)
-         */
-        static Object getBeanInfo(Class<?> clazz) throws Exception {
-            try {
-                return getBeanInfo.invoke(null, clazz);
-            } catch (InvocationTargetException e) {
-                Throwable cause = e.getCause();
-                if (cause instanceof Exception)
-                    throw (Exception)cause;
-                throw new AssertionError(e);
-            } catch (IllegalAccessException iae) {
-                throw new AssertionError(iae);
-            }
-        }
-
-        /**
-         * Invokes java.beans.BeanInfo.getPropertyDescriptors()
-         */
-        static Object[] getPropertyDescriptors(Object bi) {
-            try {
-                return (Object[])getPropertyDescriptors.invoke(bi);
-            } catch (InvocationTargetException e) {
-                Throwable cause = e.getCause();
-                if (cause instanceof RuntimeException)
-                    throw (RuntimeException)cause;
-                throw new AssertionError(e);
-            } catch (IllegalAccessException iae) {
-                throw new AssertionError(iae);
-            }
-        }
-
-        /**
-         * Invokes java.beans.PropertyDescriptor.getName()
-         */
-        static String getPropertyName(Object pd) {
-            try {
-                return (String)getPropertyName.invoke(pd);
-            } catch (InvocationTargetException e) {
-                Throwable cause = e.getCause();
-                if (cause instanceof RuntimeException)
-                    throw (RuntimeException)cause;
-                throw new AssertionError(e);
-            } catch (IllegalAccessException iae) {
-                throw new AssertionError(iae);
-            }
-        }
-
-        /**
-         * Invokes java.beans.PropertyDescriptor.getReadMethod()
-         */
-        static Method getReadMethod(Object pd) {
-            try {
-                return (Method)getReadMethod.invoke(pd);
-            } catch (InvocationTargetException e) {
-                Throwable cause = e.getCause();
-                if (cause instanceof RuntimeException)
-                    throw (RuntimeException)cause;
-                throw new AssertionError(e);
-            } catch (IllegalAccessException iae) {
-                throw new AssertionError(iae);
-            }
-        }
-    }
 }
--- a/jdk/src/share/classes/java/beans/Introspector.java	Wed Mar 26 15:58:37 2014 +0400
+++ b/jdk/src/share/classes/java/beans/Introspector.java	Wed Mar 26 12:25:09 2014 +0000
@@ -47,6 +47,8 @@
 import java.util.List;
 import java.util.TreeMap;
 
+import sun.misc.JavaBeansIntrospectorAccess;
+import sun.misc.SharedSecrets;
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -140,6 +142,20 @@
     static final String SET_PREFIX = "set";
     static final String IS_PREFIX = "is";
 
+    // register with SharedSecrets for JMX usage
+    static {
+        SharedSecrets.setJavaBeansIntrospectorAccess((clazz, property) -> {
+            BeanInfo bi = Introspector.getBeanInfo(clazz);
+            PropertyDescriptor[] pds = bi.getPropertyDescriptors();
+            for (PropertyDescriptor pd: pds) {
+                if (pd.getName().equals(property)) {
+                    return pd.getReadMethod();
+                }
+            }
+            return null;
+        });
+    }
+
     //======================================================================
     //                          Public methods
     //======================================================================
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/misc/JavaBeansIntrospectorAccess.java	Wed Mar 26 12:25:09 2014 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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 sun.misc;
+
+import java.lang.reflect.Method;
+
+public interface JavaBeansIntrospectorAccess {
+    Method getReadMethod(Class<?> clazz, String property) throws Exception;
+}
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java	Wed Mar 26 15:58:37 2014 +0400
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java	Wed Mar 26 12:25:09 2014 +0000
@@ -55,6 +55,7 @@
     private static JavaSecurityAccess javaSecurityAccess;
     private static JavaUtilZipFileAccess javaUtilZipFileAccess;
     private static JavaAWTAccess javaAWTAccess;
+    private static JavaBeansIntrospectorAccess javaBeansIntrospectorAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -184,4 +185,12 @@
         }
         return javaAWTAccess;
     }
+
+    public static JavaBeansIntrospectorAccess getJavaBeansIntrospectorAccess() {
+        return javaBeansIntrospectorAccess;
+    }
+
+    public static void setJavaBeansIntrospectorAccess(JavaBeansIntrospectorAccess access) {
+        javaBeansIntrospectorAccess = access;
+    }
 }