-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJdkProxyTests.java
193 lines (157 loc) Β· 6.26 KB
/
JdkProxyTests.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package coding.toast.bread.proxy;
import coding.toast.bread.proxy.service.WorkerManageService;
import coding.toast.bread.proxy.service.WorkerManageServiceImpl;
import coding.toast.bread.proxy.vo.DEPT;
import coding.toast.bread.proxy.vo.Worker;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Java Built-in Proxy API Test Class<br>
*
* @see WorkerManageServiceImpl
* @see Worker
*/
@Slf4j
public class JdkProxyTests {
private static final List<Worker> predefinedWorkerList = List.of(
new Worker(1L, "Norberto Weyand", DEPT.DEVELOP),
new Worker(2L, "Nadene Hoelscher", DEPT.DEVELOP),
new Worker(3L, "Salvadore Cardona", DEPT.HR),
new Worker(4L, "Kaija Brittingham", DEPT.HR),
new Worker(5L, "Tarsha Steiger", DEPT.HR),
new Worker(6L, "Lashun Eades", DEPT.DEVELOP),
new Worker(7L, "Aranda Laney", DEPT.ACCOUNT),
new Worker(8L, "Chevy Choy", DEPT.DEVELOP),
new Worker(9L, "Talayah Gassaway", DEPT.ACCOUNT),
new Worker(10L, "Kandee Pabon", DEPT.ACCOUNT),
new Worker(11L, "Chanette Mcduffie", DEPT.ACCOUNT),
new Worker(12L, "Graham Obregon", DEPT.HR)
);
private static final WorkerManageServiceImpl service = new WorkerManageServiceImpl(predefinedWorkerList);
@Test
@DisplayName("how to use Proxy.newProxyInstance?")
void simpleProxyTest() {
WorkerManageService proxyService = (WorkerManageService) Proxy.newProxyInstance(
WorkerManageService.class.getClassLoader(),
new Class[]{WorkerManageService.class},
new InvocationHandler() { // after this test code, won't use InvocationHandler but will use lambda expression.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(service, args);
}
}
);
Worker workerWithId = proxyService.findWorkerWithId(1L);
Worker compareWorker = new Worker(1L, "Norberto Weyand", DEPT.DEVELOP);
assertThat(workerWithId).isEqualTo(compareWorker);
}
@Test
@DisplayName("Logs π for all method calls")
void DecorateLoggingProxyTest() {
WorkerManageService proxyService = (WorkerManageService) Proxy.newProxyInstance(
WorkerManageService.class.getClassLoader(),
new Class[]{WorkerManageService.class},
new ThumbsUpDecoInvocationHandler(service)
);
Worker workerWithId = proxyService.findWorkerWithId(1L);
Worker compareWorker = new Worker(1L, "Norberto Weyand", DEPT.DEVELOP);
assertThat(workerWithId).isEqualTo(compareWorker);
}
/**
* relate with {@link #DecorateLoggingProxyTest() DecorateLoggingProxy Test Method}
*/
static final class ThumbsUpDecoInvocationHandler implements InvocationHandler {
private final Object proxyTarget;
private ThumbsUpDecoInvocationHandler(Object proxyTarget) {
Objects.requireNonNull(proxyTarget);
this.proxyTarget = proxyTarget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("πππππππππππππππππ");
Object returnVal = method.invoke(proxyTarget, args);
log.info("method return value = {}", returnVal);
log.info("πππππππππππππππππ");
return returnVal;
}
}
@Test
@DisplayName("If there is a name value in the return value, it will be hidden.")
void HideSensitiveProxyTest() {
// create proxy
WorkerManageService proxyService = (WorkerManageService) Proxy.newProxyInstance(
WorkerManageService.class.getClassLoader(),
new Class[]{WorkerManageService.class},
new HideSensitiveInvocationHandler(service)
);
// get security String
String securityString = HideSensitiveInvocationHandler.securityString;
// find Worker who has id = 1
Worker workerWithId = proxyService.findWorkerWithId(1L);
// create testWorker
Worker findWorker = new Worker(workerWithId.id(), securityString, workerWithId.dept());
// test (1)
assertThat(workerWithId).isEqualTo(findWorker);
// test (2)
assertThat(proxyService.workerList()).allSatisfy(worker
-> assertThat(worker.name()).isEqualTo(securityString));
}
/**
* This InvocationHandler performs encryption if the return value contains a name.
* (relate with {@link #HideSensitiveProxyTest() EncryptedReturnValTest Test Method})<br>
* <br>
* The following are the methods that expose names:<br>
* <ul>
* <li>{@link WorkerManageService#workerList() workerList}</li>
* <li>{@link WorkerManageService#workerListSort(Comparator) workerListSort}</li>
* <li>{@link WorkerManageService#findWorkerWithId(long) findWorkerWithId}</li>
* </ul>
*/
static final class HideSensitiveInvocationHandler implements InvocationHandler {
private final Object proxyTarget;
private final List<String> targetMethodNameList = List.of(
"workerList",
"workerListSort",
"findWorkerWithId"
);
static final String securityString = "[SENSITIVE INFORMATION CANNOT BE EXPOSED]";
private HideSensitiveInvocationHandler(Object proxyTarget) {
Objects.requireNonNull(proxyTarget);
this.proxyTarget = proxyTarget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnVal = method.invoke(proxyTarget, args);
String name = method.getName();
if (targetMethodNameList.contains(name)) {
log.debug("method name: {}", name);
returnVal = hideNameValue(name, returnVal);
}
return returnVal;
}
@SuppressWarnings("unchecked")
private Object hideNameValue(String invokedMethodName, Object convertTarget) {
return switch (invokedMethodName) {
case "workerList", "workerListSort" -> {
List<Worker> returnVal1 = (List<Worker>) convertTarget;
yield returnVal1.stream()
.map(worker -> new Worker(worker.id(), securityString, worker.dept()))
.toList();
}
case "findWorkerWithId" -> {
Worker worker = (Worker) convertTarget;
yield new Worker(worker.id(), securityString, worker.dept());
}
default -> throw new IllegalStateException("Unexpected value: " + invokedMethodName);
};
}
}
}