1081 lines
40 KiB
Java
1081 lines
40 KiB
Java
package eva2.gui;
|
|
|
|
import eva2.optimization.population.Population;
|
|
import eva2.optimization.strategies.GeneticAlgorithm;
|
|
import eva2.tools.Pair;
|
|
import eva2.tools.SelectedTag;
|
|
import eva2.tools.StringTools;
|
|
import eva2.tools.Tag;
|
|
import eva2.util.annotation.Description;
|
|
|
|
import java.beans.*;
|
|
import java.lang.reflect.Array;
|
|
import java.lang.reflect.Method;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
/**
|
|
* Some miscellaneous functions to help with Beans, reflection, conversion and
|
|
* generic display.
|
|
*
|
|
* @author mkron, Holger Ulmer, Felix Streichert, Hannes Planatscher
|
|
*/
|
|
public class BeanInspector {
|
|
private static final Logger LOGGER = Logger.getLogger(BeanInspector.class.getName());
|
|
|
|
/**
|
|
* Check for equality based on bean properties of two target objects.
|
|
*/
|
|
public static boolean equalProperties(Object obj1, Object obj2) {
|
|
if (obj1 == null || obj2 == null) {
|
|
System.out.println("");
|
|
return false;
|
|
}
|
|
System.out.println("equalProperties: " + obj1.getClass().getName() + " " + obj2.getClass().getName());
|
|
if (obj1.getClass().getName().equals(obj2.getClass().getName()) == false) {
|
|
System.out.println("");
|
|
return false;
|
|
}
|
|
// compare each of the properties !!
|
|
BeanInfo beanInfo1;
|
|
BeanInfo beanInfo2;
|
|
PropertyDescriptor[] Properties_1 = null;
|
|
PropertyDescriptor[] Properties_2 = null;
|
|
try {
|
|
|
|
beanInfo1 = Introspector.getBeanInfo(obj1.getClass());
|
|
beanInfo2 = Introspector.getBeanInfo(obj2.getClass());
|
|
Properties_1 = beanInfo1.getPropertyDescriptors();
|
|
Properties_2 = beanInfo2.getPropertyDescriptors();
|
|
beanInfo1.getMethodDescriptors();
|
|
} catch (IntrospectionException ex) {
|
|
LOGGER.log(Level.FINEST, "Could not introspect object.", ex);
|
|
return false;
|
|
}
|
|
boolean BeansInside = false;
|
|
boolean BeansEqual = true;
|
|
for (int i = 0; i < Properties_1.length; i++) {
|
|
if (Properties_1[i].isHidden() || Properties_1[i].isExpert()) {
|
|
continue;
|
|
}
|
|
//String name = Properties_1[i].getDisplayName(); //System.out.println("name = "+name );
|
|
//Class type = Properties_1[i].getPropertyType(); //System.out.println("type = "+type.getName() );
|
|
Method getter_1 = Properties_1[i].getReadMethod();
|
|
Method getter_2 = Properties_2[i].getReadMethod();
|
|
Method setter_1 = Properties_1[i].getWriteMethod();
|
|
// Only display read/write properties.
|
|
if (getter_1 == null || setter_1 == null) {
|
|
continue;
|
|
}
|
|
System.out.println("getter_1 = " + getter_1.getName() + " getter_2 = " + getter_2.getName());
|
|
//System.out.println("type = "+type.getName() );
|
|
Object args_1[] = {};
|
|
Object args_2[] = {};
|
|
//System.out.println("m_Target"+m_Target.toString());
|
|
try {
|
|
Object value_1 = getter_1.invoke(obj1, args_1);
|
|
Object value_2 = getter_2.invoke(obj2, args_2);
|
|
BeansInside = true;
|
|
if (BeanInspector.equalProperties(value_1, value_2) == false) {
|
|
BeansEqual = false;
|
|
}
|
|
} catch (Exception e) {
|
|
System.out.println(" BeanTest.equalProperties " + e.getMessage());
|
|
}
|
|
}
|
|
if (BeansInside == true) {
|
|
return BeansEqual;
|
|
}
|
|
// here we have Integer or Double ...
|
|
if (obj1 instanceof Integer
|
|
|| obj1 instanceof Boolean
|
|
|| obj1 instanceof Float
|
|
|| obj1 instanceof Double
|
|
|| obj1 instanceof Long
|
|
|| obj1 instanceof String) {
|
|
return obj1.equals(obj2);
|
|
}
|
|
|
|
System.err.println(" Attention no match !!!");
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Produce a String representation of an arbitrary object.
|
|
*
|
|
* @param obj
|
|
* @return
|
|
* @see #toString(Object, char, boolean, String)
|
|
*/
|
|
public static String toString(Object obj) {
|
|
return toString(obj, ';', false, "", 1, false);
|
|
}
|
|
|
|
/**
|
|
* Produce a string with newlines and indentation (easier readable for if an
|
|
* object has many properties).
|
|
*
|
|
* @param obj
|
|
* @return
|
|
*/
|
|
public static String niceToString(Object obj) {
|
|
return toString(obj, ';', false, " ", 1, true);
|
|
}
|
|
|
|
/**
|
|
* Collect the accessible properties of an object and their values in a
|
|
* string with indentations. Special cases: Arrays and Lists are
|
|
* concatenations of their elements, Population is excepted from lists. If
|
|
* the object has its own toString method, this one is preferred. Hidden or
|
|
* expert properties are not shown.
|
|
*
|
|
* @param obj an arbitrary object
|
|
* @return a String description of the object
|
|
*/
|
|
public static String toString(Object obj, char delim, boolean tight, String indentStr) {
|
|
return toString(obj, delim, tight, indentStr, 1, false);
|
|
}
|
|
|
|
/**
|
|
* Collect the accessible properties of an object and their values in a
|
|
* string. Special cases: Arrays and Lists are concatenations of their
|
|
* elements, Population is excepted from lists. If the object has its own
|
|
* toString method, this one is preferred. Hidden or expert properties are
|
|
* not shown.
|
|
*
|
|
* @param obj Description of the Parameter
|
|
* @return Description of the Return Value
|
|
*/
|
|
private static String toString(Object obj, char delim, boolean tight, String indentStr, int indentDepth, boolean withNewlines) {
|
|
if (obj == null) {
|
|
return "null";
|
|
}
|
|
// try the object itself
|
|
if (obj instanceof String) {
|
|
return (String) obj;
|
|
} // directly return a string object
|
|
Class<? extends Object> type = obj.getClass();
|
|
|
|
if (type.isArray()) { // handle the array case
|
|
StringBuffer sbuf = new StringBuffer();
|
|
sbuf.append("[");
|
|
if (!tight) {
|
|
sbuf.append(" ");
|
|
}
|
|
int len = Array.getLength(obj);
|
|
for (int i = 0; i < len; i++) {
|
|
// sbuf.append(toString(Array.get(obj, i)));
|
|
if (withNewlines) {
|
|
sbuf.append('\n');
|
|
}
|
|
sbuf.append(toString(Array.get(obj, i), delim, tight, indentStr, indentDepth, withNewlines));
|
|
if (i < len - 1) {
|
|
// sbuf.append(delim);
|
|
if (!tight) {
|
|
sbuf.append(" ");
|
|
}
|
|
}
|
|
}
|
|
if (!tight) {
|
|
sbuf.append(" ");
|
|
}
|
|
sbuf.append("]");
|
|
return sbuf.toString();
|
|
}
|
|
|
|
if (type.isEnum()) {
|
|
return makeIndent(indentStr, indentDepth) + obj.toString();
|
|
}
|
|
|
|
if (obj instanceof List && !(obj instanceof Population)) { // handle the list case
|
|
StringBuffer sbuf = new StringBuffer();
|
|
if (withNewlines) {
|
|
sbuf.append('\n');
|
|
}
|
|
addIndent(sbuf, indentStr, indentDepth);
|
|
sbuf.append("[");
|
|
if (!tight) {
|
|
sbuf.append(" ");
|
|
}
|
|
List<?> lst = (List<?>) obj;
|
|
for (Object o : lst) {
|
|
sbuf.append(o.toString());
|
|
sbuf.append(delim);
|
|
if (!tight) {
|
|
sbuf.append(" ");
|
|
}
|
|
}
|
|
if (!tight && (sbuf.charAt(sbuf.length() - 2) == delim)) {
|
|
sbuf.setCharAt(sbuf.length() - 2, ' ');
|
|
} // delete the delim
|
|
sbuf.setCharAt(sbuf.length() - 1, ']');
|
|
return sbuf.toString();
|
|
}
|
|
|
|
Method[] methods = obj.getClass().getDeclaredMethods();
|
|
for (int ii = 0; ii < methods.length; ii++) { // check if the object has its own toString method, in this case use it
|
|
if ((methods[ii].getName().equals("toString") /*|| (methods[ii].getName().equals("getStringRepresentation"))*/) && (methods[ii].getParameterTypes().length == 0)) {
|
|
Object[] args = new Object[0];
|
|
//args[0] = obj;
|
|
try {
|
|
String ret = (String) methods[ii].invoke(obj, args);
|
|
return makeIndent(indentStr, indentDepth) + ret;
|
|
} catch (Exception e) {
|
|
System.err.println(" ERROR +" + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
// otherwise try introspection and collect all public properties as strings
|
|
|
|
Pair<String[], Object[]> nameVals = getPublicPropertiesOf(obj, true, true);
|
|
|
|
StringBuffer sbuf = new StringBuffer();
|
|
if (withNewlines) {
|
|
sbuf.append('\n');
|
|
}
|
|
addIndent(sbuf, indentStr, indentDepth);
|
|
sbuf.append(type.getName());
|
|
sbuf.append("{");
|
|
for (int i = 0; i < nameVals.head.length; i++) {
|
|
if (nameVals.head[i] != null) {
|
|
if (withNewlines) {
|
|
sbuf.append('\n');
|
|
}
|
|
addIndent(sbuf, indentStr, indentDepth);
|
|
sbuf.append(nameVals.head[i]);
|
|
sbuf.append("=");
|
|
sbuf.append(toString(nameVals.tail[i], delim, tight, indentStr, indentDepth + 1, withNewlines));
|
|
sbuf.append(delim);
|
|
if (!tight) {
|
|
sbuf.append(" ");
|
|
}
|
|
}
|
|
}
|
|
|
|
sbuf.append("}");
|
|
return sbuf.toString();
|
|
}
|
|
|
|
private static void addIndent(StringBuffer sbuf, String indentStr, int indentDepth) {
|
|
if (indentStr != null && (indentDepth > 0)) {
|
|
for (int i = 0; i < indentDepth; i++) {
|
|
sbuf.append(indentStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static String makeIndent(String indentStr, int indentDepth) {
|
|
if (indentStr != null) {
|
|
if (indentDepth < 1) {
|
|
return "";
|
|
} else {
|
|
StringBuffer sbuf = new StringBuffer(indentStr);
|
|
for (int i = 2; i <= indentDepth; i++) {
|
|
sbuf.append(indentStr);
|
|
}
|
|
return sbuf.toString();
|
|
}
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println(BeanInspector.toString(new String[]{"asdf", "jdksfl", "werljk"}));
|
|
|
|
System.out.println(BeanInspector.toString(new Population()));
|
|
System.out.println(BeanInspector.toString(new GeneticAlgorithm()));
|
|
System.out.println("----");
|
|
System.out.println(BeanInspector.niceToString(new Population()));
|
|
System.out.println(BeanInspector.niceToString(new GeneticAlgorithm()));
|
|
System.out.println("----");
|
|
System.out.println(BeanInspector.toString(new Population(), ';', false, ">", 1, false));
|
|
System.out.println(BeanInspector.toString(new GeneticAlgorithm(), ';', false, ">", 1, false));
|
|
// System.out.println(BeanInspector.toString(new Population(), ',', false, "\t"));
|
|
// System.out.println(BeanInspector.toString(new GeneticAlgorithm(), ',', false, "\t"));
|
|
}
|
|
|
|
/**
|
|
* Retrieve names and values of instance fields which are accessible by
|
|
* getter method, optionally by both getter and setter method. The returned
|
|
* arrays may contain null entries. Properties marked as hidden or expert
|
|
* are skipped.
|
|
*
|
|
* @param target
|
|
* @return
|
|
*/
|
|
public static Pair<String[], Object[]> getPublicPropertiesOf(Object target, boolean requireSetter, boolean showHidden) {
|
|
BeanInfo Info = null;
|
|
PropertyDescriptor[] Properties = null;
|
|
// MethodDescriptor[] Methods = null;
|
|
try {
|
|
Info = Introspector.getBeanInfo(target.getClass());
|
|
Properties = Info.getPropertyDescriptors();
|
|
Info.getMethodDescriptors();
|
|
} catch (IntrospectionException ex) {
|
|
System.err.println("BeanTest: Couldn't introspect");
|
|
return null;
|
|
}
|
|
|
|
String[] nameArray = new String[Properties.length];
|
|
Object[] valArray = new Object[Properties.length];
|
|
for (int i = 0; i < Properties.length; i++) {
|
|
if ((Properties[i].isHidden() && !showHidden) || Properties[i].isExpert()) {
|
|
// System.err.println(Properties[i].getDisplayName() + " is " + ( (Properties[i].isExpert())? "expert": "hidden"));
|
|
continue;
|
|
}
|
|
String name = Properties[i].getDisplayName();
|
|
//System.out.println("name = "+name );
|
|
//Class type = Properties[i].getPropertyType();
|
|
//System.out.println("type = "+type.getName() );
|
|
Method getter = Properties[i].getReadMethod();
|
|
Method setter = Properties[i].getWriteMethod();
|
|
// Only display read/write properties.
|
|
if (getter == null || (setter == null && requireSetter)) {
|
|
continue;
|
|
}
|
|
//System.out.println("name = "+name );
|
|
//System.out.println("type = "+type.getName() );
|
|
Object args[] = {};
|
|
//System.out.println("m_obj"+m_obj.toString());
|
|
|
|
try {
|
|
nameArray[i] = name;
|
|
valArray[i] = getter.invoke(target, args);
|
|
} catch (Exception e) {
|
|
System.err.println("BeanTest ERROR +" + e.getMessage());
|
|
}
|
|
}
|
|
Pair<String[], Object[]> nameVals = new Pair<String[], Object[]>(nameArray, valArray);
|
|
return nameVals;
|
|
}
|
|
|
|
/**
|
|
* @param obj Description of the Parameter
|
|
*/
|
|
public static void showInfo(Object obj) {
|
|
System.out.println("Inspecting " + obj.getClass().getName());
|
|
// object itself
|
|
try {
|
|
if (obj instanceof java.lang.Integer) {
|
|
System.out.println(" Prop = Integer" + obj.toString());
|
|
}
|
|
if (obj instanceof java.lang.Boolean) {
|
|
System.out.println(" Prop = Boolean" + obj.toString());
|
|
}
|
|
if (obj instanceof java.lang.Long) {
|
|
System.out.println(" Prop = Long" + obj.toString());
|
|
}
|
|
if (obj instanceof java.lang.Double) {
|
|
System.out.println(" Prop = Long" + obj.toString());
|
|
}
|
|
} catch (Exception e) {
|
|
//System.out.println(" ERROR +"+ e.getMessage());
|
|
}
|
|
// then the properties
|
|
BeanInfo Info = null;
|
|
PropertyDescriptor[] Properties = null;
|
|
// MethodDescriptor[] Methods = null;
|
|
try {
|
|
Info = Introspector.getBeanInfo(obj.getClass());
|
|
Properties = Info.getPropertyDescriptors();
|
|
Info.getMethodDescriptors();
|
|
} catch (IntrospectionException ex) {
|
|
System.err.println("BeanTest: Couldn't introspect");
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < Properties.length; i++) {
|
|
if (Properties[i].isHidden() || Properties[i].isExpert()) {
|
|
continue;
|
|
}
|
|
String name = Properties[i].getDisplayName();
|
|
//System.out.println("name = "+name );
|
|
// Class type = Properties[i].getPropertyType();
|
|
//System.out.println("type = "+type.getName() );
|
|
Method getter = Properties[i].getReadMethod();
|
|
Method setter = Properties[i].getWriteMethod();
|
|
// Only display read/write properties.
|
|
if (getter == null || setter == null) {
|
|
continue;
|
|
}
|
|
//System.out.println("name = "+name );
|
|
//System.out.println("type = "+type.getName() );
|
|
Object args[] = {};
|
|
//System.out.println("m_Target"+m_Target.toString());
|
|
try {
|
|
Object value = getter.invoke(obj, args);
|
|
System.out.println("Inspecting name = " + name);
|
|
if (value instanceof Integer) {
|
|
Object args2[] = {new Integer(999)};
|
|
setter.invoke(obj, args2);
|
|
}
|
|
showInfo(value);
|
|
} catch (Exception e) {
|
|
System.out.println("BeanTest ERROR +" + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call a method by a given name with given arguments, if the method is
|
|
* available. Returns the return values of the call or null if it isnt
|
|
* found. This of course means that the caller is unable to distinguish
|
|
* between "method not found" and "method found and it returned null".
|
|
*
|
|
* @param obj
|
|
* @param mName
|
|
* @param args
|
|
* @return the return value of the called method or null
|
|
*/
|
|
public static Object callIfAvailable(Object obj, String mName, Object[] args) {
|
|
Method meth = hasMethod(obj, mName, toClassArray(args));
|
|
if (meth != null) {
|
|
try {
|
|
return meth.invoke(obj, args);
|
|
} catch (Exception e) {
|
|
System.err.println("Error on calling method " + mName + " on " + obj.getClass().getName());
|
|
System.err.println("Object: " + obj.toString() + ", method name: " + mName);
|
|
System.err.println("Arguments were " + BeanInspector.toString(args));
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Produce an array of Class instances matching the types of the given
|
|
* object array.
|
|
*
|
|
* @param o
|
|
* @return
|
|
*/
|
|
public static Class[] toClassArray(Object[] o) {
|
|
if (o == null) {
|
|
return null;
|
|
}
|
|
Class[] clz = new Class[o.length];
|
|
for (int i = 0; i < o.length; i++) {
|
|
clz[i] = o[i].getClass();
|
|
}
|
|
return clz;
|
|
}
|
|
|
|
/**
|
|
* Check whether an object has a method by the given name and with matching
|
|
* signature considering the arguments. Return it if found, or null if not.
|
|
*
|
|
* @param obj
|
|
* @param mName the method name
|
|
* @param args the arguments, null allowed if the method takes no parameters
|
|
* @return the method or null if it isn't found
|
|
*/
|
|
public static Method hasMethod(Object obj, String mName, Object[] args) {
|
|
return hasMethod(obj, mName, toClassArray(args));
|
|
}
|
|
|
|
/**
|
|
* Check whether an object has a method by the given name and with the given
|
|
* parameter signature. Return it if found, or null if not.
|
|
*
|
|
* @param obj
|
|
* @param mName the method name
|
|
* @param paramTypes the parameter types, null allowed if no parameters are
|
|
* expected
|
|
* @return the method or null if it isn't found
|
|
*/
|
|
public static Method hasMethod(Object obj, String mName, Class[] paramTypes) {
|
|
Class<?> cls = obj.getClass();
|
|
Method[] meths = cls.getMethods();
|
|
for (Method method : meths) {
|
|
if (method.getName().equals(mName)) { // name match
|
|
Class[] methParamTypes = method.getParameterTypes();
|
|
if (paramTypes == null && methParamTypes.length == 0) {
|
|
return method;
|
|
} // full match
|
|
else {
|
|
if (paramTypes != null && (methParamTypes.length == paramTypes.length)) {
|
|
boolean mismatch = false;
|
|
int i = 0;
|
|
while ((i < methParamTypes.length) && (!mismatch)) {
|
|
if (!methParamTypes[i].isAssignableFrom(paramTypes[i]) && !isBoxableFrom(methParamTypes[i], paramTypes[i])) {
|
|
mismatch = true;
|
|
}
|
|
i++;
|
|
}
|
|
if (!mismatch) {
|
|
return method;
|
|
} // parameter match, otherwise search on
|
|
} // parameter mismatch, search on
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check if the given first class is a primitive type and can be boxed to
|
|
* match the second class.
|
|
*
|
|
* @param clz1
|
|
* @param clz2
|
|
* @return
|
|
*/
|
|
private static boolean isBoxableFrom(Class clz1, Class clz2) {
|
|
Class box = getBoxedType(clz1);
|
|
if (box != null && (clz2.isAssignableFrom(box))) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* For a primitive type, return the boxed referenced type. Return null for
|
|
* any non-primitive type.
|
|
*
|
|
* @param clz1
|
|
* @return
|
|
*/
|
|
public static Class getBoxedType(Class cls) {
|
|
if (cls.isPrimitive()) {
|
|
if (cls == double.class) {
|
|
return Double.class;
|
|
} else if (cls == char.class) {
|
|
return Character.class;
|
|
} else if (cls == int.class) {
|
|
return Integer.class;
|
|
} else if (cls == boolean.class) {
|
|
return Boolean.class;
|
|
} else if (cls == byte.class) {
|
|
return Byte.class;
|
|
} else if (cls == short.class) {
|
|
return Short.class;
|
|
} else if (cls == long.class) {
|
|
return Long.class;
|
|
} else if (cls == float.class) {
|
|
return Float.class;
|
|
} else {
|
|
return Void.class;
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* For a Java primitive wrapper class return the corresponding primitive
|
|
* class.
|
|
*/
|
|
public static Class getUnboxedType(Class cls) {
|
|
if (cls == Double.class) {
|
|
return double.class;
|
|
} else if (cls == Character.class) {
|
|
return char.class;
|
|
} else if (cls == Integer.class) {
|
|
return int.class;
|
|
} else if (cls == Boolean.class) {
|
|
return boolean.class;
|
|
} else if (cls == Byte.class) {
|
|
return byte.class;
|
|
} else if (cls == Short.class) {
|
|
return short.class;
|
|
} else if (cls == Long.class) {
|
|
return long.class;
|
|
} else if (cls == Float.class) {
|
|
return float.class;
|
|
} else if (cls == Void.class) {
|
|
return void.class;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Just concatenates getClassDescription(obj) and getMemberDescriptions(obj,
|
|
* withValues).
|
|
*
|
|
* @param obj target object
|
|
* @param withValues if true, member values are displayed as well
|
|
* @return an info string about class and members of the given object
|
|
*/
|
|
public static String getDescription(Object obj, boolean withValues) {
|
|
StringBuffer sbuf = new StringBuffer(getClassDescription(obj));
|
|
sbuf.append("\n");
|
|
String[] mems = getMemberDescriptions(obj, withValues);
|
|
for (String str : mems) {
|
|
sbuf.append(str);
|
|
}
|
|
return sbuf.toString();
|
|
}
|
|
|
|
/**
|
|
* Check for info methods on the object to be provided by the developer and
|
|
* return their text as String.
|
|
*
|
|
* @param obj
|
|
* @return String information about the object's class
|
|
*/
|
|
public static String getClassDescription(Object obj) {
|
|
StringBuffer infoBf = new StringBuffer("Type: ");
|
|
infoBf.append(obj.getClass().getName());
|
|
infoBf.append("\t");
|
|
|
|
Object args[] = {};
|
|
Object ret;
|
|
|
|
for (String meth : new String[]{"getName", "globalInfo"}) {
|
|
ret = callIfAvailable(obj, meth, args);
|
|
if (ret != null) {
|
|
infoBf.append("\t");
|
|
infoBf.append((String) ret);
|
|
} else {
|
|
Description description = obj.getClass().getAnnotation(Description.class);
|
|
if (description != null) {
|
|
infoBf.append("\t");
|
|
infoBf.append(description.text());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return infoBf.toString();
|
|
}
|
|
|
|
/**
|
|
* Return an info string on the members of the object class, containing
|
|
* name, type, optional value and tool tip text if available. The type is
|
|
* accompanied by a tag "common" or "restricted", indicating whether the
|
|
* member property is normal or hidden, meaning it may have effect depending
|
|
* on settings of other members only, for instance.
|
|
*
|
|
* @param obj target object
|
|
* @param withValues if true, member values are displayed as well
|
|
* @return an info string about class and members of the given object
|
|
*/
|
|
public static String[] getMemberDescriptions(Object obj, boolean withValues) {
|
|
BeanInfo bi;
|
|
try {
|
|
bi = Introspector.getBeanInfo(obj.getClass());
|
|
} catch (IntrospectionException e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
PropertyDescriptor[] propertyDescriptors = bi.getPropertyDescriptors();
|
|
ArrayList<String> memberInfoList = new ArrayList<String>();
|
|
|
|
for (int i = 0; i < propertyDescriptors.length; i++) {
|
|
if (propertyDescriptors[i].isExpert()) {
|
|
continue;
|
|
}
|
|
|
|
String name = propertyDescriptors[i].getDisplayName();
|
|
|
|
Method getter = propertyDescriptors[i].getReadMethod();
|
|
Method setter = propertyDescriptors[i].getWriteMethod();
|
|
// Only display read/write properties.
|
|
if (getter == null || setter == null) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
Object args[] = {};
|
|
Object value = getter.invoke(obj, args);
|
|
|
|
// Don't try to set null values:
|
|
if (value == null) {
|
|
// If it's a user-defined property we give a warning.
|
|
String getterClass = propertyDescriptors[i].getReadMethod().getDeclaringClass().getName();
|
|
if (getterClass.indexOf("java.") != 0) {
|
|
System.err.println("Warning: Property \"" + name + "\" has null initial value. Skipping.");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
StringBuffer memberInfoBf = new StringBuffer(40);
|
|
memberInfoBf.append("Member:\t");
|
|
memberInfoBf.append(name);
|
|
|
|
memberInfoBf.append("\tType: ");
|
|
|
|
if (propertyDescriptors[i].isHidden()) {
|
|
memberInfoBf.append("restricted, ");
|
|
} else {
|
|
memberInfoBf.append("common, ");
|
|
}
|
|
String typeName = value.getClass().getName();
|
|
if (value instanceof SelectedTag) {
|
|
Tag[] tags = ((SelectedTag) value).getTags();
|
|
memberInfoBf.append("String in {");
|
|
for (int k = 0; k < tags.length; k++) {
|
|
memberInfoBf.append(tags[k].getString());
|
|
if (k + 1 < tags.length) {
|
|
memberInfoBf.append(", ");
|
|
}
|
|
}
|
|
memberInfoBf.append("}");
|
|
} else {
|
|
memberInfoBf.append(typeName);
|
|
}
|
|
|
|
if (withValues) {
|
|
memberInfoBf.append('\t');
|
|
memberInfoBf.append("Value: \t");
|
|
memberInfoBf.append(toString(value));
|
|
}
|
|
|
|
|
|
// now look for a TipText method for this property
|
|
Method tipTextMethod = hasMethod(obj, name + "TipText", null);
|
|
if (tipTextMethod == null) {
|
|
memberInfoBf.append("\tNo further hint.");
|
|
} else {
|
|
memberInfoBf.append("\tHint: ");
|
|
memberInfoBf.append(toString(tipTextMethod.invoke(obj, args)));
|
|
}
|
|
|
|
memberInfoBf.append('\n');
|
|
memberInfoList.add(memberInfoBf.toString());
|
|
} catch (Exception ex) {
|
|
System.err.println("Skipping property " + name + " ; exception: " + ex.getMessage());
|
|
ex.printStackTrace();
|
|
} // end try
|
|
} // end for
|
|
return memberInfoList.toArray(new String[1]);
|
|
}
|
|
|
|
/**
|
|
* Take an object of primitive type (like int, Integer etc) and convert it
|
|
* to double.
|
|
*
|
|
* @param val
|
|
* @return
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public static double toDouble(Object val) throws IllegalArgumentException {
|
|
if (val instanceof Integer) {
|
|
return ((Integer) val).doubleValue();
|
|
} else if (val instanceof Double) {
|
|
return ((Double) val).doubleValue();
|
|
} else if (val instanceof Boolean) {
|
|
return (((Boolean) val) ? 1. : 0.);
|
|
} else if (val instanceof Character) {
|
|
return ((Character) val).charValue();
|
|
} else if (val instanceof Byte) {
|
|
return ((Byte) val).doubleValue();
|
|
} else if (val instanceof Short) {
|
|
return ((Short) val).doubleValue();
|
|
} else if (val instanceof Long) {
|
|
return ((Long) val).doubleValue();
|
|
} else if (val instanceof Float) {
|
|
return ((Float) val).doubleValue();
|
|
} else if (val instanceof Void) {
|
|
return 0;
|
|
}
|
|
throw new IllegalArgumentException("Illegal type, cant convert " + val.getClass() + " to double.");
|
|
}
|
|
|
|
/**
|
|
* Take a String and convert it to a destined data type using the
|
|
* appropriate function.
|
|
*
|
|
* @param str
|
|
* @param destType
|
|
* @return
|
|
*/
|
|
public static Object stringToPrimitive(String str, Class<?> destType) throws NumberFormatException {
|
|
if ((destType == Integer.class) || (destType == int.class)) {
|
|
return Integer.valueOf(str);
|
|
} else if ((destType == Double.class) || (destType == double.class)) {
|
|
return Double.valueOf(str);
|
|
} else if ((destType == Boolean.class) || (destType == boolean.class)) {
|
|
return Boolean.valueOf(str);
|
|
} else if ((destType == Byte.class) || (destType == byte.class)) {
|
|
return Byte.valueOf(str);
|
|
} else if ((destType == Short.class) || (destType == short.class)) {
|
|
return Short.valueOf(str);
|
|
} else if ((destType == Long.class) || (destType == long.class)) {
|
|
return Long.valueOf(str);
|
|
} else if ((destType == Float.class) || (destType == float.class)) {
|
|
return Float.valueOf(str);
|
|
} else if ((destType == Character.class) || (destType == char.class)) {
|
|
return str.charAt(0);
|
|
} else {
|
|
// if (destType == Void.class)
|
|
System.err.println("warning, value interpreted as void type");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Take a double value and convert it to a primitive object.
|
|
*
|
|
* @param d
|
|
* @param destType
|
|
* @return
|
|
*/
|
|
public static Object doubleToPrimitive(Double d, Class<?> destType) {
|
|
if ((destType == Double.class) || (destType == double.class)) {
|
|
return d;
|
|
}
|
|
if ((destType == Integer.class) || (destType == int.class)) {
|
|
return new Integer(d.intValue());
|
|
} else if ((destType == Boolean.class) || (destType == boolean.class)) {
|
|
return (d != 0) ? Boolean.TRUE : Boolean.FALSE;
|
|
} else if ((destType == Byte.class) || (destType == byte.class)) {
|
|
return new Byte(d.byteValue());
|
|
} else if ((destType == Short.class) || (destType == short.class)) {
|
|
return new Short(d.shortValue());
|
|
} else if ((destType == Long.class) || (destType == long.class)) {
|
|
return new Long(d.longValue());
|
|
} else if ((destType == Float.class) || (destType == float.class)) {
|
|
return new Float(d.floatValue());
|
|
} else { // this makes hardly sense...
|
|
System.err.println("warning: converting from double to character or void...");
|
|
if ((destType == Character.class) || (destType == char.class)) {
|
|
return new Character(d.toString().charAt(0));
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks whether a type belongs to primitive (int, long, double, char etc.)
|
|
* or the Java encapsulations (Integer, Long etc.)
|
|
*
|
|
* @param cls
|
|
* @return
|
|
*/
|
|
public static boolean isJavaPrimitive(Class<?> cls) {
|
|
if (cls.isPrimitive()) {
|
|
return true;
|
|
}
|
|
if ((cls == Double.class) || (cls == Integer.class) || (cls == Boolean.class) || (cls == Character.class) || (cls == Void.class)
|
|
|| (cls == Byte.class) || (cls == Short.class) || (cls == Long.class) || (cls == Float.class)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the primitive class of a Java primitive encapsulation, or null if not
|
|
* applicable. E.g., returns int for Integer, long for Long, Boolean for
|
|
* Boolean etc.
|
|
*
|
|
* @param cls
|
|
* @return
|
|
*/
|
|
public static Class getJavaPrimitive(Class<?> cls) {
|
|
if (cls.isPrimitive()) {
|
|
return cls;
|
|
}
|
|
if (cls == Double.class) {
|
|
return double.class;
|
|
} else if (cls == Integer.class) {
|
|
return int.class;
|
|
} else if (cls == Boolean.class) {
|
|
return Boolean.class;
|
|
} else if (cls == Byte.class) {
|
|
return byte.class;
|
|
} else if (cls == Short.class) {
|
|
return short.class;
|
|
} else if (cls == Long.class) {
|
|
return long.class;
|
|
} else if (cls == Float.class) {
|
|
return float.class;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Try to convert an object to a destination type, especially for primitive
|
|
* types (int, double etc. but also Integer, Double etc.).
|
|
*
|
|
* @param destType
|
|
* @param value
|
|
* @return
|
|
*/
|
|
public static Object decodeType(Class<?> destType, Object value) {
|
|
// System.err.println("desttype: " + destType.toString() + ", val: " + value.getClass().toString());
|
|
if (destType.isAssignableFrom(value.getClass())) {
|
|
// value is already of destType or assignable (subclass), so just return it
|
|
return value;
|
|
}
|
|
if (destType == String.class || destType == SelectedTag.class) {
|
|
if (value.getClass() == String.class) {
|
|
return value;
|
|
} else {
|
|
return value.toString();
|
|
}
|
|
} else if (isJavaPrimitive(destType)) {
|
|
try {
|
|
if (value.getClass() == String.class) {
|
|
return stringToPrimitive((String) value, destType);
|
|
} else {
|
|
return doubleToPrimitive(toDouble(value), destType);
|
|
}
|
|
} catch (Exception e) {
|
|
System.err.println("Error in converting type of " + value + " to " + destType.getName() + ": " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
System.err.println("Error: unknown type, skipping decode " + value.getClass().getName() + " to " + destType.getName());
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Try to get an object member value using the default getter. Returns null
|
|
* if not successful.
|
|
*
|
|
* @param obj
|
|
* @param mem
|
|
* @return the value if successful, else null
|
|
*/
|
|
public static Object getMem(Object obj, String mem) {
|
|
BeanInfo bi;
|
|
try {
|
|
bi = Introspector.getBeanInfo(obj.getClass());
|
|
} catch (IntrospectionException e) {
|
|
e.printStackTrace();
|
|
return false;
|
|
}
|
|
PropertyDescriptor[] m_Properties = bi.getPropertyDescriptors();
|
|
Method getter = null;
|
|
for (int i = 0; i < m_Properties.length; i++) {
|
|
if (m_Properties[i].getDisplayName().equals(mem)) {
|
|
getter = m_Properties[i].getReadMethod();
|
|
break;
|
|
}
|
|
}
|
|
if (getter != null) {
|
|
try {
|
|
return getter.invoke(obj, (Object[]) null);
|
|
} catch (Exception e) {
|
|
System.err.println("Exception in invoking setter: " + e.getMessage());
|
|
return null;
|
|
}
|
|
} else {
|
|
System.err.println("Getter method for " + mem + " not found!");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Try to set an object member to a given value. Returns true if successful,
|
|
* else false. The types are adapted as generally as possible, converting
|
|
* using the decodeType() method.
|
|
*
|
|
* @param obj
|
|
* @param mem
|
|
* @param val
|
|
* @return true if successful, else false
|
|
*/
|
|
public static boolean setMem(Object obj, String mem, Object val) {
|
|
BeanInfo bi;
|
|
try {
|
|
bi = Introspector.getBeanInfo(obj.getClass());
|
|
} catch (IntrospectionException e) {
|
|
e.printStackTrace();
|
|
return false;
|
|
}
|
|
PropertyDescriptor[] m_Properties = bi.getPropertyDescriptors();
|
|
// Method getter = null;
|
|
Method setter = null;
|
|
Class<?> type = null;
|
|
// System.err.println("looking at " + toString(obj));
|
|
for (int i = 0; i < m_Properties.length; i++) {
|
|
if (m_Properties[i].getDisplayName().equals(mem)) {
|
|
// System.err.println("looking at " + m_Properties[i].getDisplayName());
|
|
// getter = m_Properties[i].getReadMethod();
|
|
setter = m_Properties[i].getWriteMethod();
|
|
type = m_Properties[i].getPropertyType();
|
|
break;
|
|
}
|
|
}
|
|
if (setter != null) {
|
|
try {
|
|
// System.out.println("setting value...");
|
|
Object[] args = new Object[]{decodeType(type, val)};
|
|
if (args[0] != null) {
|
|
setter.invoke(obj, args);
|
|
return true;
|
|
} else {
|
|
System.err.println("no value to set");
|
|
return false;
|
|
}
|
|
} catch (Exception e) {
|
|
System.err.println("Exception in invoking setter: " + e.getMessage());
|
|
return false;
|
|
}
|
|
} else {
|
|
System.err.println("Setter method for " + mem + " not found!");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method simply looks for an appropriate tiptext
|
|
*
|
|
* @param name The name of the property
|
|
* @param methods A list of methods to search.
|
|
* @param target The target object
|
|
* @return String for the ToolTip.
|
|
*/
|
|
public static String getToolTipText(String name, MethodDescriptor[] methods, Object target, boolean stripToolTipToFirstPoint, int toHTMLLen) {
|
|
String result = "";
|
|
String tipName = name + "TipText";
|
|
|
|
for (int j = 0; j < methods.length; j++) {
|
|
String mname = methods[j].getDisplayName();
|
|
Method meth = methods[j].getMethod();
|
|
|
|
if (mname.equals(tipName)) {
|
|
if (meth.getReturnType().equals(String.class)) {
|
|
try {
|
|
Object args[] = {};
|
|
String tempTip = (String) (meth.invoke(target, args));
|
|
result = tempTip;
|
|
if (stripToolTipToFirstPoint) {
|
|
int ci = tempTip.indexOf('.');
|
|
if (ci > 0) {
|
|
result = tempTip.substring(0, ci);
|
|
}
|
|
}
|
|
} catch (Exception ex) {
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} // end for looking for tiptext
|
|
|
|
if(result.isEmpty()) {
|
|
LOGGER.fine(String.format("No ToolTip for %s.%s available.", target.getClass().getName(), name));
|
|
}
|
|
|
|
if (toHTMLLen > 0) {
|
|
return StringTools.toHTML(result, toHTMLLen);
|
|
} else {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method simply looks for an appropriate tool tip text
|
|
*
|
|
* @param name The name of the property
|
|
* @param methods A list of methods to search.
|
|
* @param target The target object
|
|
* @return String for the ToolTip.
|
|
*/
|
|
public static String getToolTipText(String name, MethodDescriptor[] methods, Object target) {
|
|
return getToolTipText(name, methods, target, false, 0);
|
|
}
|
|
}
|