/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * Helper class to find and invoke a class constructors that matches the types of arguments supplied. */ public class ConstructorHelper { private final static Class[] EMPTY_OBJECT_ARRAY_TYPE = new Class[]{(new Object[0]).getClass()}; /** * Find and invoke constructor matching the argument number and types returning an instance * of given class. * * @param clazz is the class of instance to construct * @param arguments is the arguments for the constructor to match in number and type * @return instance of class * @throws IllegalAccessException thrown if no access to class * @throws NoSuchMethodException thrown when the constructor is not found * @throws InvocationTargetException thrown when the ctor throws and exception * @throws InstantiationException thrown when the class cannot be loaded */ public static Object invokeConstructor(Class clazz, Object[] arguments) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException { Class[] parameterTypes = new Class[arguments.length]; for (int i = 0; i < arguments.length; i++) { parameterTypes[i] = arguments[i].getClass(); } // Find a constructor that matches exactly Constructor ctor = getRegularConstructor(clazz, parameterTypes); if (ctor != null) { return ctor.newInstance(arguments); } // Find a constructor with the same number of assignable parameters (such as int -> Integer). ctor = findMatchingConstructor(clazz, parameterTypes); if (ctor != null) { return ctor.newInstance(arguments); } // Find an Object[] constructor, which always matches (throws an exception if not found) ctor = getObjectArrayConstructor(clazz); return ctor.newInstance(new Object[]{arguments}); } private static Constructor findMatchingConstructor(Class clazz, Class[] parameterTypes) { Constructor[] ctors = clazz.getConstructors(); for (int i = 0; i < ctors.length; i++) { Class[] ctorParams = ctors[i].getParameterTypes(); if (isAssignmentCompatible(parameterTypes, ctorParams)) { return ctors[i]; } } return null; } private static boolean isAssignmentCompatible(Class[] parameterTypes, Class[] ctorParams) { if (parameterTypes.length != ctorParams.length) { return false; } for (int i = 0; i < parameterTypes.length; i++) { if (!JavaClassHelper.isAssignmentCompatible(ctorParams[i], parameterTypes[i])) { return false; } } return true; } private static Constructor getRegularConstructor(Class clazz, Class[] parameterTypes) { // Try to find the matching constructor try { Constructor ctor = clazz.getConstructor(parameterTypes); try { ctor.setAccessible(true); } catch (SecurityException se) { // No action } return ctor; } catch (NoSuchMethodException e) { // Thats ok } return null; } // Try to find an Object[] constructor private static Constructor getObjectArrayConstructor(Class clazz) throws NoSuchMethodException { return clazz.getConstructor(EMPTY_OBJECT_ARRAY_TYPE); } private static final Logger log = LoggerFactory.getLogger(ConstructorHelper.class); }