21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 package jdk.jpackage.test; |
23 package jdk.jpackage.test; |
24 |
24 |
25 import java.lang.reflect.Constructor; |
25 import java.lang.reflect.Constructor; |
|
26 import java.lang.reflect.InvocationTargetException; |
26 import java.lang.reflect.Method; |
27 import java.lang.reflect.Method; |
27 import java.lang.reflect.Modifier; |
28 import java.lang.reflect.Modifier; |
|
29 import java.util.Arrays; |
|
30 import java.util.List; |
|
31 import java.util.Objects; |
|
32 import java.util.Optional; |
|
33 import java.util.function.Supplier; |
|
34 import java.util.stream.Collectors; |
|
35 import java.util.stream.Stream; |
28 import jdk.jpackage.test.Functional.ThrowingConsumer; |
36 import jdk.jpackage.test.Functional.ThrowingConsumer; |
29 import jdk.jpackage.test.Functional.ThrowingSupplier; |
|
30 import jdk.jpackage.test.TestInstance.TestDesc; |
37 import jdk.jpackage.test.TestInstance.TestDesc; |
31 |
38 |
32 class MethodCall implements ThrowingConsumer { |
39 class MethodCall implements ThrowingConsumer { |
33 |
40 |
34 MethodCall(Method method, Object... args) { |
41 MethodCall(Object[] instanceCtorArgs, Method method) { |
|
42 this.ctorArgs = Optional.ofNullable(instanceCtorArgs).orElse( |
|
43 DEFAULT_CTOR_ARGS); |
35 this.method = method; |
44 this.method = method; |
36 this.args = args; |
45 this.methodArgs = new Object[0]; |
|
46 } |
|
47 |
|
48 MethodCall(Object[] instanceCtorArgs, Method method, Object arg) { |
|
49 this.ctorArgs = Optional.ofNullable(instanceCtorArgs).orElse( |
|
50 DEFAULT_CTOR_ARGS); |
|
51 this.method = method; |
|
52 this.methodArgs = new Object[]{arg}; |
37 } |
53 } |
38 |
54 |
39 TestDesc createDescription() { |
55 TestDesc createDescription() { |
40 return TestDesc.create(method, args); |
56 var descBuilder = TestDesc.createBuilder().method(method); |
|
57 if (methodArgs.length != 0) { |
|
58 descBuilder.methodArgs(methodArgs); |
|
59 } |
|
60 |
|
61 if (ctorArgs.length != 0) { |
|
62 descBuilder.ctorArgs(ctorArgs); |
|
63 } |
|
64 |
|
65 return descBuilder.get(); |
41 } |
66 } |
42 |
67 |
43 Constructor getRequiredConstructor() throws NoSuchMethodException { |
68 Method getMethod() { |
44 return MethodCall.getRequiredConstructor(method); |
69 return method; |
45 } |
70 } |
46 |
71 |
47 static Constructor getRequiredConstructor(Method method) throws |
72 Object newInstance() throws NoSuchMethodException, InstantiationException, |
48 NoSuchMethodException { |
73 IllegalAccessException, IllegalArgumentException, |
|
74 InvocationTargetException { |
|
75 if ((method.getModifiers() & Modifier.STATIC) != 0) { |
|
76 return null; |
|
77 } |
|
78 |
|
79 Constructor ctor = findRequiredConstructor(method.getDeclaringClass(), |
|
80 ctorArgs); |
|
81 if (ctor.isVarArgs()) { |
|
82 // Assume constructor doesn't have fixed, only variable parameters. |
|
83 return ctor.newInstance(new Object[]{ctorArgs}); |
|
84 } |
|
85 |
|
86 return ctor.newInstance(ctorArgs); |
|
87 } |
|
88 |
|
89 void checkRequiredConstructor() throws NoSuchMethodException { |
49 if ((method.getModifiers() & Modifier.STATIC) == 0) { |
90 if ((method.getModifiers() & Modifier.STATIC) == 0) { |
50 return method.getDeclaringClass().getConstructor(); |
91 findRequiredConstructor(method.getDeclaringClass(), ctorArgs); |
51 } |
92 } |
52 return null; |
93 } |
|
94 |
|
95 private static Constructor findVarArgConstructor(Class type) { |
|
96 return Stream.of(type.getConstructors()).filter( |
|
97 Constructor::isVarArgs).findFirst().orElse(null); |
|
98 } |
|
99 |
|
100 private Constructor findRequiredConstructor(Class type, Object... ctorArgs) |
|
101 throws NoSuchMethodException { |
|
102 |
|
103 Supplier<NoSuchMethodException> notFoundException = () -> { |
|
104 return new NoSuchMethodException(String.format( |
|
105 "No public contructor in %s for %s arguments", type, |
|
106 Arrays.deepToString(ctorArgs))); |
|
107 }; |
|
108 |
|
109 if (Stream.of(ctorArgs).allMatch(Objects::nonNull)) { |
|
110 // No `null` in constructor args, take easy path |
|
111 try { |
|
112 return type.getConstructor(Stream.of(ctorArgs).map( |
|
113 Object::getClass).collect(Collectors.toList()).toArray( |
|
114 Class[]::new)); |
|
115 } catch (NoSuchMethodException ex) { |
|
116 // Failed to find ctor that can take the given arguments. |
|
117 Constructor varArgCtor = findVarArgConstructor(type); |
|
118 if (varArgCtor != null) { |
|
119 // There is one with variable number of arguments. Use it. |
|
120 return varArgCtor; |
|
121 } |
|
122 throw notFoundException.get(); |
|
123 } |
|
124 } |
|
125 |
|
126 List<Constructor> ctors = Stream.of(type.getConstructors()) |
|
127 .filter(ctor -> ctor.getParameterCount() == ctorArgs.length) |
|
128 .collect(Collectors.toList()); |
|
129 |
|
130 if (ctors.isEmpty()) { |
|
131 // No public constructors that can handle the given arguments. |
|
132 throw notFoundException.get(); |
|
133 } |
|
134 |
|
135 if (ctors.size() == 1) { |
|
136 return ctors.iterator().next(); |
|
137 } |
|
138 |
|
139 // Revisit this tricky case when it will start bothering. |
|
140 throw notFoundException.get(); |
53 } |
141 } |
54 |
142 |
55 @Override |
143 @Override |
56 public void accept(Object thiz) throws Throwable { |
144 public void accept(Object thiz) throws Throwable { |
57 method.invoke(thiz, args); |
145 method.invoke(thiz, methodArgs); |
58 } |
146 } |
59 |
147 |
60 private final Object[] args; |
148 private final Object[] methodArgs; |
61 private final Method method; |
149 private final Method method; |
|
150 private final Object[] ctorArgs; |
|
151 |
|
152 final static Object[] DEFAULT_CTOR_ARGS = new Object[0]; |
62 } |
153 } |