diff --git a/.gitignore b/.gitignore index b9e09d6..1167426 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ /target /test-output /.settings +/.idea +*.iml diff --git a/pom.xml b/pom.xml index c5dcd13..1c2c47c 100644 --- a/pom.xml +++ b/pom.xml @@ -75,15 +75,18 @@ - - elibom - http://repository.elibom.net/nexus/content/repositories/releases - - - - elibom - http://repository.elibom.net/nexus/content/repositories/snapshots - + + releases + Internal Releases + http://maven.polarislabs.com/content/repositories/releases/ + default + + + snapshots + Internal Snapshots + http://maven.polarislabs.com/content/repositories/snapshots/ + default + - \ No newline at end of file + diff --git a/src/main/java/net/gescobar/jmx/annotation/DescriptorFields.java b/src/main/java/net/gescobar/jmx/annotation/DescriptorFields.java new file mode 100644 index 0000000..22860a5 --- /dev/null +++ b/src/main/java/net/gescobar/jmx/annotation/DescriptorFields.java @@ -0,0 +1,19 @@ +package net.gescobar.jmx.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE}) +public @interface DescriptorFields { + /** + * Key-value pairs + * + * @return + */ + String[] value(); +} diff --git a/src/main/java/net/gescobar/jmx/annotation/Impact.java b/src/main/java/net/gescobar/jmx/annotation/Impact.java index c1fb78a..ddd8810 100644 --- a/src/main/java/net/gescobar/jmx/annotation/Impact.java +++ b/src/main/java/net/gescobar/jmx/annotation/Impact.java @@ -3,24 +3,23 @@ import javax.management.MBeanOperationInfo; /** - * An enum that maps to impact options of the MBeanOperationInfo. - * + * An enum that maps to + * impact options of the + * MBeanOperationInfo. + * * @author German Escobar */ public enum Impact { - ACTION(MBeanOperationInfo.ACTION), - + ACTION(MBeanOperationInfo.ACTION), INFO(MBeanOperationInfo.INFO), - ACTION_INFO(MBeanOperationInfo.ACTION_INFO), - UNKNOWN(MBeanOperationInfo.UNKNOWN); - + private int code; - + private Impact(int code) { - this.code = code; + this.code = code; } public int getCode() { diff --git a/src/main/java/net/gescobar/jmx/impl/AbstractInstanceResolver.java b/src/main/java/net/gescobar/jmx/impl/AbstractInstanceResolver.java new file mode 100644 index 0000000..e5d6479 --- /dev/null +++ b/src/main/java/net/gescobar/jmx/impl/AbstractInstanceResolver.java @@ -0,0 +1,16 @@ +package net.gescobar.jmx.impl; + +/** + * Abstraction to allow for lazy-resolution of proxy targets. + * + * @author bvarner + */ +public abstract class AbstractInstanceResolver { + + /** + * Return an object to have methods or attributes invoked upon it. + * + * @return + */ + public abstract Object resolve(); +} diff --git a/src/main/java/net/gescobar/jmx/impl/InstanceResolver.java b/src/main/java/net/gescobar/jmx/impl/InstanceResolver.java new file mode 100644 index 0000000..0307fbc --- /dev/null +++ b/src/main/java/net/gescobar/jmx/impl/InstanceResolver.java @@ -0,0 +1,28 @@ +package net.gescobar.jmx.impl; + +/** + * A generic AbstractInstanceResolver which resolve the same object every time. + * + * @author bvarner + */ +public class InstanceResolver extends AbstractInstanceResolver { + + private Object target; + + /** + * Creates a new InstanceResolver which returns the given object. + */ + public InstanceResolver(Object obj) { + this.target = obj; + } + + /** + * Returns the object this InstanceResolver was constructed to wrap + * + * @return + */ + @Override + public Object resolve() { + return target; + } +} diff --git a/src/main/java/net/gescobar/jmx/impl/MBeanFactory.java b/src/main/java/net/gescobar/jmx/impl/MBeanFactory.java index e0f68b2..acfb1e5 100644 --- a/src/main/java/net/gescobar/jmx/impl/MBeanFactory.java +++ b/src/main/java/net/gescobar/jmx/impl/MBeanFactory.java @@ -1,12 +1,13 @@ package net.gescobar.jmx.impl; +import net.gescobar.jmx.annotation.DescriptorFields; import static net.gescobar.jmx.util.StringUtils.capitalize; import static net.gescobar.jmx.util.StringUtils.decapitalize; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import javax.management.DynamicMBean; import javax.management.MBeanAttributeInfo; @@ -24,362 +25,440 @@ import net.gescobar.jmx.annotation.ManagedOperation; /** - *

Factory of DynamicMBeans. Users can use this object directly to create DynamicMBeans and then registering them - * with any MBeanServer. However, the preferred approach is to use the {@link Management} class (which internally uses - * this class).

- * + *

+ * Factory of DynamicMBeans. Users can use this object directly to create + * DynamicMBeans and then registering them with any MBeanServer. However, the + * preferred approach is to use the {@link Management} class (which internally + * uses this class).

