This repository has been archived by the owner on Feb 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathParameteredConstructorInvocationTest.java
136 lines (111 loc) · 5.18 KB
/
ParameteredConstructorInvocationTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package none.cvg.constructors;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import none.cvg.DemoClass;
import none.cvg.HandlesKataDisplayNames;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import static none.cvg.ErrorMessages.REFLECTION_FAILURE;
import static none.cvg.ErrorMessages.TEST_FAILURE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
/*
* TODO:
* This test aims at using MethodHandles to invoke a constructor with a parameter on a class in
* order to create a new instance.
* Each solved test shows how this can be achieved with the traditional reflection calls.
* Each unsolved test provides a few hints that will allow the kata-taker to manually solve
* the exercise to achieve the same goal with MethodHandles.
*/
@DisplayNameGeneration(HandlesKataDisplayNames.class)
@DisplayName("Invoke DemoClass(String)")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ParameteredConstructorInvocationTest {
@Test
@Tag("PASSING")
@Order(1)
public void reflectionParamConstructor() {
String expectedOutput = "[Constructor Demo]" +
" - Constructor via reflection";
try {
Class<DemoClass> demoClassClass =
(Class<DemoClass>) Class.forName("none.cvg.DemoClass");
Constructor<DemoClass> demoClassConstructor =
demoClassClass.getConstructor(String.class);
DemoClass demoClass =
demoClassConstructor.newInstance("Constructor Demo");
assertEquals(expectedOutput,
demoClass.printStuff("Constructor via reflection"),
"Reflection invocation failed");
} catch (ClassNotFoundException | NoSuchMethodException |
InstantiationException | IllegalAccessException | InvocationTargetException e) {
fail(REFLECTION_FAILURE.getValue() + e.getMessage());
}
}
@Test
@Tag("TODO")
@Order(2)
public void methodHandleParamConstructor() {
String expectedOutput = "[Constructor Demo] - Constructor via Method Handles";
/*
* TODO:
* The API provides a few lookup mechanisms. For a public constructor, on a
* public class, we can use the lookup with minimal checks and trust.
* Public members of public classes are looked up via "public lookups"
* Check API: java.lang.invoke.MethodHandles.publicLookup()
*/
MethodHandles.Lookup publicMethodHandlesLookup = null;
/*
* TODO:
* Create a methodType instance that matches the constructor that takes a string param
* Constructors should have a void return type
* This constructor has a string parameter
* Search for method that: has a return type of void (Constructor)
* and accepts a String parameter.
* Check API: java.lang.invoke.MethodType.methodType(?, ?)
*/
MethodType methodType = null; // HINT: MethodType.methodType(?, ?);
try {
/*
* TODO:
* Replace the "nulls" to find a constructor handle for DemoClass using methodType
* "Find" a constructor of the class via the Lookup instance,
* based on the methodType described above
* Check API: java.lang.invoke.MethodHandles.Lookup.findConstructor(?, ?)
*/
MethodHandle demoClassConstructor =
publicMethodHandlesLookup.findConstructor(null, null);
// Hint: Class and MethodType
/*
* TODO:
* Invoke the constructor and pass in "Constructor Demo" as the parameter.
* Create an instance of the DemoClass by invoking the method handle
* The MethodHandle has two methods invoke() and invokeExact()
* The invoke() is good for conversion/substitution of param types
* The invokeExact() is great if there is no ambiguity
* Check API: java.lang.invoke.MethodHandle.invokeExact(?)
*/
DemoClass demoClass =
null; //HINT: invokeExact(
//constructor argument(s)); Requires casting.
assertEquals(expectedOutput,
demoClass.printStuff(
"Constructor via Method Handles"),
"Method handles invocation failed");
} catch (NoSuchMethodException | IllegalAccessException e) {
fail("Failed to execute a constructor invocation via Method Handles: "
+ e.getMessage());
} catch (Throwable t) {
// invokeExact() throws a Throwable (hence catching Throwable separately).
fail(TEST_FAILURE.getValue() + t.getMessage());
}
}
}