alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Introspector.java)

This example Java source code file (Introspector.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

annotation, assertionerror, attributenotfoundexception, class, dynamicmbean, illegalaccessexception, invocationtargetexception, list, management, mbeaninfo, method, notcompliantmbeanexception, object, reflection, runtimeexception, security, string, throwable, util

The Introspector.java Java example source code

/*
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  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.jmx.mbeanserver;

import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;

import javax.management.Descriptor;
import javax.management.DescriptorKey;
import javax.management.DynamicMBean;
import javax.management.ImmutableDescriptor;
import javax.management.MBeanInfo;
import javax.management.NotCompliantMBeanException;

import com.sun.jmx.remote.util.EnvHelp;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import javax.management.AttributeNotFoundException;
import javax.management.openmbean.CompositeData;
import sun.reflect.misc.MethodUtil;
import sun.reflect.misc.ReflectUtil;

/**
 * This class contains the methods for performing all the tests needed to verify
 * that a class represents a JMX compliant MBean.
 *
 * @since 1.5
 */
public class Introspector {
    final public static boolean ALLOW_NONPUBLIC_MBEAN;
    static {
        String val = AccessController.doPrivileged(new GetPropertyAction("jdk.jmx.mbeans.allowNonPublic"));
        ALLOW_NONPUBLIC_MBEAN = Boolean.parseBoolean(val);
    }

     /*
     * ------------------------------------------
     *  PRIVATE CONSTRUCTORS
     * ------------------------------------------
     */

    // private constructor defined to "hide" the default public constructor
    private Introspector() {

        // ------------------------------
        // ------------------------------

    }

    /*
     * ------------------------------------------
     *  PUBLIC METHODS
     * ------------------------------------------
     */

    /**
     * Tell whether a MBean of the given class is a Dynamic MBean.
     * This method does nothing more than returning
     * <pre>
     * javax.management.DynamicMBean.class.isAssignableFrom(c)
     * </pre>
     * This method does not check for any JMX MBean compliance:
     * <ul>
  • If true is returned, then instances of * <code>c are DynamicMBean.
  • * <li>If false is returned, then no further * assumption can be made on instances of <code>c. * In particular, instances of <code>c may, or may not * be JMX standard MBeans.</li> * </ul> * @param c The class of the MBean under examination. * @return <code>true if instances of c are * Dynamic MBeans, <code>false otherwise. * **/ public static final boolean isDynamic(final Class<?> c) { // Check if the MBean implements the DynamicMBean interface return javax.management.DynamicMBean.class.isAssignableFrom(c); } /** * Basic method for testing that a MBean of a given class can be * instantiated by the MBean server.<p> * This method checks that: * <ul>
  • The given class is a concrete class.
  • * <li>The given class exposes at least one public constructor. * </ul> * If these conditions are not met, throws a NotCompliantMBeanException. * @param c The class of the MBean we want to create. * @exception NotCompliantMBeanException if the MBean class makes it * impossible to instantiate the MBean from within the * MBeanServer. * **/ public static void testCreation(Class<?> c) throws NotCompliantMBeanException { // Check if the class is a concrete class final int mods = c.getModifiers(); if (Modifier.isAbstract(mods) || Modifier.isInterface(mods)) { throw new NotCompliantMBeanException("MBean class must be concrete"); } // Check if the MBean has a public constructor final Constructor<?>[] consList = c.getConstructors(); if (consList.length == 0) { throw new NotCompliantMBeanException("MBean class must have public constructor"); } } public static void checkCompliance(Class<?> mbeanClass) throws NotCompliantMBeanException { // Is DynamicMBean? // if (DynamicMBean.class.isAssignableFrom(mbeanClass)) return; // Is Standard MBean? // final Exception mbeanException; try { getStandardMBeanInterface(mbeanClass); return; } catch (NotCompliantMBeanException e) { mbeanException = e; } // Is MXBean? // final Exception mxbeanException; try { getMXBeanInterface(mbeanClass); return; } catch (NotCompliantMBeanException e) { mxbeanException = e; } final String msg = "MBean class " + mbeanClass.getName() + " does not implement " + "DynamicMBean, and neither follows the Standard MBean conventions (" + mbeanException.toString() + ") nor the MXBean conventions (" + mxbeanException.toString() + ")"; throw new NotCompliantMBeanException(msg); } public static <T> DynamicMBean makeDynamicMBean(T mbean) throws NotCompliantMBeanException { if (mbean instanceof DynamicMBean) return (DynamicMBean) mbean; final Class<?> mbeanClass = mbean.getClass(); Class<? super T> c = null; try { c = Util.cast(getStandardMBeanInterface(mbeanClass)); } catch (NotCompliantMBeanException e) { // Ignore exception - we need to check whether // mbean is an MXBean first. } if (c != null) return new StandardMBeanSupport(mbean, c); try { c = Util.cast(getMXBeanInterface(mbeanClass)); } catch (NotCompliantMBeanException e) { // Ignore exception - we cannot decide whether mbean was supposed // to be an MBean or an MXBean. We will call checkCompliance() // to generate the appropriate exception. } if (c != null) return new MXBeanSupport(mbean, c); checkCompliance(mbeanClass); throw new NotCompliantMBeanException("Not compliant"); // not reached } /** * Basic method for testing if a given class is a JMX compliant MBean. * * @param baseClass The class to be tested * * @return <code>null if the MBean is a DynamicMBean, * the computed {@link javax.management.MBeanInfo} otherwise. * @exception NotCompliantMBeanException The specified class is not a * JMX compliant MBean */ public static MBeanInfo testCompliance(Class<?> baseClass) throws NotCompliantMBeanException { // ------------------------------ // ------------------------------ // Check if the MBean implements the MBean or the Dynamic // MBean interface if (isDynamic(baseClass)) return null; return testCompliance(baseClass, null); } /** * Tests the given interface class for being a compliant MXBean interface. * A compliant MXBean interface is any publicly accessible interface * following the {@link MXBean} conventions. * @param interfaceClass An interface class to test for the MXBean compliance * @throws NotCompliantMBeanException Thrown when the tested interface * is not public or contradicts the {@link MXBean} conventions. */ public static void testComplianceMXBeanInterface(Class<?> interfaceClass) throws NotCompliantMBeanException { MXBeanIntrospector.getInstance().getAnalyzer(interfaceClass); } /** * Tests the given interface class for being a compliant MBean interface. * A compliant MBean interface is any publicly accessible interface * following the {@code MBean} conventions. * @param interfaceClass An interface class to test for the MBean compliance * @throws NotCompliantMBeanException Thrown when the tested interface * is not public or contradicts the {@code MBean} conventions. */ public static void testComplianceMBeanInterface(Class<?> interfaceClass) throws NotCompliantMBeanException{ StandardMBeanIntrospector.getInstance().getAnalyzer(interfaceClass); } /** * Basic method for testing if a given class is a JMX compliant * Standard MBean. This method is only called by the legacy code * in com.sun.management.jmx. * * @param baseClass The class to be tested. * * @param mbeanInterface the MBean interface that the class implements, * or null if the interface must be determined by introspection. * * @return the computed {@link javax.management.MBeanInfo}. * @exception NotCompliantMBeanException The specified class is not a * JMX compliant Standard MBean */ public static synchronized MBeanInfo testCompliance(final Class<?> baseClass, Class<?> mbeanInterface) throws NotCompliantMBeanException { if (mbeanInterface == null) mbeanInterface = getStandardMBeanInterface(baseClass); ReflectUtil.checkPackageAccess(mbeanInterface); MBeanIntrospector<?> introspector = StandardMBeanIntrospector.getInstance(); return getClassMBeanInfo(introspector, baseClass, mbeanInterface); } private static <M> MBeanInfo getClassMBeanInfo(MBeanIntrospector<M> introspector, Class<?> baseClass, Class mbeanInterface) throws NotCompliantMBeanException { PerInterface<M> perInterface = introspector.getPerInterface(mbeanInterface); return introspector.getClassMBeanInfo(baseClass, perInterface); } /** * Get the MBean interface implemented by a JMX Standard * MBean class. This method is only called by the legacy * code in "com.sun.management.jmx". * * @param baseClass The class to be tested. * * @return The MBean interface implemented by the MBean. * Return <code>null if the MBean is a DynamicMBean, * or if no MBean interface is found. */ public static Class<?> getMBeanInterface(Class baseClass) { // Check if the given class implements the MBean interface // or the Dynamic MBean interface if (isDynamic(baseClass)) return null; try { return getStandardMBeanInterface(baseClass); } catch (NotCompliantMBeanException e) { return null; } } /** * Get the MBean interface implemented by a JMX Standard MBean class. * * @param baseClass The class to be tested. * * @return The MBean interface implemented by the Standard MBean. * * @throws NotCompliantMBeanException The specified class is * not a JMX compliant Standard MBean. */ public static <T> Class getStandardMBeanInterface(Class baseClass) throws NotCompliantMBeanException { Class<? super T> current = baseClass; Class<? super T> mbeanInterface = null; while (current != null) { mbeanInterface = findMBeanInterface(current, current.getName()); if (mbeanInterface != null) break; current = current.getSuperclass(); } if (mbeanInterface != null) { return mbeanInterface; } else { final String msg = "Class " + baseClass.getName() + " is not a JMX compliant Standard MBean"; throw new NotCompliantMBeanException(msg); } } /** * Get the MXBean interface implemented by a JMX MXBean class. * * @param baseClass The class to be tested. * * @return The MXBean interface implemented by the MXBean. * * @throws NotCompliantMBeanException The specified class is * not a JMX compliant MXBean. */ public static <T> Class getMXBeanInterface(Class baseClass) throws NotCompliantMBeanException { try { return MXBeanSupport.findMXBeanInterface(baseClass); } catch (Exception e) { throw throwException(baseClass,e); } } /* * ------------------------------------------ * PRIVATE METHODS * ------------------------------------------ */ /** * Try to find the MBean interface corresponding to the class aName * - i.e. <i>aNameMBean, from within aClass and its superclasses. **/ private static <T> Class findMBeanInterface( Class<T> aClass, String aName) { Class<? super T> current = aClass; while (current != null) { final Class<?>[] interfaces = current.getInterfaces(); final int len = interfaces.length; for (int i=0;i<len;i++) { Class<? super T> inter = Util.cast(interfaces[i]); inter = implementsMBean(inter, aName); if (inter != null) return inter; } current = current.getSuperclass(); } return null; } public static Descriptor descriptorForElement(final AnnotatedElement elmt) { if (elmt == null) return ImmutableDescriptor.EMPTY_DESCRIPTOR; final Annotation[] annots = elmt.getAnnotations(); return descriptorForAnnotations(annots); } public static Descriptor descriptorForAnnotations(Annotation[] annots) { if (annots.length == 0) return ImmutableDescriptor.EMPTY_DESCRIPTOR; Map<String, Object> descriptorMap = new HashMap(); for (Annotation a : annots) { Class<? extends Annotation> c = a.annotationType(); Method[] elements = c.getMethods(); boolean packageAccess = false; for (Method element : elements) { DescriptorKey key = element.getAnnotation(DescriptorKey.class); if (key != null) { String name = key.value(); Object value; try { // Avoid checking access more than once per annotation if (!packageAccess) { ReflectUtil.checkPackageAccess(c); packageAccess = true; } value = MethodUtil.invoke(element, a, null); } catch (RuntimeException e) { // we don't expect this - except for possibly // security exceptions? // RuntimeExceptions shouldn't be "UndeclaredThrowable". // anyway... // throw e; } catch (Exception e) { // we don't expect this throw new UndeclaredThrowableException(e); } value = annotationToField(value); Object oldValue = descriptorMap.put(name, value); if (oldValue != null && !equals(oldValue, value)) { final String msg = "Inconsistent values for descriptor field " + name + " from annotations: " + value + " :: " + oldValue; throw new IllegalArgumentException(msg); } } } } if (descriptorMap.isEmpty()) return ImmutableDescriptor.EMPTY_DESCRIPTOR; else return new ImmutableDescriptor(descriptorMap); } /** * Throws a NotCompliantMBeanException or a SecurityException. * @param notCompliant the class which was under examination * @param cause the raeson why NotCompliantMBeanException should * be thrown. * @return nothing - this method always throw an exception. * The return type makes it possible to write * <pre> throw throwException(clazz,cause);
    * @throws SecurityException - if cause is a SecurityException * @throws NotCompliantMBeanException otherwise. **/ static NotCompliantMBeanException throwException(Class<?> notCompliant, Throwable cause) throws NotCompliantMBeanException, SecurityException { if (cause instanceof SecurityException) throw (SecurityException) cause; if (cause instanceof NotCompliantMBeanException) throw (NotCompliantMBeanException)cause; final String classname = (notCompliant==null)?"null class":notCompliant.getName(); final String reason = (cause==null)?"Not compliant":cause.getMessage(); final NotCompliantMBeanException res = new NotCompliantMBeanException(classname+": "+reason); res.initCause(cause); throw res; } // Convert a value from an annotation element to a descriptor field value // E.g. with @interface Foo {class value()} an annotation @Foo(String.class) // will produce a Descriptor field value "java.lang.String" private static Object annotationToField(Object x) { // An annotation element cannot have a null value but never mind if (x == null) return null; if (x instanceof Number || x instanceof String || x instanceof Character || x instanceof Boolean || x instanceof String[]) return x; // Remaining possibilities: array of primitive (e.g. int[]), // enum, class, array of enum or class. Class<?> c = x.getClass(); if (c.isArray()) { if (c.getComponentType().isPrimitive()) return x; Object[] xx = (Object[]) x; String[] ss = new String[xx.length]; for (int i = 0; i < xx.length; i++) ss[i] = (String) annotationToField(xx[i]); return ss; } if (x instanceof Class<?>) return ((Class<?>) x).getName(); if (x instanceof Enum<?>) return ((Enum<?>) x).name(); // The only other possibility is that the value is another // annotation, or that the language has evolved since this code // was written. We don't allow for either of those currently. // If it is indeed another annotation, then x will be a proxy // with an unhelpful name like $Proxy2. So we extract the // proxy's interface to use that in the exception message. if (Proxy.isProxyClass(c)) c = c.getInterfaces()[0]; // array "can't be empty" throw new IllegalArgumentException("Illegal type for annotation " + "element using @DescriptorKey: " + c.getName()); } // This must be consistent with the check for duplicate field values in // ImmutableDescriptor.union. But we don't expect to be called very // often so this inefficient check should be enough. private static boolean equals(Object x, Object y) { return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); } /** * Returns the XXMBean interface or null if no such interface exists * * @param c The interface to be tested * @param clName The name of the class implementing this interface */ private static <T> Class implementsMBean(Class c, String clName) { String clMBeanName = clName + "MBean"; if (c.getName().equals(clMBeanName)) { return c; } Class<?>[] interfaces = c.getInterfaces(); for (int i = 0;i < interfaces.length; i++) { if (interfaces[i].getName().equals(clMBeanName) && (Modifier.isPublic(interfaces[i].getModifiers()) || ALLOW_NONPUBLIC_MBEAN)) { return Util.cast(interfaces[i]); } } return null; } public static Object elementFromComplex(Object complex, String element) throws AttributeNotFoundException { try { if (complex.getClass().isArray() && element.equals("length")) { return Array.getLength(complex); } else if (complex instanceof CompositeData) { return ((CompositeData) complex).get(element); } else { // 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; } } } else { // Java Beans not available so use simple introspection // to locate method readMethod = SimpleIntrospector.getReadMethod(clazz, element); } if (readMethod != null) { ReflectUtil.checkPackageAccess(readMethod.getDeclaringClass()); return MethodUtil.invoke(readMethod, complex, new Class[0]); } throw new AttributeNotFoundException( "Could not find the getter method for the property " + element + " using the Java Beans introspector"); } } catch (InvocationTargetException e) { throw new IllegalArgumentException(e); } catch (AttributeNotFoundException e) { throw e; } catch (Exception e) { throw EnvHelp.initCause( new AttributeNotFoundException(e.getMessage()), e); } } /** * 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 * information about the bean available). */ private static class SimpleIntrospector { private SimpleIntrospector() { } private static final String GET_METHOD_PREFIX = "get"; private static final String IS_METHOD_PREFIX = "is"; // cache to avoid repeated lookups private static final Map<Class>> cache = Collections.synchronizedMap( new WeakHashMap<Class>> ()); /** * Returns the list of methods cached for the given class, or {@code null} * if not cached. */ private static List<Method> getCachedMethods(Class clazz) { // return cached methods if possible SoftReference<List ref = cache.get(clazz); if (ref != null) { List<Method> cached = ref.get(); if (cached != null) return cached; } return null; } /** * Returns {@code true} if the given method is a "getter" method (where * "getter" method is a public method of the form getXXX or "boolean * isXXX") */ static boolean isReadMethod(Method method) { // ignore static methods int modifiers = method.getModifiers(); if (Modifier.isStatic(modifiers)) return false; String name = method.getName(); Class<?>[] paramTypes = method.getParameterTypes(); int paramCount = paramTypes.length; if (paramCount == 0 && name.length() > 2) { // boolean isXXX() if (name.startsWith(IS_METHOD_PREFIX)) return (method.getReturnType() == boolean.class); // getXXX() if (name.length() > 3 && name.startsWith(GET_METHOD_PREFIX)) return (method.getReturnType() != void.class); } return false; } /** * Returns the list of "getter" methods for the given class. The list * is ordered so that isXXX methods appear before getXXX methods - this * is for compatibility with the JavaBeans Introspector. */ static List<Method> getReadMethods(Class clazz) { // return cached result if available List<Method> cachedResult = getCachedMethods(clazz); if (cachedResult != null) return cachedResult; // get list of public methods, filtering out methods that have // been overridden to return a more specific type. List<Method> methods = StandardMBeanIntrospector.getInstance().getMethods(clazz); methods = MBeanAnalyzer.eliminateCovariantMethods(methods); // filter out the non-getter methods List<Method> result = new LinkedList(); for (Method m: methods) { if (isReadMethod(m)) { // favor isXXX over getXXX if (m.getName().startsWith(IS_METHOD_PREFIX)) { result.add(0, m); } else { result.add(m); } } } // add result to cache cache.put(clazz, new SoftReference<List(result)); return result; } /** * Returns the "getter" to read the given property from the given class or * {@code null} if no method is found. */ static Method getReadMethod(Class<?> clazz, String property) { // first character in uppercase (compatibility with JavaBeans) property = property.substring(0, 1).toUpperCase(Locale.ENGLISH) + property.substring(1); String getMethod = GET_METHOD_PREFIX + property; String isMethod = IS_METHOD_PREFIX + property; for (Method m: getReadMethods(clazz)) { String name = m.getName(); if (name.equals(isMethod) || name.equals(getMethod)) { return m; } } 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); } } } }

    Other Java examples (source code examples)

    Here is a short list of links related to this Java Introspector.java source code file:

    ... this post is sponsored by my books ...

    #1 New Release!

    FP Best Seller

     

    new blog posts

     

    Copyright 1998-2021 Alvin Alexander, alvinalexander.com
    All Rights Reserved.

    A percentage of advertising revenue from
    pages under the /java/jwarehouse URI on this website is
    paid back to open source projects.