package org.netbeans.gradle.project.others; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.atomic.AtomicReference; import org.jtrim.utils.ExceptionHelper; public final class PluginClassConstructor { private final ClassFinder pluginClass; private final ClassFinder[] argTypeFinders; private final AtomicReference<Constructor<?>> constructorRef; @SuppressWarnings("VolatileArrayField") private volatile Class<?>[] argTypesCache; public PluginClassConstructor(ClassFinder pluginClass, Class<?>... argTypes) { this(pluginClass, ReflectionHelper.constClassFinders(argTypes)); } public PluginClassConstructor(ClassFinder pluginClass, ClassFinder... argTypeFinders) { ExceptionHelper.checkNotNullArgument(pluginClass, "pluginClass"); this.pluginClass = pluginClass; this.argTypeFinders = argTypeFinders.clone(); this.constructorRef = new AtomicReference<>(null); this.argTypesCache = null; ExceptionHelper.checkNotNullElements(this.argTypeFinders, "argTypeFinders"); } private Class<?>[] findArgTypes() { Class<?>[] result = new Class<?>[argTypeFinders.length]; for (int i = 0; i < result.length; i++) { Class<?> argType = argTypeFinders[i].tryGetClass(); if (argType == null) { return null; } result[i] = argTypeFinders[i].tryGetClass(); } return result; } private Class<?>[] getArgTypes() { Class<?>[] result = argTypesCache; if (result == null) { result = findArgTypes(); if (result != null) { argTypesCache = result; } } return result; } public Constructor<?> tryGetConstructor() { Constructor<?> result = constructorRef.get(); if (result == null) { constructorRef.compareAndSet(null, tryFindConstructor()); result = constructorRef.get(); } return result; } private Constructor<?> tryFindConstructor() { Class<?> type = pluginClass.tryGetClass(); if (type == null) { return null; } try { return type.getConstructor(getArgTypes()); } catch (NoSuchMethodException ex) { return null; } } public Object tryCreateInstance(Object... arguments) { Constructor<?> constructor = tryGetConstructor(); try { return constructor != null ? constructor.newInstance(arguments) : null; } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { throw new RuntimeException(ex); } } }