package com.flaptor.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
/**
* Utility methods for the {@link Function} class.
*
* @author santip
*/
public class FunctionUtils {
/**
* @return a function that will return the toString of its parameter
*/
public static Function<Object, String> getToString() {
return new Function<Object, String>() {
public String apply(Object from) {
return String.valueOf(from);
}
};
}
/**
* @return a function that will invoke the static valueOf method of the given type on
* its String parameter and will cast the return value to the given type.
*/
public static <T> Function<String, T> getValueOf(final Class<T> type) {
return getStaticMethod(type, String.class, type, "valueOf");
}
/**
* @return a function that will invoke a static method using the function argument as
* a parameter and will cast the return value to the given toType
*/
public static <F, T> Function<F, T> getStaticMethod(Class<?> type, Class<F> fromType, final Class<T> toType, String methodName) {
try {
final Method method = type.getMethod(methodName, fromType);
return new Function<F, T>() {
public T apply(F from) {
try {
return toType.cast(method.invoke(null, from));
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
};
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
/**
* invokes the given method to the given target using reflection.
* @return the value returned by the invoked method.
*/
public static Object invokeMethod(Object target, String method) {
return getMethodInvoker(method).apply(target);
}
/**
* @return a function that invokes the given method using reflection.
*/
public static Function<Object, Object> getMethodInvoker(final String methodName) {
return getMethodInvoker(Object.class, methodName);
}
/**
* @return a function that invokes the given method using reflection and will cast it to the given return type.
*/
public static <T> Function<Object, T> getMethodInvoker(final Class<T> returnType, final String methodName) {
return new Function<Object, T>() {
public T apply(Object from) {
if (from == null) return null;
try {
Method method = from.getClass().getMethod(methodName, new Class[0]);
return returnType.cast(method.invoke(from, new Object[0]));
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
};
}
/**
* Wraps the given function in such a way that it will call the function only
* once for each different key and cache the return value for future requests.
*
* @param function the function to be cached.
* @return a wrapper function that will cache the inner function's return values
*/
public static <K,V> Function<K,V> cachedFunction(final Function<K, V> function) {
return new Function<K, V>() {
Map<K, V> cache = Maps.newHashMap();
public V apply(K key) {
if (!cache.containsKey(key)) {
cache.put(key, function.apply(key));
}
return cache.get(key);
}
};
}
}