/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.apmrouter.util;
import java.beans.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <p>Title: BeanHelper</p>
* <p>Description: A set of generic bean helper operations.</p>
* <p>Company: Helios Development Group</p>
* @author Whitehead (whitehead.nicholas@gmail.com)
* @version $LastChangedRevision: 222 $
* $HeadURL: https://helios.dev.java.net/svn/helios/helios-utils/trunk/src/org/helios/helpers/BeanHelper.java $
* $Id: BeanHelper.java 222 2008-07-08 21:05:12Z nwhitehead $
*/
public class BeanHelper {
/**
* Locates the PropertyDescriptor for the passed name in the passed class.
* @param targetType
* @param name
* @return A PropertyDescriptor
*/
public static PropertyDescriptor getPropertyDescriptor(Class<?> targetType, String name) {
String dName = Introspector.decapitalize(name);
try {
BeanInfo bi = Introspector.getBeanInfo(targetType);
for(PropertyDescriptor pd: bi.getPropertyDescriptors()) {
if(pd.getName().equals(dName)) {
return pd;
}
}
throw new Exception("No PropertyDescriptor found for " + name);
} catch (Exception e) {
throw new RuntimeException("Failed to Acquire PropertyDescriptor for [" + targetType.getName() + "/" + name + "]", e);
}
}
/**
* Determines the type of the named parameter for the passed type.
* @param targetType The target type to invoke against.
* @param name The attribute name.
* @return The class of the parameter type
*/
public static Class<?> getAttributeType(Class<?> targetType, String name) {
PropertyDescriptor pd = getPropertyDescriptor(targetType, name);
return pd.getPropertyType();
}
/**
* Sets an attribute on the passed object instance.
* @param name The name of the attribute.
* @param value The string value.
* @param target The object instance to set on.
*/
public static void setAttribute(String name, String value, Object target) {
try {
Class<?> targetType = getAttributeType(target.getClass(), name);
PropertyEditor propertyEditor = PropertyEditorManager.findEditor(targetType);
if(propertyEditor==null) throw new RuntimeException("No PropertyEditor Found for type [" + targetType.getName() + "] in object of type + [" + target.getClass().getName() + "]" );
propertyEditor.setAsText(value);
Object typedValue = propertyEditor.getValue();
Expression expression = new Expression(target, getPropertyDescriptor(target.getClass(), name).getWriteMethod().getName(), new Object[]{typedValue});
expression.execute();
} catch (Exception e) {
throw new RuntimeException("Failed to set attribute [" + name + "] on instance of [" + target.getClass().getName() + "]");
}
}
/**
* Returns the value of the named attribute from the passed pojo.
* @param name The name of the attribute.
* @param target The target pojo to retrieve the value from.
* @return the value of the named attribute.
*/
public static Object getAttribute(String name, Object target) {
try {
Class<?> targetType = getAttributeType(target.getClass(), name);
PropertyEditor propertyEditor = PropertyEditorManager.findEditor(targetType);
if(propertyEditor==null) throw new RuntimeException("No PropertyEditor Found for type [" + targetType.getName() + "] in object of type + [" + target.getClass().getName() + "]" );
Expression expression = new Expression(target, getPropertyDescriptor(target.getClass(), name).getReadMethod().getName(), new Object[]{});
expression.execute();
return expression.getValue();
} catch (Exception e) {
throw new RuntimeException("Failed to get attribute [" + name + "] on instance of [" + target.getClass().getName() + "]");
}
}
public static Object getInstance(String className, Object...args) {
try {
Class<?> clazz = Class.forName(className);
Class<?>[] sig = new Class[args.length];
for(int i = 0; i < args.length; i++) {
sig[i] = args[i].getClass();
}
Constructor<?> ctor = clazz.getConstructor(sig);
return ctor.newInstance(args);
} catch (Throwable t) {
throw new RuntimeException("Failed to create test pojo:" + className, t);
}
}
public static BeanInfo getBeanInfo(Object pojo) {
try {
return Introspector.getBeanInfo(pojo.getClass());
} catch (Exception e) {
throw new RuntimeException("Failed to create bean info", e);
}
}
public static BeanDescriptor getBeanDescriptor(Object pojo) {
try {
return new BeanDescriptor(pojo.getClass());
} catch (Exception e) {
throw new RuntimeException("Failed to create bean descriptor", e);
}
}
public static String[] repeatingArr(String value, int times) {
String[] arr = new String[times];
for(int i =0; i < times; i++) {
arr[i] = value;
}
return arr;
}
/**
* Gets a complete list of all a pojo's attribute names.
* <code>@JMXAttribute</code> annotations are ignored.
* @param pojo
* @param exclude attributes defined in Object class.
* @return A list of pojo attribute names.
*/
public static List<String> getPojoBeanAttributes(Object pojo, boolean declared) {
BeanInfo bi = getBeanInfo(pojo);
List<String> list = new ArrayList<String>();
for(PropertyDescriptor pd : bi.getPropertyDescriptors()) {
list.add(pd.getName());
}
if(pojo.getClass()!=Object.class) {
list.removeAll(getPojoBeanAttributes(new Object(), false));
}
return list;
}
/**
* Gets a complete list of all a pojo's attribute names.
* <code>@JMXAttribute</code> annotations are ignored.
* Declared defaults to true.
* @param pojo
* @return A list of pojo attribute names.
*/
public static List<String> getPojoBeanAttributes(Object pojo) {
return getPojoBeanAttributes(pojo, true);
}
/**
* Returns an alpha sorted string array of a pojo's attribute names.
* @param pojo
* @return A string array of attribute names.
*/
public static String[] getPojoAttributeTypes(Object pojo) {
List<String> list = new ArrayList<String>();
for(PropertyDescriptor pd : getPropertyDescriptors(pojo)) {
if(pd.getReadMethod()!=null) {
list.add(pd.getReadMethod().getReturnType().getName());
} else {
list.add(pd.getWriteMethod().getReturnType().getName());
}
}
Collections.sort(list);
return list.toArray(new String[list.size()]);
}
/**
* Returns a list of all of a pojo's <code>PropertyDescriptor</code>s
* @param pojo
* @return A list of <code>PropertyDescriptor</code>s.
*/
public static List<PropertyDescriptor> getAllPropertyDescriptors(Object pojo) {
List<PropertyDescriptor> list = new ArrayList<PropertyDescriptor>();
BeanInfo bi = getBeanInfo(pojo);
for(PropertyDescriptor pd : bi.getPropertyDescriptors()) {
list.add(pd);
}
return list;
}
/**
* Sorts an array of objects that implement the comparable interface.
* @param args An array of objects.
* @return An array of objects sorted by their natural order.
*/
@SuppressWarnings("unchecked")
public static Object[] sortArray(Object...args) {
List<Comparable> list = new ArrayList<Comparable>(args.length);
for(Object o: args) {list.add((Comparable)o);}
Collections.sort(list);
return list.toArray(new Object[list.size()]);
}
/**
* Sorts an array of objects that implement the comparable interface and returns a typed array specified by the class passed.
* @param arrayType
* @param args
* @return An array of objects sorted by their natural order.
*/
@SuppressWarnings("unchecked")
public static Object sortArray(Class arrayType, Object...args) {
List<Comparable> list = new ArrayList<Comparable>(args.length);
for(Object o: args) {list.add((Comparable)o);}
Collections.sort(list);
Object arrObject = Array.newInstance(arrayType, list.size());
for(int i = 0; i < list.size(); i++) {
Array.set(arrObject, i, list.get(i));
}
return arrObject;
}
/**
* Returns a list of a pojo's <code>PropertyDescriptor</code>s minus the same for <code>java.lang.Object</code>.
* @param pojo
* @return A list of <code>PropertyDescriptor</code>s.
*/
public static List<PropertyDescriptor> getPropertyDescriptors(Object pojo) {
List<PropertyDescriptor> list = getAllPropertyDescriptors(pojo);
List<PropertyDescriptor> objList = getAllPropertyDescriptors(new Object());
list.removeAll(objList);
return list;
}
/**
* Constructs an object of the passed class name from the passed string.
* @param targetClassName The class name of the object to be created.
* @param value The string to be used to construct the return object.
* @return The constructed object.
*/
public static Object stringToObject(String targetClassName, String value) {
Object object = null;
String arrayType = null;
String[] arrayElements = null;
Object convertedArrayElement = null;
Object returnArray = null;
Class<?> arrayClass = null;
try {
if(targetClassName.startsWith("[L") && targetClassName.endsWith(";")) {
arrayType = targetClassName.replace("[L", "");
arrayType = arrayType.replace(";", "");
arrayClass = Class.forName(targetClassName, false, BeanHelper.class.getClassLoader()).getComponentType();
arrayElements = value.split(",");
returnArray = Array.newInstance(arrayClass, arrayElements.length);
int index=0;
for(String s: arrayElements) {
convertedArrayElement = stringToObject(arrayType, s);
Array.set(returnArray, index, convertedArrayElement);
index++;
}
object = returnArray;
} else if("java.lang.String".equals(targetClassName) || "java.lang.Object".equals(targetClassName)) {
object = value;
} else if("java.lang.Boolean".equals(targetClassName) || "boolean".equals(targetClassName)) {
object = Boolean.valueOf(value);
} else if("java.lang.Byte".equals(targetClassName) || "byte".equals(targetClassName)) {
object = new Byte(value);
} else if("java.lang.Character".equals(targetClassName) || "char".equals(targetClassName)) {
object = Character.valueOf(value.charAt(0));
} else if("java.lang.Class".equals(targetClassName)) {
object = Class.forName(value);
} else if("java.lang.Double".equals(targetClassName) || "double".equals(targetClassName)) {
object = new Double(value);
} else if("java.lang.Float".equals(targetClassName) || "float".equals(targetClassName)) {
object = new Float(value);
} else if("java.lang.Integer".equals(targetClassName) || "int".equals(targetClassName)) {
object = new Integer(value);
} else if("java.lang.Long".equals(targetClassName) || "long".equals(targetClassName)) {
object = new Long(value);
} else {
throw new Exception("Unsupported Conversion Type[" + targetClassName + "]. Please Update " + BeanHelper.class.getName() + ".stringToObject Method");
}
return object;
} catch (Exception e) {
throw new RuntimeException("Failed to convert value [" + value + "] to an object of type [" + targetClassName + "]", e);
}
}
}