Quinta-feira, Janeiro 12, 2006

Duck Type em Java

Como o Java é uma linguagem boa e com excelentes APIs, mas muito tosca em algumas coisas básicas (como manipulação de Strings e Coleções), volta e meio fazemos alguns utilitários estúpidos pra facilitar a vida.

Aqui vai um dos meus, um simples wrapper para facilitar a chamada de métodos dinâmicos.


package common;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* Executes a method in an object dinamically. It's a wrapper to the java
* reflection way of execute methods dinamically.
*/
public class DuckType {

public static T execute(Object object, String methodName, Object ... parameters) {

if (object == null) return null;
if (methodName == null || methodName.equals("")) return null;

Class[] classes = extractClassesFromParameters(parameters);

try {

return (T) executeEasyWay(object, methodName, classes, parameters);

} catch (NoSuchMethodException e) {

return (T) executeHardWay(object, methodName, classes, parameters);

} catch (SecurityException e) {
return null;
} catch (IllegalArgumentException e) {
return null;
} catch (IllegalAccessException e) {
return null;
} catch (InvocationTargetException e) {
return null;
}
}

private static Object executeEasyWay(Object object, String methodName, Class[] classes, Object... parameters) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

Method method = object.getClass().getMethod(methodName, classes);
return method.invoke(object, parameters);
}

private static Object executeHardWay(Object object, String methodName, Class[] classes, Object... parameters) {

// it didn't find the method in the easy way, trying the hard way
Method[] methods = object.getClass().getMethods();

for (Method method : methods) {
Class[] methodTypes = method.getParameterTypes();

// Ignore methods with different names
if (!methodName.equals(method.getName())) continue;

// Ignore methods with different number of parameters
if (methodTypes.length != classes.length) continue;

boolean isMethodExecutable = true;
for (int i = 0; i < methodTypes.length; i++) {
Class methodType = (Class) methodTypes[i];
Class parameterType = classes[i];

if (!methodType.isAssignableFrom(parameterType)) {
isMethodExecutable = false;
break;
}
}

try {

if (isMethodExecutable) return method.invoke(object, parameters);

} catch (IllegalArgumentException e1) {
return null;
} catch (IllegalAccessException e1) {
return null;
} catch (InvocationTargetException e1) {
return null;
}
}

return null;
}

private static Class[] extractClassesFromParameters(Object[] parameters) {

Class[] classes = new Class[parameters.length];

for (int i = 0; i < parameters.length; i++) {
Object parameter = parameters[i];
classes[i] = parameter.getClass();
}

return classes;
}
}

0 comentários: