2828import net .bytebuddy .pool .TypePool ;
2929import net .bytebuddy .utility .CompoundList ;
3030import net .bytebuddy .utility .FileSystem ;
31+ import net .bytebuddy .utility .QueueFactory ;
3132import net .bytebuddy .utility .StreamDrainer ;
3233import net .bytebuddy .utility .nullability .AlwaysNull ;
3334import net .bytebuddy .utility .nullability .MaybeNull ;
@@ -2518,14 +2519,16 @@ public void remove() {
25182519 interface Element {
25192520
25202521 /**
2521- * Returns the element's relative path and name.
2522+ * Returns the element's relative path and name. If the name ends with a {@code /}, it represents
2523+ * a folder.
25222524 *
25232525 * @return The element's path and name.
25242526 */
25252527 String getName ();
25262528
25272529 /**
2528- * Returns an input stream to read this element's binary information.
2530+ * Returns an input stream to read this element's binary information. Must not be invoked for
2531+ * folders.
25292532 *
25302533 * @return An input stream that represents this element's binary information.
25312534 * @throws IOException If an I/O error occurs.
@@ -2865,15 +2868,15 @@ protected static class CompoundIterator implements Iterator<Element> {
28652868 /**
28662869 * A backlog of iterables to still consider.
28672870 */
2868- private final List <? extends Iterable <? extends Element >> backlog ;
2871+ private final Queue <? extends Iterable <? extends Element >> backlog ;
28692872
28702873 /**
28712874 * Creates a compound iterator.
28722875 *
28732876 * @param iterables The iterables to consider.
28742877 */
28752878 protected CompoundIterator (List <? extends Iterable <? extends Element >> iterables ) {
2876- backlog = iterables ;
2879+ backlog = QueueFactory . make ( iterables ) ;
28772880 forward ();
28782881 }
28792882
@@ -2904,7 +2907,7 @@ public Element next() {
29042907 */
29052908 private void forward () {
29062909 while ((current == null || !current .hasNext ()) && !backlog .isEmpty ()) {
2907- current = backlog .remove (0 ).iterator ();
2910+ current = backlog .remove ().iterator ();
29082911 }
29092912 }
29102913
@@ -3180,23 +3183,23 @@ protected class FolderIterator implements Iterator<Element> {
31803183 /**
31813184 * A list of files and folders to process with the next processed file at the end of the list.
31823185 */
3183- private final List <File > files ;
3186+ private final Queue <File > files ;
31843187
31853188 /**
31863189 * Creates a new iterator representation for all files within a folder.
31873190 *
31883191 * @param folder The root folder.
31893192 */
31903193 protected FolderIterator (File folder ) {
3191- files = new ArrayList < File >( Collections . singleton ( folder ) );
3192- File candidate ;
3193- do {
3194- candidate = files . remove ( files . size () - 1 );
3195- File [] file = candidate .listFiles ();
3196- if ( file != null ) {
3197- files . addAll ( Arrays . asList ( file ));
3194+ files = QueueFactory . make ( );
3195+ File [] file = folder . listFiles () ;
3196+ if ( file != null ) {
3197+ for ( File candidate : file ) {
3198+ if (! candidate .equals ( new File ( folder , JarFile . MANIFEST_NAME ))) {
3199+ files . add ( candidate );
3200+ }
31983201 }
3199- } while (! files . isEmpty () && ( files . get ( files . size () - 1 ). isDirectory () || files . get ( files . size () - 1 ). equals ( new File ( folder , JarFile . MANIFEST_NAME ))));
3202+ }
32003203 }
32013204
32023205 /**
@@ -3211,17 +3214,18 @@ public boolean hasNext() {
32113214 */
32123215 @ SuppressFBWarnings (value = "IT_NO_SUCH_ELEMENT" , justification = "Exception is thrown by invoking removeFirst on an empty list." )
32133216 public Element next () {
3214- try {
3215- return new Element . ForFile ( folder , files . remove ( files . size () - 1 ));
3216- } finally {
3217- while (! files . isEmpty () && ( files . get ( files . size () - 1 ). isDirectory () || files . get ( files . size () - 1 ). equals ( new File ( folder , JarFile . MANIFEST_NAME ))) ) {
3218- File folder = files . remove ( files . size () - 1 );
3219- File [] file = folder . listFiles ();
3220- if ( file != null ) {
3221- files . addAll ( Arrays . asList ( file ));
3217+ File next = files . remove ();
3218+ if ( next . isDirectory ()) {
3219+ File [] file = next . listFiles ();
3220+ if ( file != null ) {
3221+ for ( File candidate : file ) {
3222+ if (! candidate . equals ( new File ( folder , JarFile . MANIFEST_NAME ))) {
3223+ files . add ( candidate );
3224+ }
32223225 }
32233226 }
32243227 }
3228+ return new Element .ForFile (folder , next );
32253229 }
32263230
32273231 /**
@@ -3313,7 +3317,17 @@ public Filtering(Source delegate, ElementMatcher<Element> matcher, boolean manif
33133317 * @return A source that applies an appropriate filter.
33143318 */
33153319 public static Source dropMultiReleaseClassFilesAbove (Source delegate , ClassFileVersion classFileVersion ) {
3316- return new Filtering (delegate , new MultiReleaseVersionMatcher (classFileVersion ), true );
3320+ return new Filtering (delegate , new MultiReleaseVersionMatcher (classFileVersion ));
3321+ }
3322+
3323+ /**
3324+ * Wraps a source to exclude elements that represent folders.
3325+ *
3326+ * @param delegate The delegate source.
3327+ * @return A source that drops folders and delegates to the original source.
3328+ */
3329+ public static Source dropFolders (Source delegate ) {
3330+ return new Filtering (delegate , NoFolderMatcher .INSTANCE );
33173331 }
33183332
33193333 /**
@@ -3368,6 +3382,25 @@ public boolean matches(@MaybeNull Element target) {
33683382 return true ;
33693383 }
33703384 }
3385+
3386+ /**
3387+ * A matcher that removes folders from the iteration.
3388+ */
3389+ @ HashCodeAndEqualsPlugin .Enhance
3390+ protected enum NoFolderMatcher implements ElementMatcher <Element > {
3391+
3392+ /**
3393+ * The singleton instance.
3394+ */
3395+ INSTANCE ;
3396+
3397+ /**
3398+ * {@inheritDoc}
3399+ */
3400+ public boolean matches (@ MaybeNull Element target ) {
3401+ return target == null || target .getName ().endsWith ("/" );
3402+ }
3403+ }
33713404 }
33723405 }
33733406
@@ -3466,18 +3499,21 @@ public void store(ClassFileVersion classFileVersion, Map<TypeDescription, byte[]
34663499 */
34673500 public void retain (Source .Element element ) throws IOException {
34683501 JarEntry entry = element .resolveAs (JarEntry .class );
3502+ String name = element .getName ();
34693503 outputStream .putNextEntry (entry == null
3470- ? new JarEntry (element . getName () )
3504+ ? new JarEntry (name )
34713505 : entry );
3472- InputStream inputStream = element .getInputStream ();
3473- try {
3474- byte [] buffer = new byte [1024 ];
3475- int length ;
3476- while ((length = inputStream .read (buffer )) != -1 ) {
3477- outputStream .write (buffer , 0 , length );
3506+ if (entry != null || !name .endsWith ("/" )) {
3507+ InputStream inputStream = element .getInputStream ();
3508+ try {
3509+ byte [] buffer = new byte [1024 ];
3510+ int length ;
3511+ while ((length = inputStream .read (buffer )) != -1 ) {
3512+ outputStream .write (buffer , 0 , length );
3513+ }
3514+ } finally {
3515+ inputStream .close ();
34783516 }
3479- } finally {
3480- inputStream .close ();
34813517 }
34823518 outputStream .closeEntry ();
34833519 }
@@ -3798,8 +3834,9 @@ public void store(ClassFileVersion classFileVersion, Map<TypeDescription, byte[]
37983834 */
37993835 public void retain (Source .Element element ) throws IOException {
38003836 String name = element .getName ();
3837+ File target = new File (folder , name );
38013838 if (!name .endsWith ("/" )) {
3802- File target = new File ( folder , name ), resolved = element .resolveAs (File .class );
3839+ File resolved = element .resolveAs (File .class );
38033840 if (!target .getCanonicalPath ().startsWith (folder .getCanonicalPath () + File .separatorChar )) {
38043841 throw new IllegalArgumentException (target + " is not a subdirectory of " + folder );
38053842 } else if (!target .getParentFile ().isDirectory () && !target .getParentFile ().mkdirs ()) {
@@ -3827,6 +3864,8 @@ public void retain(Source.Element element) throws IOException {
38273864 inputStream .close ();
38283865 }
38293866 }
3867+ } else if (!target .isDirectory () && !target .mkdirs ()) {
3868+ throw new IllegalStateException ("Cannot create requested directory: " + target );
38303869 }
38313870 }
38323871
0 commit comments