Skip to content

Instantly share code, notes, and snippets.

@leifoolsen
Created March 22, 2015 20:34
Show Gist options
  • Save leifoolsen/17211b420986d814ea08 to your computer and use it in GitHub Desktop.
Save leifoolsen/17211b420986d814ea08 to your computer and use it in GitHub Desktop.
Some reflection utils + SneakyThrow
package com.github.leifoolsen.reflection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
public class ReflectionUtils {
private static final Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);
private ReflectionUtils() {
}
public static <T> T invokeConstructor(Class<T> clazz, Object... args) {
if(clazz == null) {
return null;
}
try {
if(args.length < 1) {
return (T) clazz.newInstance();
}
Constructor[] constructors = clazz.getConstructors();
ArrayList<Constructor> filteredConstructors = new ArrayList();
for(int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
if(constructor.getParameterTypes().length == args.length)
filteredConstructors.add(constructor);
}
if(filteredConstructors.isEmpty()) {
throw new IllegalArgumentException(
String.format("No matching constructor found for %s%s", clazz, argsToString(args)));
}
if(filteredConstructors.size() == 1) {
Constructor constructor = filteredConstructors.get(0);
return (T) constructor.newInstance(boxArgs(constructor.getParameterTypes(), args));
}
else {
//overloaded w/same arity
for(Iterator iterator = filteredConstructors.iterator(); iterator.hasNext();) {
Constructor constructor = (Constructor) iterator.next();
Class[] params = constructor.getParameterTypes();
if(isCongruent(params, args)) {
Object[] boxedArgs = boxArgs(params, args);
return (T) constructor.newInstance(boxedArgs);
}
}
throw new IllegalArgumentException(
String.format("No matching constructor found for %s%s", clazz, argsToString(args)));
}
}
catch (Throwable t) {
throw sneakyThrow(getCauseOrThrowable(t));
// Alernatively use Guava Throwables
// ... but the problem with Throwables is that the real exception is wrapped inside a RuntimeException
//throw Throwables.propagate(getCauseOrThrowable(t));
}
}
private static String argsToString(Object[] args) {
final StringBuilder sb = new StringBuilder("(");
for(int i = 0, n = args.length; i < n; i++) {
sb.append(args[i].getClass().getSimpleName());
if(i < n-1) {
sb.append(", ");
}
}
return sb.append(")").toString();
}
static Object[] boxArgs(Class[] params, Object[] args){
if(params.length == 0)
return null;
Object[] ret = new Object[params.length];
for(int i = 0; i < params.length; i++)
{
Object arg = args[i];
Class paramType = params[i];
ret[i] = boxArg(paramType, arg);
}
return ret;
}
static Object boxArg(Class paramType, Object arg){
if(!paramType.isPrimitive())
return paramType.cast(arg);
else if(paramType == boolean.class)
return Boolean.class.cast(arg);
else if(paramType == char.class)
return Character.class.cast(arg);
else if(arg instanceof Number)
{
Number n = (Number) arg;
if(paramType == int.class)
return n.intValue();
else if(paramType == float.class)
return n.floatValue();
else if(paramType == double.class)
return n.doubleValue();
else if(paramType == long.class)
return n.longValue();
else if(paramType == short.class)
return n.shortValue();
else if(paramType == byte.class)
return n.byteValue();
}
throw new IllegalArgumentException(
String.format("Unexpected param type, expected: %s, given: %s", paramType, arg.getClass().getName()));
}
static boolean isCongruent(Class[] params, Object[] args){
boolean ret = false;
if(args == null)
return params.length == 0;
if(params.length == args.length)
{
ret = true;
for(int i = 0; ret && i < params.length; i++)
{
Object arg = args[i];
Class argType = (arg == null) ? null : arg.getClass();
Class paramType = params[i];
ret = paramArgTypeMatch(paramType, argType);
}
}
return ret;
}
public static boolean paramArgTypeMatch(Class paramType, Class argType){
if(argType == null)
return !paramType.isPrimitive();
if(paramType == argType || paramType.isAssignableFrom(argType))
return true;
if(paramType == int.class)
return argType == Integer.class
|| argType == long.class
|| argType == Long.class
|| argType == short.class
|| argType == byte.class;// || argType == FixNum.class;
else if(paramType == float.class)
return argType == Float.class
|| argType == double.class;
else if(paramType == double.class)
return argType == Double.class
|| argType == float.class;// || argType == DoubleNum.class;
else if(paramType == long.class)
return argType == Long.class
|| argType == int.class
|| argType == short.class
|| argType == byte.class;// || argType == BigNum.class;
else if(paramType == char.class)
return argType == Character.class;
else if(paramType == short.class)
return argType == Short.class;
else if(paramType == byte.class)
return argType == Byte.class;
else if(paramType == boolean.class)
return argType == Boolean.class;
return false;
}
public static Throwable getCauseOrThrowable(Throwable t) {
return t.getCause() != null ? t.getCause() : t;
}
/**
* Throw even checked exceptions without being required
* to declare them or catch them. Suggested idiom:
* <p>
* <code>throw sneakyThrow( some exception );</code>
* </p>
*/
public static RuntimeException sneakyThrow(Throwable t) {
// http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
if (t == null) {
throw new NullPointerException();
}
ReflectionUtils.<RuntimeException>_sneakyThrow(t);
return null;
}
private static <T extends Throwable> void _sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment