blob: adec2f46a553dc21c0ada6bc84510fdbd9bfb1c1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2010 Soyatec (http://www.soyatec.com) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Soyatec - initial API and implementation
*******************************************************************************/
package org.eclipse.xwt.internal.utils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.databinding.conversion.IConverter;
import org.eclipse.xwt.XWT;
/**
* Object Tools.
*
* @author yyang (yves.yang@soyatec.com)
* @version 1.0
*/
public class ObjectUtil {
public static final Class<?>[] EMPTY = new Class[0];
private ObjectUtil() {
}
public static Class<?> normalizedType(Class<?> type) {
if (type == int.class) {
return Integer.class;
}
if (type == double.class) {
return Double.class;
}
if (type == float.class) {
return Float.class;
}
if (type == boolean.class) {
return Boolean.class;
}
if (type == char.class) {
return Character.class;
}
if (type == byte.class) {
return Byte.class;
}
return type;
}
public static boolean isAssignableFrom(Class<?> source, Class<?> target) {
if (normalizedType(source) == normalizedType(target)) {
return true;
}
return source.isAssignableFrom(target);
}
/**
* Find the compatible class. This includes superclasses, interfaces and so on.
*
* @param clazz
* the specified class.
* @return Returns the class array includes its superclasses, interfaces and itself.
*/
public static final Class<?>[] findCompatibleClasses(Class<?> clazz) {
Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
// Add itself to list.
classes.add(clazz);
// Add primitive compatible type
if (clazz == Boolean.class) {
classes.add(boolean.class);
} else if (clazz == Byte.class) {
classes.add(byte.class);
} else if (clazz == Short.class) {
classes.add(short.class);
} else if (clazz == Integer.class) {
classes.add(int.class);
} else if (clazz == Long.class) {
classes.add(long.class);
} else if (clazz == Float.class) {
classes.add(float.class);
} else if (clazz == Double.class) {
classes.add(double.class);
} else if (clazz == Character.class) {
classes.add(char.class);
} else if (clazz == boolean.class) {
classes.add(Boolean.class);
} else if (clazz == byte.class) {
classes.add(Byte.class);
} else if (clazz == short.class) {
classes.add(Short.class);
} else if (clazz == int.class) {
classes.add(Integer.class);
} else if (clazz == long.class) {
classes.add(Long.class);
} else if (clazz == float.class) {
classes.add(Float.class);
} else if (clazz == double.class) {
classes.add(Double.class);
} else if (clazz == char.class) {
classes.add(Character.class);
}
// Add its interfaces
findInterfaces(classes, clazz);
// Add its superclasses
findSuperClasses(classes, clazz);
// At last, add Object class.
classes.add(Object.class);
return classes.toArray(EMPTY);
}
public static Object resolveValue(Object value, Class<?> targetType, Object defaultValue) {
return resolveValue(value, value.getClass(), targetType, defaultValue);
}
public static Object resolveValue(Object value, Class<?> sourceType, Class<?> targetType, Object defaultValue) {
IConverter converter = XWT.findConvertor(sourceType, targetType);
if (converter != null) {
return converter.convert(value);
}
return defaultValue;
}
/**
* Find compatible constructor for specified class.
*
* @param clazz
* the specified class.
* @param argumentTypes
* constructor argument types.
* @return Returns constructor instance. If snot find, returns null.
*/
public static final Constructor<?> findConstructor(Class<?> clazz, Class<?>... argumentTypes) {
Class<?>[][] classesArray = new Class[argumentTypes.length][];
for (int i = 0, len = argumentTypes.length; i < len; i++) {
Class<?>[] classes = findCompatibleClasses(argumentTypes[i]);
classesArray[i] = classes;
}
int totalPossibles = 1;
for (int i = 0; i < classesArray.length; i++) {
totalPossibles *= classesArray[i].length;
}
List<Class<?>[]> classList = new ArrayList<Class<?>[]>(totalPossibles);
computeArguments(classList, classesArray, new Class[classesArray.length], 0);
for (Class<?>[] arguments : classList) {
try {
return clazz.getConstructor(arguments);
} catch (NoSuchMethodException e) {
continue;
}
}
return null;
}
/**
* Find compatible public method for specified class.
*
* @param clazz
* the specified class.
* @param name
* method name.
* @param argumentTypes
* method argument types. If it is a null value, system will find method without argument types.
* @return Returns method instance. If not find, returns null.
*/
public static final Method findMethod(Class<?> clazz, String name, Class<?>... argumentTypes) {
if (argumentTypes != null && argumentTypes.length > 0) {
Class<?>[][] classesArray = new Class[argumentTypes.length][];
for (int i = 0, len = argumentTypes.length; i < len; i++) {
Class<?>[] classes = findCompatibleClasses(argumentTypes[i]);
classesArray[i] = classes;
}
int totalPossibles = 1;
for (int i = 0; i < classesArray.length; i++) {
totalPossibles *= classesArray[i].length;
}
List<Class<?>[]> classList = new ArrayList<Class<?>[]>(totalPossibles);
computeArguments(classList, classesArray, new Class[classesArray.length], 0);
for (Class<?>[] arguments : classList) {
try {
return clazz.getDeclaredMethod(name, arguments);
} catch (NoSuchMethodException e) {
continue;
}
}
} else {
// find method without argument types;
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getName().equals(name)) {
return method;
}
}
}
return null;
}
/**
* Find compatible method for specified class.
*
* @param clazz
* the specified class.
* @param name
* method name.
* @param argumentTypes
* method argument types. If it is a null value, system will find method without argument types.
* @return Returns method instance. If not find, returns null.
*/
public static final Method findDeclaredMethod(Class<?> clazz, String name, Class<?>... argumentTypes) {
if (argumentTypes != null && argumentTypes.length > 0) {
Class<?>[][] classesArray = new Class[argumentTypes.length][];
for (int i = 0, len = argumentTypes.length; i < len; i++) {
Class<?>[] classes = findCompatibleClasses(argumentTypes[i]);
classesArray[i] = classes;
}
int totalPossibles = 1;
for (int i = 0; i < classesArray.length; i++) {
totalPossibles *= classesArray[i].length;
}
List<Class<?>[]> classList = new ArrayList<Class<?>[]>(totalPossibles);
computeArguments(classList, classesArray, new Class[classesArray.length], 0);
for (Class<?>[] arguments : classList) {
try {
return clazz.getDeclaredMethod(name, arguments);
} catch (NoSuchMethodException e) {
continue;
}
}
} else {
// find method without argument types;
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(name) && method.getParameterTypes().length == 0) {
return method;
}
}
}
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
return findDeclaredMethod(superclass, name, argumentTypes);
}
return null;
}
/**
* Find property getter method for specified class.
*
* @param clazz
* the specified class.
* @param name
* property name
* @param type
* property type. If it is a null value, system will find the suitable method.
* @return Returns method instance. If not find, returns null.
*/
public static final Method findGetter(Class<?> clazz, String name, Class<?> type) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException("Invalid getter method name, null value found");
}
String getterName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method method;
try {
if (clazz.isEnum()) {
method = clazz.getClass().getMethod(getterName, EMPTY);
}
else {
method = clazz.getMethod(getterName, EMPTY);
}
} catch (NoSuchMethodException e1) {
// :Check if it is a boolean getter
getterName = "is" + name.substring(0, 1).toUpperCase() + name.substring(1);
try {
method = clazz.getMethod(getterName, EMPTY);
if (method.getReturnType() != Boolean.class && method.getReturnType() != boolean.class) {
return null;
}
} catch (NoSuchMethodException e2) {
method = findCaseIgnoreGetter(clazz, name, type);
}
// :~
}
if (type == null) {
return method;
} else {
if (method != null) {
Class<?> returnType = method.getReturnType();
Class<?>[] types = findCompatibleClasses(type);
for (Class<?> t : types) {
if (t == returnType) {
return method;
}
}
}
}
return null;
}
private static Method findCaseIgnoreGetter(Class<?> clazz, String name, Class<?> type) {
String getterName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
String isName = "is" + name.substring(0, 1).toUpperCase() + name.substring(1);
for (Method element : clazz.getMethods()) {
if (element.getParameterTypes().length != 0) {
continue;
}
if (element.getName().equalsIgnoreCase(getterName)) {
return element;
}
if (element.getName().equalsIgnoreCase(isName) && element.getReturnType() != Boolean.class && element.getReturnType() != boolean.class) {
return element;
}
}
return null;
}
/**
* Find superclasses and add them to list.
*/
private static void findSuperClasses(Set<Class<?>> list, Class<?> clazz) {
if (clazz != null) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != Object.class) {
list.add(superClass);
findInterfaces(list, superClass);
findSuperClasses(list, superClass);
}
}
}
/**
* Find interfaces and add them to list.
*/
private static void findInterfaces(Set<Class<?>> list, Class<?> clazz) {
if (clazz != null) {
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> interfac1 : interfaces) {
list.add(interfac1);
findInterfaces(list, interfac1);
}
}
}
/**
* Combine arithmetic.
*/
private static void computeArguments(List<Class<?>[]> list, Class<?>[][] arguments, Class<?>[] buffer, int start) {
if (start >= arguments.length) {
Class<?>[] classes = new Class<?>[arguments.length];
for (int i = 0; i < arguments.length; ++i) {
classes[i] = buffer[i];
}
list.add(classes);
return;
}
for (int i = 0; i < arguments[start].length; ++i) {
buffer[start] = arguments[start][i];
computeArguments(list, arguments, buffer, start + 1);
}
}
}