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