|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
4 | 4 | *
|
5 | 5 | * This code is free software; you can redistribute it and/or modify it
|
|
41 | 41 | import java.nio.file.Path;
|
42 | 42 | import java.util.ArrayList;
|
43 | 43 | import java.util.Collections;
|
44 |
| -import java.util.Iterator; |
45 | 44 | import java.util.List;
|
46 |
| -import java.util.NoSuchElementException; |
47 | 45 | import java.util.Set;
|
| 46 | +import java.util.function.Consumer; |
48 | 47 | import java.util.jar.JarEntry;
|
49 | 48 | import java.util.jar.JarFile;
|
50 | 49 | import java.util.stream.Collectors;
|
@@ -102,6 +101,10 @@ public List<String> skippedEntries() {
|
102 | 101 | return skippedEntries;
|
103 | 102 | }
|
104 | 103 |
|
| 104 | + protected void skipEntry(Throwable ex, String entryPath) { |
| 105 | + skippedEntries.add(String.format("%s: %s", ex.toString(), entryPath)); |
| 106 | + } |
| 107 | + |
105 | 108 | /**
|
106 | 109 | * Returns all entries in this archive.
|
107 | 110 | */
|
@@ -135,8 +138,15 @@ public ClassModel getClassFile(String name) throws IOException {
|
135 | 138 | return null;
|
136 | 139 | }
|
137 | 140 |
|
138 |
| - public Iterable<ClassModel> getClassFiles() throws IOException { |
139 |
| - return FileIterator::new; |
| 141 | + public void forEachClassFile(Consumer<ClassModel> handler) throws IOException { |
| 142 | + if (baseFileName.endsWith(".class")) { |
| 143 | + // propagate ClassFileError for single file |
| 144 | + try { |
| 145 | + handler.accept(readClassFile(path)); |
| 146 | + } catch (ClassFileError ex) { |
| 147 | + skipEntry(ex, path.toString()); |
| 148 | + } |
| 149 | + } |
140 | 150 | }
|
141 | 151 |
|
142 | 152 | protected ClassModel readClassFile(Path p) throws IOException {
|
@@ -167,33 +177,6 @@ static boolean isClass(Path file) {
|
167 | 177 | public void close() throws IOException {
|
168 | 178 | }
|
169 | 179 |
|
170 |
| - class FileIterator implements Iterator<ClassModel> { |
171 |
| - int count; |
172 |
| - FileIterator() { |
173 |
| - this.count = 0; |
174 |
| - } |
175 |
| - public boolean hasNext() { |
176 |
| - return count == 0 && baseFileName.endsWith(".class"); |
177 |
| - } |
178 |
| - |
179 |
| - public ClassModel next() { |
180 |
| - if (!hasNext()) { |
181 |
| - throw new NoSuchElementException(); |
182 |
| - } |
183 |
| - try { |
184 |
| - ClassModel cf = readClassFile(path); |
185 |
| - count++; |
186 |
| - return cf; |
187 |
| - } catch (IOException e) { |
188 |
| - throw new ClassFileError(e); |
189 |
| - } |
190 |
| - } |
191 |
| - |
192 |
| - public void remove() { |
193 |
| - throw new UnsupportedOperationException("Not supported yet."); |
194 |
| - } |
195 |
| - } |
196 |
| - |
197 | 180 | public String toString() {
|
198 | 181 | return path.toString();
|
199 | 182 | }
|
@@ -241,42 +224,17 @@ public ClassModel getClassFile(String name) throws IOException {
|
241 | 224 | return null;
|
242 | 225 | }
|
243 | 226 |
|
244 |
| - public Iterable<ClassModel> getClassFiles() throws IOException { |
245 |
| - final Iterator<ClassModel> iter = new DirectoryIterator(); |
246 |
| - return () -> iter; |
247 |
| - } |
248 |
| - |
249 |
| - class DirectoryIterator implements Iterator<ClassModel> { |
250 |
| - private final List<Path> entries; |
251 |
| - private int index = 0; |
252 |
| - DirectoryIterator() throws IOException { |
253 |
| - List<Path> paths = null; |
254 |
| - try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE)) { |
255 |
| - paths = stream.filter(ClassFileReader::isClass).toList(); |
256 |
| - |
257 |
| - } |
258 |
| - this.entries = paths; |
259 |
| - this.index = 0; |
260 |
| - } |
261 |
| - |
262 |
| - public boolean hasNext() { |
263 |
| - return index != entries.size(); |
264 |
| - } |
265 |
| - |
266 |
| - public ClassModel next() { |
267 |
| - if (!hasNext()) { |
268 |
| - throw new NoSuchElementException(); |
269 |
| - } |
270 |
| - Path path = entries.get(index++); |
271 |
| - try { |
272 |
| - return readClassFile(path); |
273 |
| - } catch (IOException e) { |
274 |
| - throw new ClassFileError(e); |
275 |
| - } |
276 |
| - } |
277 |
| - |
278 |
| - public void remove() { |
279 |
| - throw new UnsupportedOperationException("Not supported yet."); |
| 227 | + @Override |
| 228 | + public void forEachClassFile(Consumer<ClassModel> handler) throws IOException { |
| 229 | + try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE)) { |
| 230 | + stream.filter(ClassFileReader::isClass) |
| 231 | + .forEach(e -> { |
| 232 | + try { |
| 233 | + handler.accept(readClassFile(e)); |
| 234 | + } catch (ClassFileError | IOException ex) { |
| 235 | + skipEntry(ex, e.toString()); |
| 236 | + } |
| 237 | + }); |
280 | 238 | }
|
281 | 239 | }
|
282 | 240 | }
|
@@ -314,14 +272,15 @@ private static JarFile openJarFile(File f, Runtime.Version version)
|
314 | 272 | return jf;
|
315 | 273 | }
|
316 | 274 |
|
| 275 | + private static boolean isJarEntryClass(JarEntry e) { |
| 276 | + return e.getName().endsWith(".class"); |
| 277 | + } |
| 278 | + |
317 | 279 | protected Set<String> scan() {
|
318 |
| - try (JarFile jf = openJarFile(path.toFile(), version)) { |
319 |
| - return jf.versionedStream().map(JarEntry::getName) |
320 |
| - .filter(n -> n.endsWith(".class")) |
321 |
| - .collect(Collectors.toSet()); |
322 |
| - } catch (IOException e) { |
323 |
| - throw new UncheckedIOException(e); |
324 |
| - } |
| 280 | + return jarfile.versionedStream() |
| 281 | + .filter(JarFileReader::isJarEntryClass) |
| 282 | + .map(JarEntry::getName) |
| 283 | + .collect(Collectors.toSet()); |
325 | 284 | }
|
326 | 285 |
|
327 | 286 | public ClassModel getClassFile(String name) throws IOException {
|
@@ -358,76 +317,17 @@ protected ClassModel readClassFile(JarFile jarfile, JarEntry e) throws IOExcepti
|
358 | 317 | }
|
359 | 318 | }
|
360 | 319 |
|
361 |
| - public Iterable<ClassModel> getClassFiles() throws IOException { |
362 |
| - final Iterator<ClassModel> iter = new JarFileIterator(this, jarfile); |
363 |
| - return () -> iter; |
364 |
| - } |
365 |
| - } |
366 |
| - |
367 |
| - class JarFileIterator implements Iterator<ClassModel> { |
368 |
| - protected final JarFileReader reader; |
369 |
| - protected Iterator<JarEntry> entries; |
370 |
| - protected JarFile jf; |
371 |
| - protected JarEntry nextEntry; |
372 |
| - protected ClassModel cf; |
373 |
| - JarFileIterator(JarFileReader reader) { |
374 |
| - this(reader, null); |
375 |
| - } |
376 |
| - JarFileIterator(JarFileReader reader, JarFile jarfile) { |
377 |
| - this.reader = reader; |
378 |
| - setJarFile(jarfile); |
379 |
| - } |
380 |
| - |
381 |
| - void setJarFile(JarFile jarfile) { |
382 |
| - if (jarfile == null) return; |
383 |
| - |
384 |
| - this.jf = jarfile; |
385 |
| - this.entries = jarfile.versionedStream().iterator(); |
386 |
| - this.nextEntry = nextEntry(); |
387 |
| - } |
388 |
| - |
389 |
| - public boolean hasNext() { |
390 |
| - if (nextEntry != null && cf != null) { |
391 |
| - return true; |
392 |
| - } |
393 |
| - while (nextEntry != null) { |
394 |
| - try { |
395 |
| - cf = reader.readClassFile(jf, nextEntry); |
396 |
| - return true; |
397 |
| - } catch (ClassFileError | IOException ex) { |
398 |
| - skippedEntries.add(String.format("%s: %s (%s)", |
399 |
| - ex.getMessage(), |
400 |
| - nextEntry.getName(), |
401 |
| - jf.getName())); |
402 |
| - } |
403 |
| - nextEntry = nextEntry(); |
404 |
| - } |
405 |
| - return false; |
406 |
| - } |
407 |
| - |
408 |
| - public ClassModel next() { |
409 |
| - if (!hasNext()) { |
410 |
| - throw new NoSuchElementException(); |
411 |
| - } |
412 |
| - ClassModel classFile = cf; |
413 |
| - cf = null; |
414 |
| - nextEntry = nextEntry(); |
415 |
| - return classFile; |
416 |
| - } |
417 |
| - |
418 |
| - protected JarEntry nextEntry() { |
419 |
| - while (entries.hasNext()) { |
420 |
| - JarEntry e = entries.next(); |
421 |
| - String name = e.getName(); |
422 |
| - if (name.endsWith(".class")) { |
423 |
| - return e; |
424 |
| - } |
425 |
| - } |
426 |
| - return null; |
427 |
| - } |
428 |
| - |
429 |
| - public void remove() { |
430 |
| - throw new UnsupportedOperationException("Not supported yet."); |
| 320 | + @Override |
| 321 | + public void forEachClassFile(Consumer<ClassModel> handler) throws IOException { |
| 322 | + jarfile.versionedStream() |
| 323 | + .filter(JarFileReader::isJarEntryClass) |
| 324 | + .forEach(e -> { |
| 325 | + try { |
| 326 | + handler.accept(readClassFile(jarfile, e)); |
| 327 | + } catch (ClassFileError | IOException ex) { |
| 328 | + skipEntry(ex, e.getName() + " (" + jarfile.getName() + ")"); |
| 329 | + } |
| 330 | + }); |
431 | 331 | }
|
432 | 332 | }
|
433 | 333 | }
|
0 commit comments