gobblin.util.reflection.GobblinConstructorUtils.java Source code

Java tutorial

Introduction

Here is the source code for gobblin.util.reflection.GobblinConstructorUtils.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package gobblin.util.reflection;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.reflect.ConstructorUtils;

/**
 * Helper methods to instantiate classes
 */
@Slf4j
public class GobblinConstructorUtils {

    /**
     * Convenience method on top of {@link ConstructorUtils#invokeConstructor(Class, Object[])} that returns a new
     * instance of the <code>cls</code> based on a constructor priority order. Each {@link List} in the
     * <code>constructorArgs</code> array contains the arguments for a constructor of <code>cls</code>. The first
     * constructor whose signature matches the argument types will be invoked.
     *
     * @param cls the class to be instantiated
     * @param constructorArgs An array of constructor argument list. Order defines the priority of a constructor.
     * @return
     *
     * @throws NoSuchMethodException if no constructor matched was found
     */
    @SafeVarargs
    public static <T> T invokeFirstConstructor(Class<T> cls, List<Object>... constructorArgs)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
            InstantiationException {

        for (List<Object> args : constructorArgs) {

            Class<?>[] parameterTypes = new Class[args.size()];
            for (int i = 0; i < args.size(); i++) {
                parameterTypes[i] = args.get(i).getClass();
            }

            if (ConstructorUtils.getMatchingAccessibleConstructor(cls, parameterTypes) != null) {
                return ConstructorUtils.invokeConstructor(cls, args.toArray(new Object[args.size()]));
            }
        }
        throw new NoSuchMethodException("No accessible constructor found");
    }

    /**
     * Returns a new instance of the <code>cls</code> based on a set of arguments. The method will search for a
     * constructor accepting the first k arguments in <code>args</code> for every k from args.length to 0, and will
     * invoke the first constructor found.
     *
     * For example, {@link #invokeLongestConstructor}(cls, myString, myInt) will first attempt to create an object with
     * of class <code>cls</code> with constructor <init>(String, int), if it fails it will attempt <init>(String), and
     * finally <init>().
     *
     * @param cls the class to instantiate.
     * @param args the arguments to use for instantiation.
     * @throws ReflectiveOperationException
     */
    public static <T> T invokeLongestConstructor(Class<T> cls, Object... args) throws ReflectiveOperationException {

        Class<?>[] parameterTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            parameterTypes[i] = args[i].getClass();
        }

        for (int i = args.length; i >= 0; i--) {
            if (ConstructorUtils.getMatchingAccessibleConstructor(cls,
                    Arrays.copyOfRange(parameterTypes, 0, i)) != null) {
                log.info(String.format("Found accessible constructor for class %s with parameter types %s.", cls,
                        Arrays.toString(Arrays.copyOfRange(parameterTypes, 0, i))));
                return ConstructorUtils.invokeConstructor(cls, Arrays.copyOfRange(args, 0, i));
            }
        }
        throw new NoSuchMethodException(
                String.format("No accessible constructor for class %s with parameters a subset of %s.", cls,
                        Arrays.toString(parameterTypes)));
    }

    /**
     * Utility method to create an instance of <code>clsName</code> using the constructor matching the arguments, <code>args</code>
     *
     * @param superType of <code>clsName</code>. The new instance is cast to superType
     * @param clsName complete cannonical name of the class to be instantiated
     * @param args constructor args to be used
     *
     * @throws IllegalArgumentException if there was an issue creating the instance due to
     * {@link NoSuchMethodException}, {@link InvocationTargetException},{@link InstantiationException},
     *  {@link ClassNotFoundException}
     *
     * @return A new instance of <code>clsName</code>
     */
    @SuppressWarnings("unchecked")
    public static <T> T invokeConstructor(final Class<T> superType, final String clsName, Object... args) {

        try {
            return (T) ConstructorUtils.invokeConstructor(Class.forName(clsName), args);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException
                | ClassNotFoundException e) {
            throw new IllegalArgumentException(e);
        }
    }
}