Skip to content

Instantly share code, notes, and snippets.

@andrewrlee
Created April 24, 2016 21:16
Show Gist options
  • Select an option

  • Save andrewrlee/a8d3429a9a6d85e123d0cd7fab2ca43d to your computer and use it in GitHub Desktop.

Select an option

Save andrewrlee/a8d3429a9a6d85e123d0cd7fab2ca43d to your computer and use it in GitHub Desktop.
instantiate class by constructor args. (Derive constructor based on arg types)
/**
* Highly influenced by: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java
* Copyright (c) Rich Hickey. All rights reserved.
* The use and distribution terms for this software are covered by the
* Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
* which can be found in the file epl-v10.html at the root of this distribution.
* By using this software in any fashion, you are agreeing to be bound by
* the terms of this license.
* You must not remove this notice, or any other, from this software.
**/
package uk.co.optimisticpanda.metricsdecorator;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
public class Instantiator {
@SuppressWarnings("unchecked")
public static <T> T invokeConstructor(Class<T> c, Object[] args) {
try {
List<Constructor<T>> constructors = new ArrayList<Constructor<T>>();
for (Constructor<T> constructor : (Constructor<T>[]) c.getConstructors()) {
if (constructor.getParameterTypes().length == args.length) {
constructors.add(constructor);
}
}
if (constructors.isEmpty()) {
throw new IllegalArgumentException("No matching ctor found" + " for " + c);
}
if (constructors.size() == 1) {
Constructor<T> ctor = constructors.get(0);
return ctor.newInstance(boxArgs(ctor.getParameterTypes(), args));
}
for (Constructor<T> constructor : constructors) {
Class<?>[] params = constructor.getParameterTypes();
if (isCongruent(params, args)) {
Object[] boxedArgs = boxArgs(params, args);
return constructor.newInstance(boxedArgs);
}
}
throw new IllegalArgumentException("No matching ctor found" + " for " + c);
} catch (Exception e) {
throw SneakyThrow.sneakyThrow(getCauseOrElse(e));
}
}
public static class SneakyThrow {
public static RuntimeException sneakyThrow(Throwable ex) {
return SneakyThrow.<RuntimeException> sneakyThrowInner(ex);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrowInner(Throwable ex) throws T {
return (T) ex;
}
}
private static Throwable getCauseOrElse(Exception e) {
if (e.getCause() != null)
return e.getCause();
return e;
}
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;
}
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("Unexpected param type, expected: " + paramType + ", given: " + arg.getClass().getName());
}
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 public 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;// ||
else if (paramType == float.class)
return argType == Float.class || argType == double.class;
else if (paramType == double.class)
return argType == Double.class || argType == float.class;
else if (paramType == long.class)
return argType == Long.class || argType == int.class || argType == short.class || argType == byte.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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment