InstantiationHelper.java

package net.secodo.jcircuitbreaker.breakhandler.helper;

import java.lang.reflect.Constructor;

import net.secodo.jcircuitbreaker.breakhandler.BreakHandler;
import net.secodo.jcircuitbreaker.breakhandler.BreakHandlerFactory;
import net.secodo.jcircuitbreaker.breakhandler.exception.BreakHandlerException;


/**
 * Helper class which role is to create new instances of given {@link BreakHandler} class.
 * The class given needs to have a public one-argument constructor.
 *
 */
public class InstantiationHelper {
  /**
   * Creates new instances of given {@link BreakHandler} class. The class given needs to have a publicly accessible(!)
   * one-argument constructor.
   *
   * @param handlerClass the class representing break handler which should be created
   * @param constructorParam constructor parameter of break handler which should be created
   * @param <R> the return type of real-method for which a <i>break handler</i> is created
   * @param <P> the type of constructor parameter which is used to create new instance of break handler
   *
   * @return new instance of {@link BreakHandler} constructed using single parameter constructor with given parameter
   *         value
   *
   * @throws BreakHandlerException in case instantiation failed
   */
  @SuppressWarnings("rawtypes")
  public static <R, P> BreakHandler<R> constructSingleParamInstance(Class<? extends BreakHandler> handlerClass,
                                                                    P constructorParam) throws BreakHandlerException {
    final BreakHandler<R> breakHandler;
    try {
      Constructor<? extends BreakHandler> constructor = null;
      try {
        Class<P> parameterClass = getConstructorParamClass(constructorParam);
        constructor = handlerClass.getConstructor(parameterClass);

      } catch (NoSuchMethodException originalException) {
        // try to find matching constructor containing primitive type

        try {
          if (Integer.class.isInstance(constructorParam)) {
            constructor = handlerClass.getConstructor(int.class);
          } else if (Long.class.isInstance(constructorParam)) {
            constructor = handlerClass.getConstructor(long.class);
          } else if (Float.class.isInstance(constructorParam)) {
            constructor = handlerClass.getConstructor(float.class);
          } else if (Double.class.isInstance(constructorParam)) {
            constructor = handlerClass.getConstructor(double.class);
          } else if (Short.class.isInstance(constructorParam)) {
            constructor = handlerClass.getConstructor(short.class);
          } else if (Byte.class.isInstance(constructorParam)) {
            constructor = handlerClass.getConstructor(byte.class);
          } else {
            throw originalException;
          }
        } catch (NoSuchMethodException anotherException) {
          throw originalException;
        }
      }

      breakHandler = instantiate(constructor, constructorParam);

    } catch (Exception ex) {
      throw new BreakHandlerException(
        "Unable to create new instance of break handler of class: " + handlerClass + " " +
        "by using constructor with parameter: " + constructorParam + ". The constructor must be public - otherwise " +
        "you need to create custom " + BreakHandlerFactory.class.getSimpleName() + " instead of using " +
        InstantiationHelper.class.getSimpleName() + " to instantiate handler class)",
        ex);
    }

    return breakHandler;
  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
  private static <R, P> BreakHandler<R> instantiate(Constructor<? extends BreakHandler> constructor,
                                                    P constructorParam)
                                             throws InstantiationException, IllegalAccessException,
                                                    java.lang.reflect.InvocationTargetException {
    return constructor.newInstance(constructorParam);
  }

  @SuppressWarnings("unchecked")
  private static <P> Class<P> getConstructorParamClass(P constructorParam) {
    return (Class<P>) constructorParam.getClass();
  }

}