1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.bcel.generic;
21
22 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.fail;
25 import static org.junit.jupiter.api.Assumptions.assumeTrue;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.nio.file.FileSystems;
31 import java.nio.file.FileVisitResult;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.PathMatcher;
35 import java.nio.file.Paths;
36 import java.nio.file.SimpleFileVisitor;
37 import java.nio.file.attribute.BasicFileAttributes;
38 import java.util.Enumeration;
39 import java.util.jar.JarEntry;
40 import java.util.jar.JarFile;
41 import java.util.stream.Stream;
42
43 import org.apache.bcel.classfile.ClassParser;
44 import org.apache.bcel.classfile.Code;
45 import org.apache.bcel.classfile.JavaClass;
46 import org.apache.bcel.classfile.Method;
47 import org.apache.bcel.util.ModularRuntimeImage;
48 import org.apache.commons.lang3.JavaVersion;
49 import org.apache.commons.lang3.SystemUtils;
50 import org.junit.jupiter.api.condition.DisabledOnJre;
51 import org.junit.jupiter.api.condition.JRE;
52 import org.junit.jupiter.params.ParameterizedTest;
53 import org.junit.jupiter.params.provider.MethodSource;
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 class JdkGenericDumpTest {
80
81 private static class ClassParserFilesVisitor extends SimpleFileVisitor<Path> {
82
83 private final PathMatcher matcher;
84
85 @SuppressWarnings("resource")
86 ClassParserFilesVisitor(final String pattern) {
87 matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
88 }
89
90 private void find(final Path path) throws IOException {
91 final Path name = path.getFileName();
92 if (name != null && matcher.matches(name)) {
93 try (InputStream inputStream = Files.newInputStream(path)) {
94 final ClassParser classParser = new ClassParser(inputStream, name.toAbsolutePath().toString());
95 assertNotNull(classParser.parse());
96 }
97 }
98 }
99
100 @Override
101 public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
102 find(dir);
103 return FileVisitResult.CONTINUE;
104 }
105
106 @Override
107 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
108 find(file);
109 return FileVisitResult.CONTINUE;
110 }
111
112 @Override
113 public FileVisitResult visitFileFailed(final Path file, final IOException e) {
114 System.err.println(e);
115 return FileVisitResult.CONTINUE;
116 }
117 }
118
119 private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
120
121 private static String bytesToHex(final byte[] bytes) {
122 final char[] hexChars = new char[bytes.length * 3];
123 int i = 0;
124 for (final byte b : bytes) {
125 final int v = b & 0xFF;
126 hexChars[i++] = hexArray[v >>> 4];
127 hexChars[i++] = hexArray[v & 0x0F];
128 hexChars[i++] = ' ';
129 }
130 return new String(hexChars);
131 }
132
133 static Stream<Path> testJdkModules() {
134
135
136 return Stream.concat(JavaHome.streamModulePath(), Stream.of(Paths.get("src/test/resources/jpms/empty/empty.jmod")));
137 }
138
139 private void compare(final String name, final Method method) {
140
141 final Code code = method.getCode();
142 if (code == null) {
143 return;
144 }
145 final byte[] src = code.getCode();
146 final InstructionList instructionList = new InstructionList(src);
147 final byte[] out = instructionList.getByteCode();
148 if (src.length == out.length) {
149 assertArrayEquals(src, out, () -> name + ": " + method.toString());
150 } else {
151 System.out.println(name + ": " + method.toString() + " " + src.length + " " + out.length);
152 System.out.println(bytesToHex(src));
153 System.out.println(bytesToHex(out));
154 for (final InstructionHandle instructionHandle : instructionList) {
155 System.out.println(instructionHandle.toString(false));
156 }
157 fail("Array comparison failure");
158 }
159 }
160
161 private void testJar(final Path file) throws Exception {
162 System.out.println(file);
163 try (JarFile jar = new JarFile(file.toFile())) {
164 final Enumeration<JarEntry> en = jar.entries();
165 while (en.hasMoreElements()) {
166 final JarEntry jarEntry = en.nextElement();
167 final String name = jarEntry.getName();
168 if (name.endsWith(JavaClass.EXTENSION)) {
169
170 try (InputStream inputStream = jar.getInputStream(jarEntry)) {
171 final ClassParser classParser = new ClassParser(inputStream, name);
172 final JavaClass javaClass = classParser.parse();
173 for (final Method method : javaClass.getMethods()) {
174 compare(name, method);
175 }
176 }
177 }
178 }
179 }
180 }
181
182 @ParameterizedTest
183 @MethodSource("org.apache.bcel.generic.JavaHome#streamJarPath")
184 void testJdkJars(final Path jarPath) throws Exception {
185 testJar(jarPath);
186 }
187
188 @ParameterizedTest
189 @DisabledOnJre(value = JRE.JAVA_8)
190 @MethodSource
191 void testJdkModules(final Path jmodPath) throws Exception {
192 testJar(jmodPath);
193 }
194
195 @ParameterizedTest
196 @MethodSource("org.apache.bcel.generic.JavaHome#streamJavaHome")
197 void testJreModules(final JavaHome javaHome) throws Exception {
198 assumeTrue(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9));
199 try (ModularRuntimeImage mri = javaHome.getModularRuntimeImage()) {
200 for (final Path path : mri.modules()) {
201 Files.walkFileTree(path, new ClassParserFilesVisitor("*.class"));
202 }
203 }
204 }
205
206 }