Created
April 24, 2016 21:16
-
-
Save andrewrlee/a8d3429a9a6d85e123d0cd7fab2ca43d to your computer and use it in GitHub Desktop.
instantiate class by constructor args. (Derive constructor based on arg types)
This file contains hidden or 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
| /** | |
| * 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