test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java
branchJDK-8200758-branch
changeset 58648 3bf53ffa9ae7
parent 58416 f09bf58c1f17
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java	Wed Oct 16 09:57:23 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java	Wed Oct 16 10:32:08 2019 -0400
@@ -23,40 +23,131 @@
 package jdk.jpackage.test;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import jdk.jpackage.test.Functional.ThrowingConsumer;
-import jdk.jpackage.test.Functional.ThrowingSupplier;
 import jdk.jpackage.test.TestInstance.TestDesc;
 
 class MethodCall implements ThrowingConsumer {
 
-    MethodCall(Method method, Object... args) {
+    MethodCall(Object[] instanceCtorArgs, Method method) {
+        this.ctorArgs = Optional.ofNullable(instanceCtorArgs).orElse(
+                DEFAULT_CTOR_ARGS);
         this.method = method;
-        this.args = args;
+        this.methodArgs = new Object[0];
+    }
+
+    MethodCall(Object[] instanceCtorArgs, Method method, Object arg) {
+        this.ctorArgs = Optional.ofNullable(instanceCtorArgs).orElse(
+                DEFAULT_CTOR_ARGS);
+        this.method = method;
+        this.methodArgs = new Object[]{arg};
     }
 
     TestDesc createDescription() {
-        return TestDesc.create(method, args);
+        var descBuilder = TestDesc.createBuilder().method(method);
+        if (methodArgs.length != 0) {
+            descBuilder.methodArgs(methodArgs);
+        }
+
+        if (ctorArgs.length != 0) {
+            descBuilder.ctorArgs(ctorArgs);
+        }
+
+        return descBuilder.get();
+    }
+
+    Method getMethod() {
+        return method;
     }
 
-    Constructor getRequiredConstructor() throws NoSuchMethodException {
-        return MethodCall.getRequiredConstructor(method);
+    Object newInstance() throws NoSuchMethodException, InstantiationException,
+            IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException {
+        if ((method.getModifiers() & Modifier.STATIC) != 0) {
+            return null;
+        }
+
+        Constructor ctor = findRequiredConstructor(method.getDeclaringClass(),
+                ctorArgs);
+        if (ctor.isVarArgs()) {
+            // Assume constructor doesn't have fixed, only variable parameters.
+            return ctor.newInstance(new Object[]{ctorArgs});
+        }
+
+        return ctor.newInstance(ctorArgs);
+    }
+
+    void checkRequiredConstructor() throws NoSuchMethodException {
+        if ((method.getModifiers() & Modifier.STATIC) == 0) {
+            findRequiredConstructor(method.getDeclaringClass(), ctorArgs);
+        }
     }
 
-    static Constructor getRequiredConstructor(Method method) throws
-            NoSuchMethodException {
-        if ((method.getModifiers() & Modifier.STATIC) == 0) {
-            return method.getDeclaringClass().getConstructor();
+    private static Constructor findVarArgConstructor(Class type) {
+        return Stream.of(type.getConstructors()).filter(
+                Constructor::isVarArgs).findFirst().orElse(null);
+    }
+
+    private Constructor findRequiredConstructor(Class type, Object... ctorArgs)
+            throws NoSuchMethodException {
+
+        Supplier<NoSuchMethodException> notFoundException = () -> {
+            return new NoSuchMethodException(String.format(
+                    "No public contructor in %s for %s arguments", type,
+                    Arrays.deepToString(ctorArgs)));
+        };
+
+        if (Stream.of(ctorArgs).allMatch(Objects::nonNull)) {
+            // No `null` in constructor args, take easy path
+            try {
+                return type.getConstructor(Stream.of(ctorArgs).map(
+                        Object::getClass).collect(Collectors.toList()).toArray(
+                        Class[]::new));
+            } catch (NoSuchMethodException ex) {
+                // Failed to find ctor that can take the given arguments.
+                Constructor varArgCtor = findVarArgConstructor(type);
+                if (varArgCtor != null) {
+                    // There is one with variable number of arguments. Use it.
+                    return varArgCtor;
+                }
+                throw notFoundException.get();
+            }
         }
-        return null;
+
+        List<Constructor> ctors = Stream.of(type.getConstructors())
+                .filter(ctor -> ctor.getParameterCount() == ctorArgs.length)
+                .collect(Collectors.toList());
+
+        if (ctors.isEmpty()) {
+            // No public constructors that can handle the given arguments.
+            throw notFoundException.get();
+        }
+
+        if (ctors.size() == 1) {
+            return ctors.iterator().next();
+        }
+
+        // Revisit this tricky case when it will start bothering.
+        throw notFoundException.get();
     }
 
     @Override
     public void accept(Object thiz) throws Throwable {
-        method.invoke(thiz, args);
+        method.invoke(thiz, methodArgs);
     }
 
-    private final Object[] args;
+    private final Object[] methodArgs;
     private final Method method;
+    private final Object[] ctorArgs;
+
+    final static Object[] DEFAULT_CTOR_ARGS = new Object[0];
 }