1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.classfile;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertTrue;
22 import static org.junit.jupiter.api.Assertions.fail;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.net.URL;
27 import java.nio.file.Files;
28 import java.nio.file.Paths;
29 import java.util.Enumeration;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33 import org.apache.bcel.util.SyntheticRepository;
34 import org.apache.commons.lang3.StringUtils;
35 import org.junit.jupiter.api.Test;
36 import org.junit.jupiter.params.ParameterizedTest;
37 import org.junit.jupiter.params.provider.ValueSource;
38
39
40
41
42 public class ConstantPoolModuleToStringTestCase {
43
44 static class ToStringVisitor extends EmptyVisitor {
45
46 private final StringBuilder stringBuilder = new StringBuilder();
47 private final ConstantPool pool;
48 private int count;
49
50 public ToStringVisitor(final ConstantPool pool) {
51 this.pool = pool;
52 }
53
54 private void append(final Object obj) {
55 if (!(stringBuilder.length() == 0)) {
56 stringBuilder.append('\n');
57 }
58 stringBuilder.append(obj);
59 }
60
61 @Override
62 public String toString() {
63 return "ToStringVisitor [count=" + count + ", stringBuilder=" + stringBuilder + ", pool=" + pool + "]";
64 }
65
66 @Override
67 public void visitAnnotation(final Annotations obj) {
68 super.visitAnnotation(obj);
69 append(obj);
70 }
71
72 @Override
73 public void visitAnnotationDefault(final AnnotationDefault obj) {
74 super.visitAnnotationDefault(obj);
75 append(obj);
76 }
77
78 @Override
79 public void visitAnnotationEntry(final AnnotationEntry obj) {
80 super.visitAnnotationEntry(obj);
81 append(obj);
82 }
83
84 @Override
85 public void visitBootstrapMethods(final BootstrapMethods obj) {
86 super.visitBootstrapMethods(obj);
87 append(obj);
88 }
89
90 @Override
91 public void visitCode(final Code obj) {
92 super.visitCode(obj);
93 append(obj.toString(true));
94 }
95
96 @Override
97 public void visitCodeException(final CodeException obj) {
98 super.visitCodeException(obj);
99 append(obj.toString(pool, true));
100 }
101
102 @Override
103 public void visitConstantClass(final ConstantClass obj) {
104 super.visitConstantClass(obj);
105 append(obj);
106 }
107
108 @Override
109 public void visitConstantDouble(final ConstantDouble obj) {
110 super.visitConstantDouble(obj);
111 append(obj);
112 }
113
114 @Override
115 public void visitConstantDynamic(final ConstantDynamic constantDynamic) {
116 super.visitConstantDynamic(constantDynamic);
117 append(constantDynamic);
118 }
119
120 @Override
121 public void visitConstantFieldref(final ConstantFieldref obj) {
122 super.visitConstantFieldref(obj);
123 append(obj);
124 }
125
126 @Override
127 public void visitConstantFloat(final ConstantFloat obj) {
128 super.visitConstantFloat(obj);
129 append(obj);
130 }
131
132 @Override
133 public void visitConstantInteger(final ConstantInteger obj) {
134 super.visitConstantInteger(obj);
135 append(obj);
136 }
137
138 @Override
139 public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref obj) {
140 super.visitConstantInterfaceMethodref(obj);
141 append(obj);
142 }
143
144 @Override
145 public void visitConstantInvokeDynamic(final ConstantInvokeDynamic obj) {
146 super.visitConstantInvokeDynamic(obj);
147 append(obj);
148 }
149
150 @Override
151 public void visitConstantLong(final ConstantLong obj) {
152 super.visitConstantLong(obj);
153 append(obj);
154 }
155
156 @Override
157 public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
158 super.visitConstantMethodHandle(obj);
159 append(obj);
160 }
161
162 @Override
163 public void visitConstantMethodref(final ConstantMethodref obj) {
164 super.visitConstantMethodref(obj);
165 append(obj);
166 }
167
168 @Override
169 public void visitConstantMethodType(final ConstantMethodType obj) {
170 super.visitConstantMethodType(obj);
171 append(obj);
172 }
173
174 @Override
175 public void visitConstantModule(final ConstantModule constantModule) {
176 super.visitConstantModule(constantModule);
177 append(constantModule);
178 }
179
180 @Override
181 public void visitConstantNameAndType(final ConstantNameAndType obj) {
182 super.visitConstantNameAndType(obj);
183 append(obj);
184 }
185
186 @Override
187 public void visitConstantPackage(final ConstantPackage constantPackage) {
188 super.visitConstantPackage(constantPackage);
189 append(constantPackage);
190 }
191
192 @Override
193 public void visitConstantPool(final ConstantPool obj) {
194 super.visitConstantPool(obj);
195 append(obj);
196 }
197
198 @Override
199 public void visitConstantString(final ConstantString obj) {
200 super.visitConstantString(obj);
201 append(obj);
202 }
203
204 @Override
205 public void visitConstantUtf8(final ConstantUtf8 obj) {
206 super.visitConstantUtf8(obj);
207 append(obj);
208 }
209
210 @Override
211 public void visitConstantValue(final ConstantValue obj) {
212 super.visitConstantValue(obj);
213 append(obj);
214 }
215
216 @Override
217 public void visitDeprecated(final Deprecated obj) {
218 super.visitDeprecated(obj);
219 append(obj);
220 }
221
222 @Override
223 public void visitEnclosingMethod(final EnclosingMethod obj) {
224 super.visitEnclosingMethod(obj);
225 append(obj);
226 }
227
228 @Override
229 public void visitExceptionTable(final ExceptionTable obj) {
230 super.visitExceptionTable(obj);
231 append(obj);
232 }
233
234 @Override
235 public void visitField(final Field obj) {
236 super.visitField(obj);
237 append(obj);
238 }
239
240 @Override
241 public void visitInnerClass(final InnerClass obj) {
242 super.visitInnerClass(obj);
243 append(obj.toString(pool));
244 }
245
246 @Override
247 public void visitInnerClasses(final InnerClasses obj) {
248 super.visitInnerClasses(obj);
249 append(obj);
250 }
251
252 @Override
253 public void visitJavaClass(final JavaClass obj) {
254 super.visitJavaClass(obj);
255 append(obj);
256 }
257
258 @Override
259 public void visitLineNumber(final LineNumber obj) {
260 super.visitLineNumber(obj);
261 append(obj);
262 }
263
264 @Override
265 public void visitLineNumberTable(final LineNumberTable obj) {
266 super.visitLineNumberTable(obj);
267 append(obj);
268 }
269
270 @Override
271 public void visitLocalVariable(final LocalVariable obj) {
272 super.visitLocalVariable(obj);
273 append(obj);
274 }
275
276 @Override
277 public void visitLocalVariableTable(final LocalVariableTable obj) {
278 super.visitLocalVariableTable(obj);
279 append(obj);
280 }
281
282 @Override
283 public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
284 super.visitLocalVariableTypeTable(obj);
285 append(obj);
286 }
287
288 @Override
289 public void visitMethod(final Method obj) {
290 super.visitMethod(obj);
291 append(obj);
292 }
293
294 @Override
295 public void visitMethodParameter(final MethodParameter obj) {
296 super.visitMethodParameter(obj);
297 append(obj);
298 }
299
300 @Override
301 public void visitMethodParameters(final MethodParameters obj) {
302 super.visitMethodParameters(obj);
303 append(obj);
304 }
305
306 @Override
307 public void visitModule(final Module constantModule) {
308 super.visitModule(constantModule);
309 final String s = constantModule.toString();
310 final Matcher matcher = Pattern.compile(" (\\w+)([:(])").matcher(s);
311 while (matcher.find()) {
312 switch (matcher.group(2)) {
313 case ":":
314 assertTrue(StringUtils.containsAny(matcher.group(1), "name", "flags", "version"));
315 break;
316 case "(":
317 assertTrue(StringUtils.containsAny(matcher.group(1), "requires", "exports", "opens", "uses", "provides"));
318 break;
319 default:
320 break;
321 }
322 }
323 append(constantModule);
324 }
325
326 @Override
327 public void visitModuleExports(final ModuleExports constantModule) {
328 super.visitModuleExports(constantModule);
329 append(constantModule);
330 final String s = constantModule.toString(pool);
331 final String[] tokens = s.split(", ");
332 assertNotNull(tokens);
333 assertEquals(3, tokens.length);
334 assertEquals("0000", tokens[1]);
335 final Matcher matcher = Pattern.compile("to\\((\\d+)\\):").matcher(tokens[2]);
336 assertTrue(matcher.find());
337 assertEquals(Integer.parseInt(matcher.group(1)), StringUtils.countMatches(s, '\n'));
338 }
339
340 @Override
341 public void visitModuleMainClass(final ModuleMainClass obj) {
342 super.visitModuleMainClass(obj);
343 append(obj);
344 }
345
346 @Override
347 public void visitModuleOpens(final ModuleOpens constantModule) {
348 super.visitModuleOpens(constantModule);
349 append(constantModule);
350 final String s = constantModule.toString(pool);
351 final String[] tokens = s.split(", ");
352 assertNotNull(tokens);
353 assertEquals(3, tokens.length);
354 assertEquals("0000", tokens[1]);
355 final Matcher matcher = Pattern.compile("to\\((\\d+)\\):").matcher(tokens[2]);
356 assertTrue(matcher.find());
357 assertEquals(Integer.parseInt(matcher.group(1)), StringUtils.countMatches(s, '\n'));
358 }
359
360 @Override
361 public void visitModulePackages(final ModulePackages constantModule) {
362 super.visitModulePackages(constantModule);
363 append(constantModule);
364 final String s = constantModule.toString();
365 assertEquals(constantModule.getNumberOfPackages(), StringUtils.countMatches(s, '\n'));
366 }
367
368 @Override
369 public void visitModuleProvides(final ModuleProvides constantModule) {
370 super.visitModuleProvides(constantModule);
371 append(constantModule);
372 final String s = constantModule.toString(pool);
373 final String[] tokens = s.split(", ");
374 assertNotNull(tokens);
375 assertEquals(2, tokens.length);
376 final Matcher matcher = Pattern.compile("with\\((\\d+)\\):").matcher(tokens[1]);
377 assertTrue(matcher.find());
378 assertEquals(Integer.parseInt(matcher.group(1)), StringUtils.countMatches(s, '\n'));
379 append(s);
380 }
381
382 @Override
383 public void visitModuleRequires(final ModuleRequires constantModule) {
384 super.visitModuleRequires(constantModule);
385 append(constantModule);
386 append(constantModule.toString(pool));
387 final String s = constantModule.toString(pool).trim();
388 final boolean condition = StringUtils.startsWithAny(s,
389 "jdk.",
390 "java.",
391 "org.junit",
392 "org.apiguardian.api",
393 "org.opentest4j",
394 "net.bytebuddy",
395 "com.sun.jna",
396 "junit",
397 "org.hamcrest");
398 assertTrue(condition, s);
399 }
400
401 @Override
402 public void visitNestHost(final NestHost obj) {
403 super.visitNestHost(obj);
404 append(obj);
405 }
406
407 @Override
408 public void visitNestMembers(final NestMembers obj) {
409 super.visitNestMembers(obj);
410 append(obj);
411 }
412
413 @Override
414 public void visitParameterAnnotation(final ParameterAnnotations obj) {
415 super.visitParameterAnnotation(obj);
416 append(obj);
417 }
418
419 @Override
420 public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
421 super.visitParameterAnnotationEntry(obj);
422 append(obj);
423 }
424
425 @Override
426 public void visitSignature(final Signature obj) {
427 super.visitSignature(obj);
428 append(obj);
429 }
430
431 @Override
432 public void visitSourceFile(final SourceFile obj) {
433 super.visitSourceFile(obj);
434 append(obj);
435 }
436
437 @Override
438 public void visitStackMap(final StackMap obj) {
439 super.visitStackMap(obj);
440 append(obj);
441 }
442
443 @Override
444 public void visitStackMapEntry(final StackMapEntry obj) {
445 super.visitStackMapEntry(obj);
446 append(obj);
447 }
448
449 @Override
450 public void visitSynthetic(final Synthetic obj) {
451 super.visitSynthetic(obj);
452 append(obj);
453 }
454
455 @Override
456 public void visitUnknown(final Unknown obj) {
457 super.visitUnknown(obj);
458 append(obj);
459 }
460 }
461
462 private static void test(final InputStream inputStream) throws IOException {
463 final ClassParser classParser = new ClassParser(inputStream, "module-info.class");
464 final JavaClass javaClass = classParser.parse();
465 testJavaClass(javaClass);
466 }
467
468 private static void testJavaClass(final JavaClass javaClass) {
469 final ConstantPool constantPool = javaClass.getConstantPool();
470 final ToStringVisitor visitor = new ToStringVisitor(constantPool);
471 final DescendingVisitor descendingVisitor = new DescendingVisitor(javaClass, visitor);
472 try {
473 javaClass.accept(descendingVisitor);
474 assertNotNull(visitor.toString());
475 } catch (Exception | Error e) {
476 fail(visitor.toString(), e);
477 }
478 }
479
480 @Test
481 public void test() throws Exception {
482 final Enumeration<URL> moduleURLs = getClass().getClassLoader().getResources("module-info.class");
483 while (moduleURLs.hasMoreElements()) {
484 final URL url = moduleURLs.nextElement();
485 try (InputStream inputStream = url.openStream()) {
486 test(inputStream);
487 }
488 }
489 }
490
491 @ParameterizedTest
492 @ValueSource(strings = {
493
494 "src/test/resources/jpms/java11/commons-io/module-info.class",
495 "src/test/resources/jpms/java17/commons-io/module-info.class",
496 "src/test/resources/jpms/java18/commons-io/module-info.class",
497 "src/test/resources/jpms/java19-ea/commons-io/module-info.class"})
498
499 public void test(final String first) throws Exception {
500 try (final InputStream inputStream = Files.newInputStream(Paths.get(first))) {
501 test(inputStream);
502 }
503 }
504
505 @ParameterizedTest
506 @ValueSource(strings = {
507
508 "java.lang.CharSequence$1CharIterator",
509 "org.apache.commons.lang3.function.TriFunction",
510
511 "org.apache.commons.lang3.math.NumberUtils",
512 "org.apache.bcel.Const",
513 "java.io.StringBufferInputStream",
514 "java.nio.file.Files",
515 "org.junit.jupiter.api.AssertionsKt",
516 "javax.annotation.ManagedBean",
517 "javax.management.remote.rmi.RMIConnectionImpl_Stub"})
518
519 public void testClass(final String className) throws Exception {
520 testJavaClass(SyntheticRepository.getInstance().loadClass(className));
521 }
522 }