+ * * @author German Escobar */ -public final class MBeanFactory { - - /** - * Hide public constructor. - */ - private MBeanFactory() {} - - /** - * Creates a DynamicMBean from an object annotated with {@link ManagedBean} exposing all methods and attributes - * annotated with {@link ManagedOperation} and {@link ManagedAttribute} respectively. - * - * @param object the object from which we are creating the DynamicMBean. - * - * @return a constructed DynamicMBean object that can be registered with any MBeanServer. - */ - public static DynamicMBean createMBean(Object object) { - - if (object == null) { - throw new IllegalArgumentException("No object specified."); - } - - Class objectType = object.getClass(); - - // retrieve description - String description = ""; - if (objectType.isAnnotationPresent(Description.class)) { - description = objectType.getAnnotation(Description.class).value(); - } - - // build attributes and operations - Method[] methods = objectType.getMethods(); - MethodHandler methodHandler = new MBeanFactory().new MethodHandler( objectType ); - for (Method method : methods) { - methodHandler.handleMethod(method); - } - - // build the MBeanInfo - MBeanInfo mBeanInfo = new MBeanInfo(objectType.getName(), description, methodHandler.getMBeanAttributes(), - new MBeanConstructorInfo[0], methodHandler.getMBeanOperations(), new MBeanNotificationInfo[0]); - - // create the MBean - return new MBeanImpl(object, mBeanInfo); - - } +public class MBeanFactory { + + /** + * Hide public constructor. + */ + private MBeanFactory() { + } /** - * This class is used internally to handle the methods of the object that the - * {@link MBeanFactory#createMBean(Object)} receives as an argument. It creates a collection of MBeanAttributeInfo - * and MBeanOperationInfo from the information of the methods that it handles. - * + * Creates a DynamicMBean from an object annotated with {@link ManagedBean} + * exposing all methods and attributes annotated with + * {@link ManagedOperation} and {@link ManagedAttribute} respectively. + * + * @param object the class representing the object type resolved by TargetObjectResolver. + * + * @return a constructed DynamicMBean object that can be registered with any + * MBeanServer. + */ + public static DynamicMBean createMBean(Object object) { + if (object == null) { + throw new IllegalArgumentException("No object specified."); + } + return createMBean(object.getClass(), new InstanceResolver(object)); + } + + /** + * Creates a DynamicMBean from an object annotated with {@link ManagedBean} + * exposing all methods and attributes annotated with + * {@link ManagedOperation} and {@link ManagedAttribute} respectively. + * + * @param objectType the class representing the object type resolved by TargetObjectResolver. + * @param targetResolver A resolver capable of resolving an instance of the given type. + * + * @return a constructed DynamicMBean object that can be registered with any + * MBeanServer. + */ + public static DynamicMBean createMBean(Class objectType, AbstractInstanceResolver targetResolver) { + if (objectType == null) { + throw new IllegalArgumentException("No object class specified."); + } + + // retrieve description + String description = ""; + if (objectType.isAnnotationPresent(Description.class)) { + description = objectType.getAnnotation(Description.class).value(); + } + + // build attributes and operations + Method[] methods = objectType.getMethods(); + MethodHandler methodHandler = new MBeanFactory().new MethodHandler(objectType); + for (Method method : methods) { + methodHandler.handleMethod(method); + } + + // build the MBeanInfo + MBeanInfo mBeanInfo = new MBeanInfo(objectType.getName(), description, methodHandler.getMBeanAttributes(), + new MBeanConstructorInfo[0], methodHandler.getMBeanOperations(), new MBeanNotificationInfo[0]); + + // create the MBean + return new MBeanImpl(targetResolver, mBeanInfo); + + } + + /** + * This class is used internally to handle the methods of the object that + * the {@link MBeanFactory#createMBean(Object)} receives as an argument. It + * creates a collection of MBeanAttributeInfo and MBeanOperationInfo from + * the information of the methods that it handles. + * * @author German Escobar */ private class MethodHandler { - - /** - * The class of the object. - */ - private Class objectType; - - /** - * Holds the MBeanAttributeInfo objects that are created from the methods annotated with - * {@link MBeanAttributeInfo}. Notice that the relation is not 1-1. If the attribute is not readable or - * writable, it will not get added. - */ - private Collection mBeanAttributes = new ArrayList(); - - /** - * Holds the MBeanOperationInfo objects that are created from the methods annotated with - * {@link MBeanOperationInfo}. The relation is 1-1. - */ - private Collection mBeanOperations = new ArrayList(); - - /** - * Constructor. Initializes the object with the specified class. - * - * @param objectType the class of the object that the MBeanFactory is handling. - */ - public MethodHandler(Class objectType) { - this.objectType = objectType; - } - - /** - * Called once for each method of the object that the {@link MBeanFactory#createMBean(Object)} receives as an - * argument. If the method is annotated with {@link ManagedAttribute} it will try to create a - * MBeanAttributeInfo. If the method is annotated with {@link ManagedOperation} it will create a - * MBeanOperationInfo. Otherwise, it will do nothing with the method. - * - * @param method the method we are handling. - * - * @throws ManagementException wraps anyting that could go wrong. - */ - public void handleMethod(Method method) throws ManagementException { - - boolean hasManagedAttribute = method.isAnnotationPresent(ManagedAttribute.class); - boolean hasManagedOperation = method.isAnnotationPresent(ManagedOperation.class); - - if (hasManagedAttribute && hasManagedOperation) { - throw new ManagementException("Method " + method.getName() + " cannot have both ManagedAttribute and " + - "ManagedOperation annotations."); - } - - if (hasManagedAttribute) { - handleManagedAttribute(method); - } - - if (hasManagedOperation) { - handleManagedOperation(method); - } - - } - - /** - * Called after the {@link #handleMethod(Method)} is called for all the methods of the objectType. - * Retrieves the exposed attributes. - * - * @return an array of initialized MBeanAttributeInfo objects. It will never return null. - */ - public MBeanAttributeInfo[] getMBeanAttributes() { - return mBeanAttributes.toArray( new MBeanAttributeInfo[0] ); - } - - /** - * Called after the {@link #handleMethod(Method)} is called for all the methods of the objectType. - * Retrieves the exposed operations. - * - * @return an array of initialized MBeanOperationInfo objects. It will never return null. - */ - public MBeanOperationInfo[] getMBeanOperations() { - return mBeanOperations.toArray( new MBeanOperationInfo[0] ); - } - - /** - * Helper method. Handles a method that has a {@link ManagedAttribute} annotation. Notice that the mehtod is - * not necessarily a valid getter/setter. We actually need to find out. - * - * @param method the method that is annotated with {@link ManagedAttribute} - */ - private void handleManagedAttribute(Method method) { - - // validate if the method is a getter or setter - Method getterMethod = isGetterMethod(method) ? method : null; - Method setterMethod = isSetterMethod(method) ? method : null; - - if (getterMethod == null && setterMethod == null) { - // not a getter or setter - throw new ManagementException("Method " + method.getName() + " is annotated as ManagedAttribute " + - "but doesn't looks like a valid getter or setter."); - } - - // retrieve the attribute name from the method name - String attributeName = method.getName().startsWith("is") ? - decapitalize( method.getName().substring(2) ) : decapitalize( method.getName().substring(3) ); - - // retrieve the attribute type from the setter argument type or the getter return type - Class attributeType = setterMethod != null ? - method.getParameterTypes()[0] : method.getReturnType(); - - // find the missing method - getterMethod = getterMethod == null ? findGetterMethod(objectType, attributeName) : getterMethod; - setterMethod = setterMethod == null ? findSetterMethod(objectType, attributeName, attributeType) : setterMethod; - - boolean existsAttribute = existsAttribute(mBeanAttributes, attributeName, attributeType); - if ( !existsAttribute ) { - - // add the MBeanAttribute to the collection - MBeanAttributeInfo mBeanAttribute = buildMBeanAttribute(attributeName, attributeType, getterMethod, - setterMethod, method); - if (mBeanAttribute != null) { // it can be null if it is neither readable or writable - mBeanAttributes.add( mBeanAttribute ); - } - - } else { - // both getter and setter are annotated ... throw exception - throw new ManagementException("Both getter and setter are annotated for attribute " + - attributeName + ". Please remove one of the annotations."); - } - - } - - /** - * Helper method. Tells if the method is a getter or not. It checks if the method name starts with "get" or - * "is", that the method has no parameters and returns something different than void. - * - * @param method the method that we are testing to see if it is a getter. - * - * @return true if the method is a getter, false otherwise. - */ - private boolean isGetterMethod(Method method) { - return (method.getName().startsWith("get") || method.getName().startsWith("is")) - && (!method.getReturnType().equals(Void.TYPE) && method.getParameterTypes().length == 0); - } - - /** - * Helper method. Tells if the method is a setter or not. It checks if the method name starts with "set", - * that the return type is void and that it has exactly one parameter. - * - * @param method the method that we are testing to see if it is a setter. - * - * @return true if the method is a setter, false otherwise. - */ - private boolean isSetterMethod(Method method) { - return method.getName().startsWith("set") && method.getReturnType().equals(Void.TYPE) - && method.getParameterTypes().length == 1; - } - - /** - * Helper method. Tries to find a getter method for the specified objectType and - * attributeName. - * - * @param objectType the class from which we are going to find the getter method. - * @param attributeName the name of the attribute we are looking for. - * - * @return a java.lang.reflect.Method object representing the getter or null if not found. - */ - private Method findGetterMethod(Class objectType, String attributeName) { - - try { - return objectType.getMethod( "get" + capitalize(attributeName) ); - } catch (NoSuchMethodException e) {} - - try { - return objectType.getMethod( "is" + capitalize(attributeName) ); - } catch (NoSuchMethodException e) {} - - return null; + + /** + * The class of the object. + */ + private Class objectType; + + /** + * Holds the MBeanAttributeInfo objects that are created from the + * methods annotated with {@link MBeanAttributeInfo}. Notice that the + * relation is not 1-1. If the attribute is not readable or writable, it + * will not get added. + */ + private Collection mBeanAttributes = new ArrayList(); + + /** + * Holds the MBeanOperationInfo objects that are created from the + * methods annotated with {@link MBeanOperationInfo}. The relation is + * 1-1. + */ + private Collection mBeanOperations = new ArrayList(); + + /** + * Constructor. Initializes the object with the specified class. + * + * @param objectType the class of the object that the MBeanFactory is + * handling. + */ + public MethodHandler(Class objectType) { + this.objectType = objectType; + } + + /** + * Called once for each method of the object that the + * {@link MBeanFactory#createMBean(Object)} receives as an argument. If + * the method is annotated with {@link ManagedAttribute} it will try to + * create a MBeanAttributeInfo. If the method is annotated with + * {@link ManagedOperation} it will create a MBeanOperationInfo. + * Otherwise, it will do nothing with the method. + * + * @param method the method we are handling. + * + * @throws ManagementException wraps anyting that could go wrong. + */ + public void handleMethod(Method method) throws ManagementException { + + boolean hasManagedAttribute = method.isAnnotationPresent(ManagedAttribute.class); + boolean hasManagedOperation = method.isAnnotationPresent(ManagedOperation.class); + + if (hasManagedAttribute && hasManagedOperation) { + throw new ManagementException("Method " + method.getName() + " cannot have both ManagedAttribute and " + + "ManagedOperation annotations."); + } + + if (hasManagedAttribute) { + handleManagedAttribute(method); + } + + if (hasManagedOperation) { + handleManagedOperation(method); + } + + } + + /** + * Called after the {@link #handleMethod(Method)} is called for all the + * methods of the objectType. Retrieves the exposed + * attributes. + * + * @return an array of initialized MBeanAttributeInfo objects. It will + * never return null. + */ + public MBeanAttributeInfo[] getMBeanAttributes() { + return mBeanAttributes.toArray(new MBeanAttributeInfo[0]); + } + + /** + * Called after the {@link #handleMethod(Method)} is called for all the + * methods of the objectType. Retrieves the exposed + * operations. + * + * @return an array of initialized MBeanOperationInfo objects. It will + * never return null. + */ + public MBeanOperationInfo[] getMBeanOperations() { + return mBeanOperations.toArray(new MBeanOperationInfo[0]); + } + + /** + * Helper method. Handles a method that has a {@link ManagedAttribute} + * annotation. Notice that the mehtod is not necessarily a valid + * getter/setter. We actually need to find out. + * + * @param method the method that is annotated with + * {@link ManagedAttribute} + */ + private void handleManagedAttribute(Method method) { + + // validate if the method is a getter or setter + Method getterMethod = isGetterMethod(method) ? method : null; + Method setterMethod = isSetterMethod(method) ? method : null; + + if (getterMethod == null && setterMethod == null) { + // not a getter or setter + throw new ManagementException("Method " + method.getName() + " is annotated as ManagedAttribute " + + "but doesn't looks like a valid getter or setter."); + } + + // retrieve the attribute name from the method name + String attributeName = method.getName().startsWith("is") + ? decapitalize(method.getName().substring(2)) : decapitalize(method.getName().substring(3)); + + // retrieve the attribute type from the setter argument type or the getter return type + Class attributeType = setterMethod != null + ? method.getParameterTypes()[0] : method.getReturnType(); + + // find the missing method + getterMethod = getterMethod == null ? findGetterMethod(objectType, attributeName) : getterMethod; + setterMethod = setterMethod == null ? findSetterMethod(objectType, attributeName, attributeType) : setterMethod; + + boolean existsAttribute = existsAttribute(mBeanAttributes, attributeName, attributeType); + if (!existsAttribute) { + + // add the MBeanAttribute to the collection + MBeanAttributeInfo mBeanAttribute = buildMBeanAttribute(attributeName, attributeType, getterMethod, + setterMethod, method); + if (mBeanAttribute != null) { // it can be null if it is neither readable or writable + mBeanAttributes.add(mBeanAttribute); + } + + } else { + // both getter and setter are annotated ... throw exception + throw new ManagementException("Both getter and setter are annotated for attribute " + + attributeName + ". Please remove one of the annotations."); + } + } - /** - * Helper method. Tries to find a setter method for the specified objectType, - * attributeName and attributeType - * - * @param objectType the class from which we are going to find the setter method. - * @param attributeName the name of the attribute we are looking for. - * @param attributeType the type of the attribute we are looking for. - * - * @return a java.lang.reflect.Method object representing the setter or null if not found. - */ + /** + * Helper method. Tells if the method is a getter or not. It checks if + * the method name starts with "get" or "is", that the method has no + * parameters and returns something different than void. + * + * @param method the method that we are testing to see if it is a + * getter. + * + * @return true if the method is a getter, false otherwise. + */ + private boolean isGetterMethod(Method method) { + return (method.getName().startsWith("get") || method.getName().startsWith("is")) + && (!method.getReturnType().equals(Void.TYPE) && method.getParameterTypes().length == 0); + } + + /** + * Helper method. Tells if the method is a setter or not. It checks if + * the method name starts with "set", that the return type is + * void and that it has exactly one parameter. + * + * @param method the method that we are testing to see if it is a + * setter. + * + * @return true if the method is a setter, false otherwise. + */ + private boolean isSetterMethod(Method method) { + return method.getName().startsWith("set") && method.getReturnType().equals(Void.TYPE) + && method.getParameterTypes().length == 1; + } + + /** + * Helper method. Tries to find a getter method for the specified + * objectType and attributeName. + * + * @param objectType the class from which we are going to find the + * getter method. + * @param attributeName the name of the attribute we are looking for. + * + * @return a java.lang.reflect.Method object representing the getter or + * null if not found. + */ + private Method findGetterMethod(Class objectType, String attributeName) { + + try { + return objectType.getMethod("get" + capitalize(attributeName)); + } catch (NoSuchMethodException e) { + } + + try { + return objectType.getMethod("is" + capitalize(attributeName)); + } catch (NoSuchMethodException e) { + } + + return null; + } + + /** + * Helper method. Tries to find a setter method for the specified + * objectType, attributeName and + * attributeType + * + * @param objectType the class from which we are going to find the + * setter method. + * @param attributeName the name of the attribute we are looking for. + * @param attributeType the type of the attribute we are looking for. + * + * @return a java.lang.reflect.Method object representing the setter or + * null if not found. + */ private Method findSetterMethod(Class objectType, String name, Class attributeType) { - - try { - return objectType.getMethod( "set" + capitalize(name), attributeType ); - } catch (NoSuchMethodException e) { - return null; - } - + + try { + return objectType.getMethod("set" + capitalize(name), attributeType); + } catch (NoSuchMethodException e) { + return null; + } + } - - /** - * Helper method. Tells if the collection of MBeanAttributeInfo holds an attribute with the specified name - * and type. - * - * @param mBeanAttributes the collection of MBeanAttributeInfo in which we are searching the attribute. - * @param attributeName the name of the attribute we are searching for. - * @param attributeType the type of the attribute we are searching for. - * - * @return true if the collections holds the attribute, false otherwise. - */ - private boolean existsAttribute(Collection mBeanAttributes, String attributeName, Class attributeType) { - - for (MBeanAttributeInfo mBeanAttribute : mBeanAttributes) { - if (mBeanAttribute.getName().equals(attributeName) - && mBeanAttribute.getType().equals(attributeType.getName())) { - return true; - } - } - - return false; - - } - - /** - * Helper method. Builds an MBeanAttributeInfo. As a precondition we know that there is public getter or - * setter method for the attribute that it's annotated with {@link ManagedAttribute}. - * - * @param attributeName the name of the attribute for which we are trying to build the MBeanAttributeInfo. - * @param attributeType the class of the attribute for which we are trying to build the MBeanAttributeInfo. - * @param getterMethod the getter method of the attribute ... can be null. - * @param setterMethod the setter method of the attribute ... can be null. - * @param annotatedMethod the method that is annotated with {@link ManagedAttribute} ... can't be null. - * - * @return a constructed MBeanAttributeInfo object or null if the attribute is neither readable or writable. - */ - private MBeanAttributeInfo buildMBeanAttribute(String attributeName, - Class attributeType, Method getterMethod, Method setterMethod, Method annotatedMethod) { - - ManagedAttribute managedAttribute = annotatedMethod.getAnnotation(ManagedAttribute.class); - - // it's readable if the annotation has readable=true (which is the default) and the getter method exists - boolean readable = managedAttribute.readable() && getterMethod != null; - - // it's writable if the annotation has writable=true (which is the default) and the setter method exists. - boolean writable = managedAttribute.writable() && setterMethod != null; - - // it's IS if the getter method exists and starts with "is". - boolean isIs = getterMethod != null && getterMethod.getName().startsWith("is"); - - // only add the attribute if it is readable and writable - if (readable || writable) { - return new MBeanAttributeInfo(attributeName, attributeType.getName(), managedAttribute.description(), - readable, writable, isIs); - } - - return null; - + + /** + * Helper method. Tells if the collection of MBeanAttributeInfo holds an + * attribute with the specified name and type. + * + * @param mBeanAttributes the collection of MBeanAttributeInfo in which + * we are searching the attribute. + * @param attributeName the name of the attribute we are searching for. + * @param attributeType the type of the attribute we are searching for. + * + * @return true if the collections holds the attribute, false otherwise. + */ + private boolean existsAttribute(Collection mBeanAttributes, String attributeName, Class attributeType) { + + for (MBeanAttributeInfo mBeanAttribute : mBeanAttributes) { + if (mBeanAttribute.getName().equals(attributeName) + && mBeanAttribute.getType().equals(attributeType.getName())) { + return true; + } + } + + return false; + + } + + /** + * Helper method. Builds an MBeanAttributeInfo. As a precondition we + * know that there is public getter or setter method for the attribute + * that it's annotated with {@link ManagedAttribute}. + * + * @param attributeName the name of the attribute for which we are + * trying to build the MBeanAttributeInfo. + * @param attributeType the class of the attribute for which we are + * trying to build the MBeanAttributeInfo. + * @param getterMethod the getter method of the attribute ... can be + * null. + * @param setterMethod the setter method of the attribute ... can be + * null. + * @param annotatedMethod the method that is annotated with + * {@link ManagedAttribute} ... can't be null. + * + * @return a constructed MBeanAttributeInfo object or null if the + * attribute is neither readable or writable. + */ + private MBeanAttributeInfo buildMBeanAttribute(String attributeName, + Class attributeType, Method getterMethod, Method setterMethod, Method annotatedMethod) { + + ManagedAttribute managedAttribute = annotatedMethod.getAnnotation(ManagedAttribute.class); + + // it's readable if the annotation has readable=true (which is the default) and the getter method exists + boolean readable = managedAttribute.readable() && getterMethod != null; + + // it's writable if the annotation has writable=true (which is the default) and the setter method exists. + boolean writable = managedAttribute.writable() && setterMethod != null; + + // it's IS if the getter method exists and starts with "is". + boolean isIs = getterMethod != null && getterMethod.getName().startsWith("is"); + + // only add the attribute if it is readable and writable + if (readable || writable) { + return new MBeanAttributeInfo(attributeName, attributeType.getName(), managedAttribute.description(), + readable, writable, isIs); + } + + return null; + + } + + /** + * Helper method. Handles a method that has a {@link ManagedOperation} + * annotation. It creates an MBeanOperationInfo from the method. + * + * @param method the method that is annotated with + * {@link ManagedOperation} + */ + private void handleManagedOperation(Method method) { + + // build the MBeanParameterInfo array from the parameters of the method + MBeanParameterInfo[] mBeanParameters = buildMBeanParameters(method); + + ManagedOperation managedOperation = method.getAnnotation(ManagedOperation.class); + Impact impact = managedOperation.impact(); + + mBeanOperations.add(new MBeanOperationInfo(method.getName(), managedOperation.description(), + mBeanParameters, method.getReturnType().getName(), impact.getCode())); + } - + /** - * Helper method. Handles a method that has a {@link ManagedOperation} annotation. It creates an - * MBeanOperationInfo from the method. - * - * @param method the method that is annotated with {@link ManagedOperation} - */ - private void handleManagedOperation(Method method) { - - // build the MBeanParameterInfo array from the parameters of the method - MBeanParameterInfo[] mBeanParameters = buildMBeanParameters( method.getParameterTypes(), - method.getParameterAnnotations() ); - - ManagedOperation managedOperation = method.getAnnotation(ManagedOperation.class); - Impact impact = managedOperation.impact(); - - mBeanOperations.add( new MBeanOperationInfo(method.getName(), managedOperation.description(), - mBeanParameters, method.getReturnType().getName(), impact.getCode()) ); - - } - - /** - * Helper method. Builds an array of MBeanParameterInfo objects that represent the parameters. - * - * @param paramsTypes the type of the parameters from which we are building the MBeanParameterInfo array. - * @param paramsAnnotations the annotations on the parameters .. we are not using this info yet but we will - * need it to retrieve the description of the parameters. - * - * @return an array of MBeanParameterInfo objects of the same size of the paramsTypes argument. - */ - private MBeanParameterInfo[] buildMBeanParameters(Class[] paramsTypes, Annotation[][] paramsAnnotations) { - - MBeanParameterInfo[] mBeanParameters = new MBeanParameterInfo[paramsTypes.length]; - - for (int i=0; i < paramsTypes.length; i++) { - - MBeanParameterInfo parameterInfo = new MBeanParameterInfo("param" + i, paramsTypes[i].getName(), ""); - mBeanParameters[i] = parameterInfo; - - } - - return mBeanParameters; - + * Helper method. Builds an array of MBeanParameterInfo objects that + * represent the parameters, using the DescriptorFields annotation style from the JMX 2.0 specification. + * + * @param method the method having parameter info build for it. + * + * @return an array of MBeanParameterInfo objects describing the Method. + */ + private MBeanParameterInfo[] buildMBeanParameters(Method method) { + Class[] paramsTypes = method.getParameterTypes(); + + HashMap paramNames = new HashMap(); + HashMap paramDesc = new HashMap(); + + boolean hasDescriptorFields = method.isAnnotationPresent(DescriptorFields.class); + if (hasDescriptorFields) { + String[] pairs = method.getAnnotation(DescriptorFields.class).value(); + for (int i = 0; i < pairs.length; i++) { + String[] keydesc = pairs[i].split(";"); + String[] keyval = keydesc[0].split("="); + + String desc = ""; + if (keydesc.length > 1) { + desc = keydesc[1]; + } + + paramNames.put(keyval[0], keyval[1]); + paramDesc.put(keyval[0], desc); + } + } + + MBeanParameterInfo[] mBeanParameters = new MBeanParameterInfo[paramsTypes.length]; + + for (int i = 0; i < paramsTypes.length; i++) { + String name = "p" + i; + String description = ""; + + if (paramDesc.containsKey(name)) { + description = paramDesc.get(name); + } + + if (paramNames.containsKey(name)) { + name = paramNames.get(name); + } + + + MBeanParameterInfo parameterInfo = new MBeanParameterInfo(name, paramsTypes[i].getName(), description); + mBeanParameters[i] = parameterInfo; + } + + return mBeanParameters; } - } - -} \ No newline at end of file +} diff --git a/src/main/java/net/gescobar/jmx/impl/MBeanImpl.java b/src/main/java/net/gescobar/jmx/impl/MBeanImpl.java index c557514..5f317a0 100644 --- a/src/main/java/net/gescobar/jmx/impl/MBeanImpl.java +++ b/src/main/java/net/gescobar/jmx/impl/MBeanImpl.java @@ -20,447 +20,450 @@ /** * This is the DynamicMBean implementation that is returned from the {@link MBeanFactory#createMBean(Object)} method. - * + * * @author German Escobar */ public class MBeanImpl implements DynamicMBean { - /** - * The object that is being instrumented. - */ - private Object object; - - /** - * Describes the exposed information of the object. - */ + /** + * The object that is being instrumented. + */ + private AbstractInstanceResolver resolver; + + /** + * Describes the exposed information of the object. + */ private MBeanInfo mBeanInfo; - + /** - * Constructor. Creates an instance using the Object instance that is going to be instrumented and the MBeanInfo - * that describes the exposed information from the object. - * + * Constructor. Creates an instance using the Object instance that is going to be instrumented and the MBeanInfo that describes + * the exposed information from the object. + * * @param object the object that is going to be instrumented. * @param mBeanInfo describes the exposed information of the object. */ - public MBeanImpl(Object object, MBeanInfo mBeanInfo) { - this.object = object; - this.mBeanInfo = mBeanInfo; + public MBeanImpl(AbstractInstanceResolver resolver, MBeanInfo mBeanInfo) { + this.resolver = resolver; + this.mBeanInfo = mBeanInfo; } @Override - public Object getAttribute(String attributeName) throws AttributeNotFoundException, MBeanException, - ReflectionException { - - // check attribute_name is not null to avoid NullPointerException later on - if (attributeName == null) { - throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name cannot be null"), - "Cannot invoke a getter of " + mBeanInfo.getClassName() + " with null attribute name"); - } - - MBeanAttributeInfo mBeanAttribute = findMBeanAttribute(attributeName); - if (mBeanAttribute == null) { - throw new AttributeNotFoundException("Cannot find " + attributeName + " attribute in " + - mBeanInfo.getClassName()); - } - - Method getterMethod = findGetterMethod( mBeanAttribute ); - if (getterMethod == null) { - throw new AttributeNotFoundException("Cannot find " + attributeName + " attribute or equivalent getter in " + - mBeanInfo.getClassName()); - } - - try { - return getterMethod.invoke(object); - } catch (Exception e) { - throw new MBeanException(e); - } + public Object getAttribute(String attributeName) throws AttributeNotFoundException, MBeanException, + ReflectionException { + + // check attribute_name is not null to avoid NullPointerException later on + if (attributeName == null) { + throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name cannot be null"), + "Cannot invoke a getter of " + mBeanInfo.getClassName() + " with null attribute name"); + } + + MBeanAttributeInfo mBeanAttribute = findMBeanAttribute(attributeName); + if (mBeanAttribute == null) { + throw new AttributeNotFoundException("Cannot find " + attributeName + " attribute in " + + mBeanInfo.getClassName()); + } + + Method getterMethod = findGetterMethod(mBeanAttribute); + if (getterMethod == null) { + throw new AttributeNotFoundException("Cannot find " + attributeName + " attribute or equivalent getter in " + + mBeanInfo.getClassName()); + } + + try { + return getterMethod.invoke(resolver.resolve()); + } catch (Exception e) { + throw new MBeanException(e); + } } - + @Override public AttributeList getAttributes(String[] attributesNames) { - - // check attributeNames is not null to avoid NullPointerException later on - if (attributesNames == null) { - throw new RuntimeOperationsException(new IllegalArgumentException("attributeNames[] cannot be null"), - "Cannot invoke a getter of " + mBeanInfo.getClassName()); - } - - AttributeList resultList = new AttributeList(); - - // if attributeNames is empty, return an empty result list - if (attributesNames.length == 0) { - return resultList; - } - - // build the result attribute list - for (int i=0 ; i < attributesNames.length ; i++){ - try { - Object value = getAttribute((String) attributesNames[i]); - resultList.add(new Attribute(attributesNames[i], value)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - return resultList; - + + // check attributeNames is not null to avoid NullPointerException later on + if (attributesNames == null) { + throw new RuntimeOperationsException(new IllegalArgumentException("attributeNames[] cannot be null"), + "Cannot invoke a getter of " + mBeanInfo.getClassName()); + } + + AttributeList resultList = new AttributeList(); + + // if attributeNames is empty, return an empty result list + if (attributesNames.length == 0) { + return resultList; + } + + // build the result attribute list + for (int i = 0; i < attributesNames.length; i++) { + try { + Object value = getAttribute(attributesNames[i]); + resultList.add(new Attribute(attributesNames[i], value)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return resultList; + } @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, - MBeanException, ReflectionException { - - // check attribute is not null to avoid NullPointerException later on - if (attribute == null) { - throw new RuntimeOperationsException(new IllegalArgumentException("Attribute cannot be null"), - "Cannot invoke a setter of " + mBeanInfo.getClassName() + " with null attribute"); - } - - String attributeName = attribute.getName(); - Object value = attribute.getValue(); - - if (attributeName == null) { - throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name cannot be null"), - "Cannot invoke the setter of " + mBeanInfo.getClassName() + " with null attribute name"); - } - - if (value == null) { - throw(new InvalidAttributeValueException("Cannot set attribute " + attributeName + " to null")); - } - - // try to set from the setter method - MBeanAttributeInfo mBeanAttribute = findMBeanAttribute(attributeName); - if (mBeanAttribute == null) { - throw new AttributeNotFoundException("Cannot find " + attributeName + " attribute in " + - mBeanInfo.getClassName()); - } - - Class type = null; - try { - type = findClass(mBeanAttribute.getType()); - if ( !isAssignable(type, value.getClass()) ) { - throw new InvalidAttributeValueException("Cannot set attribute "+ attributeName +" to a " + - value.getClass().getName() + " object, " + type.getName() + " expected"); - } - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - - Method setterMethod = findSetterMethod( mBeanAttribute, type ); - if (setterMethod == null) { - throw new RuntimeException("No setter method for attribute " + attributeName); - } - - try { - setterMethod.invoke(object, value); - } catch (Exception e) { - throw new MBeanException(e); - } - + MBeanException, ReflectionException { + + // check attribute is not null to avoid NullPointerException later on + if (attribute == null) { + throw new RuntimeOperationsException(new IllegalArgumentException("Attribute cannot be null"), + "Cannot invoke a setter of " + mBeanInfo.getClassName() + " with null attribute"); + } + + String attributeName = attribute.getName(); + Object value = attribute.getValue(); + + if (attributeName == null) { + throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name cannot be null"), + "Cannot invoke the setter of " + mBeanInfo.getClassName() + " with null attribute name"); + } + + if (value == null) { + throw (new InvalidAttributeValueException("Cannot set attribute " + attributeName + " to null")); + } + + // try to set from the setter method + MBeanAttributeInfo mBeanAttribute = findMBeanAttribute(attributeName); + if (mBeanAttribute == null) { + throw new AttributeNotFoundException("Cannot find " + attributeName + " attribute in " + + mBeanInfo.getClassName()); + } + + Class type = null; + try { + type = findClass(mBeanAttribute.getType()); + if (!isAssignable(type, value.getClass())) { + throw new InvalidAttributeValueException("Cannot set attribute " + attributeName + " to a " + + value.getClass().getName() + " object, " + type.getName() + " expected"); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + Method setterMethod = findSetterMethod(mBeanAttribute, type); + if (setterMethod == null) { + throw new RuntimeException("No setter method for attribute " + attributeName); + } + + try { + setterMethod.invoke(resolver.resolve(), value); + } catch (Exception e) { + throw new MBeanException(e); + } + } - + @Override public AttributeList setAttributes(AttributeList attributes) { - // check attributes is not null to avoid NullPointerException later on - if (attributes == null) { - throw new RuntimeOperationsException(new IllegalArgumentException("AttributeList attributes cannot be null"), - "Cannot invoke a setter of " + mBeanInfo.getClassName()); - } - - AttributeList resultList = new AttributeList(); - - // if attributeNames is empty, nothing more to do - if (attributes.isEmpty()) { - return resultList; - } - - // for each attribute, try to set it and add to the result list if successful - for (Iterator i = attributes.iterator(); i.hasNext();) { - Attribute attr = (Attribute) i.next(); - try { - setAttribute(attr); - String name = attr.getName(); - Object value = getAttribute(name); - resultList.add(new Attribute(name,value)); - } catch(Exception e) { - throw new RuntimeException(e); - } - } - - return resultList; + // check attributes is not null to avoid NullPointerException later on + if (attributes == null) { + throw new RuntimeOperationsException(new IllegalArgumentException("AttributeList attributes cannot be null"), + "Cannot invoke a setter of " + mBeanInfo.getClassName()); + } + + AttributeList resultList = new AttributeList(); + + // if attributeNames is empty, nothing more to do + if (attributes.isEmpty()) { + return resultList; + } + + // for each attribute, try to set it and add to the result list if successful + for (Iterator i = attributes.iterator(); i.hasNext();) { + Attribute attr = (Attribute) i.next(); + try { + setAttribute(attr); + String name = attr.getName(); + Object value = getAttribute(name); + resultList.add(new Attribute(name, value)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return resultList; } - + @Override - public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, - ReflectionException { - - // check operationName is not null to avoid NullPointerException later on - if (actionName == null) { - throw new RuntimeOperationsException(new IllegalArgumentException("Operation name cannot be null"), - "Cannot invoke a null operation in " + mBeanInfo.getClassName()); - } - - MBeanOperationInfo mBeanOperation = findMBeanOperation(actionName, signature); - if (mBeanOperation == null) { - throw new ReflectionException(new NoSuchMethodException(actionName), - "Cannot find the operation " + actionName + " with specified signature in " + - mBeanInfo.getClassName()); - } - - try { - - Method method = object.getClass().getMethod(actionName, getParametersTypes(signature)); - return method.invoke(object, params); - - } catch (NoSuchMethodException e) { - throw new ReflectionException(e); - } catch (Exception e) { - throw new ReflectionException(e); - } + public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, + ReflectionException { + + // check operationName is not null to avoid NullPointerException later on + if (actionName == null) { + throw new RuntimeOperationsException(new IllegalArgumentException("Operation name cannot be null"), + "Cannot invoke a null operation in " + mBeanInfo.getClassName()); + } + + MBeanOperationInfo mBeanOperation = findMBeanOperation(actionName, signature); + if (mBeanOperation == null) { + throw new ReflectionException(new NoSuchMethodException(actionName), + "Cannot find the operation " + actionName + " with specified signature in " + + mBeanInfo.getClassName()); + } + + try { + + Method method = resolver.resolve().getClass().getMethod(actionName, getParametersTypes(signature)); + return method.invoke(resolver.resolve(), params); + + } catch (NoSuchMethodException e) { + throw new ReflectionException(e); + } catch (Exception e) { + throw new ReflectionException(e); + } } - + private Class[] getParametersTypes(String[] signature) throws ClassNotFoundException { - - if (signature == null) { - return null; - } - - Class[] paramTypes = new Class[signature.length]; - for (int i=0; i < signature.length; i++) { - paramTypes[i] = findClass( signature[i] ); - } - - return paramTypes; + + if (signature == null) { + return null; + } + + Class[] paramTypes = new Class[signature.length]; + for (int i = 0; i < signature.length; i++) { + paramTypes[i] = findClass(signature[i]); + } + + return paramTypes; } - + @Override public MBeanInfo getMBeanInfo() { - return mBeanInfo; + return mBeanInfo; } - + /** - * Helper method. Tries to find the MBeanAttributeInfo from the mBeanInfo instance variable. - * + * Helper method. Tries to find the MBeanAttributeInfo from the mBeanInfo instance variable. + * * @param attributeName the name of the attribute we are looking for. - * + * * @return the MBeanAttributeInfo for the attribute name or null if not found. */ private MBeanAttributeInfo findMBeanAttribute(String attributeName) { - - MBeanAttributeInfo[] mBeanAttributes = mBeanInfo.getAttributes(); - for (MBeanAttributeInfo mBeanAttribute : mBeanAttributes) { - - if (mBeanAttribute.getName().equals(attributeName)) { - return mBeanAttribute; - } - - } - - return null; + + MBeanAttributeInfo[] mBeanAttributes = mBeanInfo.getAttributes(); + for (MBeanAttributeInfo mBeanAttribute : mBeanAttributes) { + + if (mBeanAttribute.getName().equals(attributeName)) { + return mBeanAttribute; + } + + } + + return null; } - + /** - * Helper method. Tries to find the MBeanOperationInfo from the mBeanInfo instance - * variable. - * + * Helper method. Tries to find the + * MBeanOperationInfo from the + * mBeanInfo instance variable. + * * @param operationName the name of the operation we are looking for. * @param receivedSignature the signature of the operation we are looking for. - * - * @return the MBeanOperationInfo that matches the operationName and receivedSignature. + * + * @return the MBeanOperationInfo that matches the operationName and receivedSignature. */ private MBeanOperationInfo findMBeanOperation(String operationName, String[] receivedSignature) { - - MBeanOperationInfo[] mBeanOperations = mBeanInfo.getOperations(); - for (MBeanOperationInfo mBeanOperation : mBeanOperations) { - - if (mBeanOperation.getName().equals(operationName) - && isAssignableSignature(mBeanOperation.getSignature(), receivedSignature) ) { - return mBeanOperation; - } - - } - - return null; + + MBeanOperationInfo[] mBeanOperations = mBeanInfo.getOperations(); + for (MBeanOperationInfo mBeanOperation : mBeanOperations) { + + if (mBeanOperation.getName().equals(operationName) + && isAssignableSignature(mBeanOperation.getSignature(), receivedSignature)) { + return mBeanOperation; + } + + } + + return null; } - + /** - * Helper method. Validates if the receivedSignature is assignable to the + * Helper method. Validates if the + * receivedSignature is assignable to the * operationSignature. - * + * * @param operationSignature the signature of the operation. * @param receivedSignature the received signature. - * + * * @return true if the receivedSignature is assignable to the operationSignature. */ private boolean isAssignableSignature(MBeanParameterInfo[] operationSignature, String[] receivedSignature) { - - if (operationSignature == null && receivedSignature == null) { - return true; - } - - if ( (operationSignature == null && receivedSignature != null) - || (operationSignature != null && receivedSignature == null) ) { - return false; - } - - if (operationSignature.length != receivedSignature.length) { - return false; - } - - try { - for (int i=0; i < operationSignature.length; i++) { - - Class operationParamClass = findClass( operationSignature[i].getType() ); - Class receivedParamClass = findClass( receivedSignature[i] ); - - if ( !isAssignable(operationParamClass, receivedParamClass) ) { - return false; - } - } - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - - return true; + + if (operationSignature == null && receivedSignature == null) { + return true; + } + + if ((operationSignature == null && receivedSignature != null) + || (operationSignature != null && receivedSignature == null)) { + return false; + } + + if (operationSignature.length != receivedSignature.length) { + return false; + } + + try { + for (int i = 0; i < operationSignature.length; i++) { + + Class operationParamClass = findClass(operationSignature[i].getType()); + Class receivedParamClass = findClass(receivedSignature[i]); + + if (!isAssignable(operationParamClass, receivedParamClass)) { + return false; + } + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + return true; } - + /** - * Helper method. Tries to find a getter method from the instrumented object using the mBeanAttribute + * Helper method. Tries to find a getter method from the instrumented object using the + * mBeanAttribute * info. - * + * * @param mBeanAttribute the MBeanAttributeInfo from which we are trying to find the getter method. - * + * * @return a java.lang.reflect.Method object that represents the getter method; null if no match. */ private Method findGetterMethod(MBeanAttributeInfo mBeanAttribute) { - String prefix = "get"; - if (mBeanAttribute.isIs()) { - prefix = "is"; - } - - try { - return object.getClass().getMethod( prefix + capitalize(mBeanAttribute.getName()) ); - } catch (NoSuchMethodException e) { - return null; - } - + String prefix = "get"; + if (mBeanAttribute.isIs()) { + prefix = "is"; + } + + try { + return resolver.resolve().getClass().getMethod(prefix + capitalize(mBeanAttribute.getName())); + } catch (NoSuchMethodException e) { + return null; + } + } - + /** - * Helper method. Tries to find a setter method from the instrumented object using the mBeanAttribute - * and the paramType. - * + * Helper method. Tries to find a setter method from the instrumented object using the + * mBeanAttribute and the + * paramType. + * * @param mBeanAttribute the MBeanAttributeInfo from which we are trying to find the setter method. * @param attributeType the class of the attribute. - * + * * @return a java.lang.reflect.Method object that represents the setter method; null if no match. */ private Method findSetterMethod(MBeanAttributeInfo mBeanAttribute, Class attributeType) { - - try { - return object.getClass().getMethod( "set" + capitalize(mBeanAttribute.getName()), attributeType); - } catch (NoSuchMethodException e) { - return null; - } - + + try { + return resolver.resolve().getClass().getMethod("set" + capitalize(mBeanAttribute.getName()), attributeType); + } catch (NoSuchMethodException e) { + return null; + } + } - + /** - * Helper method. Finds a class from its class name. - * + * Helper method. Finds a class from its class name. + * * @param className * @return * @throws ClassNotFoundException */ private Class findClass(String className) throws ClassNotFoundException { - - if (className == null) { - throw new ClassNotFoundException(className); - } - - if (Integer.TYPE.getName().equals(className)) { - return Integer.TYPE; - } else if (Byte.TYPE.getName().equals(className)) { - return Byte.TYPE; - } else if (Short.TYPE.getName().equals(className)) { - return Short.TYPE; - } else if (Long.TYPE.getName().equals(className)) { - return Long.TYPE; - } else if (Float.TYPE.getName().equals(className)) { - return Float.TYPE; - } else if (Double.TYPE.getName().equals(className)) { - return Double.TYPE; - } else if (Boolean.TYPE.getName().equals(className)) { - return Boolean.TYPE; - } else if (Character.TYPE.getName().equals(className)) { - return Character.TYPE; - } - - return Class.forName(className); - + + if (className == null) { + throw new ClassNotFoundException(className); + } + + if (Integer.TYPE.getName().equals(className)) { + return Integer.TYPE; + } else if (Byte.TYPE.getName().equals(className)) { + return Byte.TYPE; + } else if (Short.TYPE.getName().equals(className)) { + return Short.TYPE; + } else if (Long.TYPE.getName().equals(className)) { + return Long.TYPE; + } else if (Float.TYPE.getName().equals(className)) { + return Float.TYPE; + } else if (Double.TYPE.getName().equals(className)) { + return Double.TYPE; + } else if (Boolean.TYPE.getName().equals(className)) { + return Boolean.TYPE; + } else if (Character.TYPE.getName().equals(className)) { + return Character.TYPE; + } + + return Class.forName(className); + } - + /** - * Helper method. Checks if a class is assignable to another (i.e. the class must be the same or a subclass). - * Actually, the test is done using the Class.isAssignableFrom(Class) method. - * + * Helper method. Checks if a class is assignable to another (i.e. the class must be the same or a subclass). Actually, the test + * is done using the Class.isAssignableFrom(Class) method. + * * @param to the class to which we are assigning. - * @param from the class from which we are assigning. - * + * @param from the class from which we are assigning. + * * @return true if the from class is assignable to the to class. */ private boolean isAssignable(final Class to, final Class from) { - - if (to == null) { - throw new IllegalArgumentException("no to class specified"); - } - - if (from == null) { - throw new IllegalArgumentException("no from class specified"); - } - - Class toClass = to; - if (toClass.isPrimitive()) { - toClass = fromPrimitiveToObject(toClass); - } - - Class fromClass = from; - if (fromClass.isPrimitive()) { - fromClass = fromPrimitiveToObject(fromClass); - } - - return toClass.isAssignableFrom(fromClass); + + if (to == null) { + throw new IllegalArgumentException("no to class specified"); + } + + if (from == null) { + throw new IllegalArgumentException("no from class specified"); + } + + Class toClass = to; + if (toClass.isPrimitive()) { + toClass = fromPrimitiveToObject(toClass); + } + + Class fromClass = from; + if (fromClass.isPrimitive()) { + fromClass = fromPrimitiveToObject(fromClass); + } + + return toClass.isAssignableFrom(fromClass); } - + /** * Returns the wrapper class of the primitive class. - * + * * @param primitive the primitive class for which we are looking the wrapper. - * + * * @return the wrapper class of the primitive or the same class if not a primitive. */ private Class fromPrimitiveToObject(Class primitive) { - - if (primitive.equals(Integer.TYPE)) { - return Integer.class; - } else if (primitive.equals(Byte.TYPE)) { - return Byte.class; - } else if (primitive.equals(Short.TYPE)) { - return Short.class; - } else if (primitive.equals(Long.TYPE)) { - return Long.class; - } else if (primitive.equals(Float.TYPE)) { - return Float.class; - } else if (primitive.equals(Double.TYPE)) { - return Double.class; - } else if (primitive.equals(Boolean.TYPE)) { - return Boolean.class; - } else if (primitive.equals(Character.TYPE)) { - return Character.class; - } - - return primitive; - } + if (primitive.equals(Integer.TYPE)) { + return Integer.class; + } else if (primitive.equals(Byte.TYPE)) { + return Byte.class; + } else if (primitive.equals(Short.TYPE)) { + return Short.class; + } else if (primitive.equals(Long.TYPE)) { + return Long.class; + } else if (primitive.equals(Float.TYPE)) { + return Float.class; + } else if (primitive.equals(Double.TYPE)) { + return Double.class; + } else if (primitive.equals(Boolean.TYPE)) { + return Boolean.class; + } else if (primitive.equals(Character.TYPE)) { + return Character.class; + } + + return primitive; + } }