Created
March 22, 2015 20:34
-
-
Save leifoolsen/17211b420986d814ea08 to your computer and use it in GitHub Desktop.
Some reflection utils + SneakyThrow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/[email protected]/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