/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
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><li>If <code>true</code> is returned, then instances of
* <code>c</code> are DynamicMBean.</li>
* <li>If <code>false</code> is returned, then no further
* assumption can be made on instances of <code>c</code>.
* In particular, instances of <code>c</code> may, or may not
* be JMX standard MBeans.</li>
* </ul>
* @param c The class of the MBean under examination.
* @return <code>true</code> if instances of <code>c</code> are
* Dynamic MBeans, <code>false</code> 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><li>The given class is a concrete class.</li>
* <li>The given class exposes at least one public constructor.</li>
* </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</code> 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</code> 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<? super T>
getStandardMBeanInterface(
Class<T>
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<? super T>
getMXBeanInterface(
Class<T>
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>aName</i>MBean, from within aClass and its superclasses.
**/
private static <T>
Class<? super T>
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<
String,
Object>();
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); </pre>
* @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<? super T>
implementsMBean(
Class<T>
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<?>,
SoftReference<
List<
Method>>>
cache =
Collections.
synchronizedMap(
new
WeakHashMap<
Class<?>,
SoftReference<
List<
Method>>> ());
/**
* 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<
Method>>
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<
Method>();
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<
Method>>(
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);
}
}
}
}