Merge remote-tracking branch 'aosp/upstream-master' am: 02bd81f6e8 am: cc522d0053

Original change: https://android-review.googlesource.com/c/platform/external/jarjar/+/2904651

Change-Id: Icf1b70e87e1ab7171a2d2fbdbf69efb17e5eb721
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.allstar/binary_artifacts.yaml b/.allstar/binary_artifacts.yaml
new file mode 100644
index 0000000..c8a822f
--- /dev/null
+++ b/.allstar/binary_artifacts.yaml
@@ -0,0 +1,4 @@
+# Exemption reason: The ant build relies on dependencies in lib/ and predates allstar
+# Exemption timeframe: permanent
+optConfig:
+  optOut: true
diff --git a/build.xml b/build.xml
index d0d73f5..9eb947a 100644
--- a/build.xml
+++ b/build.xml
@@ -5,8 +5,8 @@
 
     <property name="javadoc.access" value="public"/>
 
-    <property name="compile.source" value="1.5"/>
-    <property name="compile.target" value="1.5"/>
+    <property name="compile.source" value="1.6"/>
+    <property name="compile.target" value="1.6"/>
     <property name="compile.bootclasspath" value=""/>
     <property name="compile.extdirs" value=""/>
 
@@ -95,9 +95,9 @@
         <mkdir dir="dist"/>
         <jarjar jarfile="${jarfile}">
             <fileset dir="build/main"/>
-            <zipfileset src="lib/asm-4.0.jar"/>
-            <zipfileset src="lib/asm-commons-4.0.jar">
-                <include name="org/objectweb/asm/commons/Remap*.class"/>
+            <zipfileset src="lib/asm-7.3.1.jar"/>
+            <zipfileset src="lib/asm-commons-7.3.1.jar">
+                <include name="org/objectweb/asm/commons/*Remapper.class"/>
                 <include name="org/objectweb/asm/commons/LocalVariablesSorter.class"/>
             </zipfileset>
         	<keep pattern="com.tonicsystems.jarjar.Main"/>
@@ -208,8 +208,8 @@
         <delete file="${test.jar}"/>
         <jarjar2 jarfile="${test.jar}">
             <fileset dir="build/main"/>
-            <zipfileset src="lib/asm-4.0.jar"/>
-            <zipfileset src="lib/asm-commons-4.0.jar"/>
+            <zipfileset src="lib/asm-7.3.1.jar"/>
+            <zipfileset src="lib/asm-commons-7.3.1.jar"/>
             <rule pattern="org.objectweb.asm.**" result="com.tonicsystems.jarjar.asm.@1"/>
         </jarjar2>
         <delete file="${test.jar}"/>
diff --git a/lib/asm-4.0.jar b/lib/asm-4.0.jar
deleted file mode 100644
index cca0d9c..0000000
--- a/lib/asm-4.0.jar
+++ /dev/null
Binary files differ
diff --git a/lib/asm-7.3.1.jar b/lib/asm-7.3.1.jar
new file mode 100644
index 0000000..8a50266
--- /dev/null
+++ b/lib/asm-7.3.1.jar
Binary files differ
diff --git a/lib/asm-commons-4.0.jar b/lib/asm-commons-4.0.jar
deleted file mode 100644
index 169400e..0000000
--- a/lib/asm-commons-4.0.jar
+++ /dev/null
Binary files differ
diff --git a/lib/asm-commons-7.3.1.jar b/lib/asm-commons-7.3.1.jar
new file mode 100644
index 0000000..65fb30e
--- /dev/null
+++ b/lib/asm-commons-7.3.1.jar
Binary files differ
diff --git a/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java b/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java
index 052e358..04942b1 100644
--- a/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java
+++ b/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java
@@ -17,7 +17,8 @@
 package com.android.jarjar;
 
 import com.tonicsystems.jarjar.util.JarTransformer;
-
+import java.util.Set;
+import java.util.function.Supplier;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
@@ -25,98 +26,95 @@
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.commons.Remapper;
 
-import java.util.Set;
-import java.util.function.Supplier;
-
-/**
- * A transformer that removes annotations from repackaged classes.
- */
+/** A transformer that removes annotations from repackaged classes. */
 public final class RemoveAndroidCompatAnnotationsJarTransformer extends JarTransformer {
 
-    private static int ASM_VERSION = Opcodes.ASM9;
+  private static int ASM_VERSION = Opcodes.ASM9;
 
-    private static final Set<String> REMOVE_ANNOTATIONS = Set.of(
-            "Landroid/compat/annotation/UnsupportedAppUsage;");
+  private static final Set<String> REMOVE_ANNOTATIONS =
+      Set.of("Landroid/compat/annotation/UnsupportedAppUsage;");
 
-    private final Remapper remapper;
+  private final Remapper remapper;
 
-    public RemoveAndroidCompatAnnotationsJarTransformer(Remapper remapper) {
-        this.remapper = remapper;
+  public RemoveAndroidCompatAnnotationsJarTransformer(Remapper remapper) {
+    this.remapper = remapper;
+  }
+
+  protected ClassVisitor transform(ClassVisitor classVisitor) {
+    return new AnnotationRemover(classVisitor);
+  }
+
+  private class AnnotationRemover extends ClassVisitor {
+
+    private boolean isClassRemapped;
+
+    AnnotationRemover(ClassVisitor cv) {
+      super(ASM_VERSION, cv);
     }
 
-    protected ClassVisitor transform(ClassVisitor classVisitor) {
-        return new AnnotationRemover(classVisitor);
+    @Override
+    public void visit(
+        int version,
+        int access,
+        String name,
+        String signature,
+        String superName,
+        String[] interfaces) {
+      String newName = remapper.map(name);
+      // On every new class header visit, remember whether the class is repackaged.
+      isClassRemapped = newName != null && !newName.equals(name);
+      super.visit(version, access, name, signature, superName, interfaces);
     }
 
-    private class AnnotationRemover extends ClassVisitor {
+    @Override
+    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+      return visitAnnotationCommon(descriptor, () -> super.visitAnnotation(descriptor, visible));
+    }
 
-        private boolean isClassRemapped;
-
-        AnnotationRemover(ClassVisitor cv) {
-            super(ASM_VERSION, cv);
-        }
-
-        @Override
-        public void visit(int version, int access, String name, String signature, String superName,
-                String[] interfaces) {
-            String newName = remapper.map(name);
-            // On every new class header visit, remember whether the class is repackaged.
-            isClassRemapped = newName != null && !newName.equals(name);
-            super.visit(version, access, name, signature, superName, interfaces);
-        }
-
+    @Override
+    public FieldVisitor visitField(
+        int access, String name, String descriptor, String signature, Object value) {
+      FieldVisitor superVisitor = super.visitField(access, name, descriptor, signature, value);
+      return new FieldVisitor(ASM_VERSION, superVisitor) {
         @Override
         public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
-            return visitAnnotationCommon(descriptor,
-                    () -> super.visitAnnotation(descriptor, visible));
+          return visitAnnotationCommon(
+              descriptor, () -> super.visitAnnotation(descriptor, visible));
         }
-
-        @Override
-        public FieldVisitor visitField(int access, String name, String descriptor, String signature,
-                Object value) {
-            FieldVisitor superVisitor =
-                    super.visitField(access, name, descriptor, signature, value);
-            return new FieldVisitor(ASM_VERSION, superVisitor) {
-                @Override
-                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
-                    return visitAnnotationCommon(descriptor,
-                            () -> super.visitAnnotation(descriptor, visible));
-
-                }
-            };
-        }
-
-        @Override
-        public MethodVisitor visitMethod(int access, String name, String descriptor,
-                String signature, String[] exceptions) {
-            MethodVisitor superVisitor =
-                    super.visitMethod(access, name, descriptor, signature, exceptions);
-            return new MethodVisitor(ASM_VERSION, superVisitor) {
-                @Override
-                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
-                    return visitAnnotationCommon(descriptor,
-                            () -> super.visitAnnotation(descriptor, visible));
-                }
-            };
-        }
-
-        /**
-         * Create an {@link AnnotationVisitor} that removes any annotations from {@link
-         * #REMOVE_ANNOTATIONS} if the class is being repackaged.
-         *
-         * <p>For the annotations to be dropped correctly, do not visit the annotation beforehand,
-         * provide a supplier instead.
-         */
-        private AnnotationVisitor visitAnnotationCommon(String annotation,
-                Supplier<AnnotationVisitor> defaultVisitorSupplier) {
-            if (isClassRemapped && REMOVE_ANNOTATIONS.contains(annotation)) {
-                return null;
-            }
-            // Only get() the default AnnotationVisitor if the annotation is to be included.
-            // Invoking super.visitAnnotation(descriptor, visible) causes the annotation to be
-            // included in the output even if the resulting AnnotationVisitor is not returned or
-            // used.
-            return defaultVisitorSupplier.get();
-        }
+      };
     }
+
+    @Override
+    public MethodVisitor visitMethod(
+        int access, String name, String descriptor, String signature, String[] exceptions) {
+      MethodVisitor superVisitor =
+          super.visitMethod(access, name, descriptor, signature, exceptions);
+      return new MethodVisitor(ASM_VERSION, superVisitor) {
+        @Override
+        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+          return visitAnnotationCommon(
+              descriptor, () -> super.visitAnnotation(descriptor, visible));
+        }
+      };
+    }
+
+    /**
+     * Create an {@link AnnotationVisitor} that removes any annotations from {@link
+     * #REMOVE_ANNOTATIONS} if the class is being repackaged.
+     *
+     * <p>For the annotations to be dropped correctly, do not visit the annotation beforehand,
+     * provide a supplier instead.
+     */
+    private AnnotationVisitor visitAnnotationCommon(
+        String annotation, Supplier<AnnotationVisitor> defaultVisitorSupplier) {
+      if (isClassRemapped && REMOVE_ANNOTATIONS.contains(annotation)) {
+        return null;
+      }
+      // Only get() the default AnnotationVisitor if the annotation is to be included.
+      // Invoking super.visitAnnotation(descriptor, visible) causes the annotation to be
+      // included in the output even if the resulting AnnotationVisitor is not returned or
+      // used.
+      return defaultVisitorSupplier.get();
+    }
+  }
 }
diff --git a/src/android/com/android/jarjar/StripAnnotation.java b/src/android/com/android/jarjar/StripAnnotation.java
index debd469..60fc965 100644
--- a/src/android/com/android/jarjar/StripAnnotation.java
+++ b/src/android/com/android/jarjar/StripAnnotation.java
@@ -18,9 +18,5 @@
 
 import com.tonicsystems.jarjar.PatternElement;
 
-/**
- * Configuration element for stripping annotations in a jar file.
- */
-public class StripAnnotation extends PatternElement
-{
-}
+/** Configuration element for stripping annotations in a jar file. */
+public class StripAnnotation extends PatternElement {}
diff --git a/src/android/com/android/jarjar/StripAnnotationsJarTransformer.java b/src/android/com/android/jarjar/StripAnnotationsJarTransformer.java
index d547fac..aa71715 100644
--- a/src/android/com/android/jarjar/StripAnnotationsJarTransformer.java
+++ b/src/android/com/android/jarjar/StripAnnotationsJarTransformer.java
@@ -17,105 +17,98 @@
 package com.android.jarjar;
 
 import com.tonicsystems.jarjar.util.JarTransformer;
-
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
-import java.util.List;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-/**
- * A transformer that strips annotations from all classes based on custom rules.
- */
+/** A transformer that strips annotations from all classes based on custom rules. */
 public final class StripAnnotationsJarTransformer extends JarTransformer {
 
-    private static int ASM_VERSION = Opcodes.ASM9;
+  private static int ASM_VERSION = Opcodes.ASM9;
 
-    private final List<String> stripAnnotationList;
+  private final List<String> stripAnnotationList;
 
-    public StripAnnotationsJarTransformer(List<StripAnnotation> stripAnnotationList) {
-        this.stripAnnotationList = getAnnotationList(stripAnnotationList);
-    }
+  public StripAnnotationsJarTransformer(List<StripAnnotation> stripAnnotationList) {
+    this.stripAnnotationList = getAnnotationList(stripAnnotationList);
+  }
 
-    private static List<String> getAnnotationList(List<StripAnnotation> stripAnnotationList) {
-        return stripAnnotationList.stream().map(el -> getClassName(el)).collect(Collectors.toList());
-    }
+  private static List<String> getAnnotationList(List<StripAnnotation> stripAnnotationList) {
+    return stripAnnotationList.stream().map(el -> getClassName(el)).collect(Collectors.toList());
+  }
 
-    private static String getClassName(StripAnnotation element) {
-        return "L" + element.getPattern().replace('.', '/') + ";";
+  private static String getClassName(StripAnnotation element) {
+    return "L" + element.getPattern().replace('.', '/') + ";";
+  }
+
+  @Override
+  protected ClassVisitor transform(ClassVisitor classVisitor) {
+    return new AnnotationRemover(classVisitor);
+  }
+
+  private class AnnotationRemover extends ClassVisitor {
+
+    AnnotationRemover(ClassVisitor cv) {
+      super(ASM_VERSION, cv);
     }
 
     @Override
-    protected ClassVisitor transform(ClassVisitor classVisitor) {
-        return new AnnotationRemover(classVisitor);
+    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+      return visitAnnotationCommon(descriptor, () -> super.visitAnnotation(descriptor, visible));
     }
 
-    private class AnnotationRemover extends ClassVisitor {
-
-        AnnotationRemover(ClassVisitor cv) {
-            super(ASM_VERSION, cv);
-        }
-
+    @Override
+    public FieldVisitor visitField(
+        int access, String name, String descriptor, String signature, Object value) {
+      FieldVisitor superVisitor = super.visitField(access, name, descriptor, signature, value);
+      return new FieldVisitor(ASM_VERSION, superVisitor) {
         @Override
         public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
-            return visitAnnotationCommon(descriptor,
-                    () -> super.visitAnnotation(descriptor, visible));
+          return visitAnnotationCommon(
+              descriptor, () -> super.visitAnnotation(descriptor, visible));
         }
-
-        @Override
-        public FieldVisitor visitField(int access, String name, String descriptor, String signature,
-                Object value) {
-            FieldVisitor superVisitor =
-                    super.visitField(access, name, descriptor, signature, value);
-            return new FieldVisitor(ASM_VERSION, superVisitor) {
-                @Override
-                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
-                    return visitAnnotationCommon(descriptor,
-                            () -> super.visitAnnotation(descriptor, visible));
-
-                }
-            };
-        }
-
-        @Override
-        public MethodVisitor visitMethod(int access, String name, String descriptor,
-                String signature, String[] exceptions) {
-            MethodVisitor superVisitor =
-                    super.visitMethod(access, name, descriptor, signature, exceptions);
-            return new MethodVisitor(ASM_VERSION, superVisitor) {
-                @Override
-                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
-                    return visitAnnotationCommon(descriptor,
-                            () -> super.visitAnnotation(descriptor, visible));
-                }
-
-                @Override
-                public AnnotationVisitor visitParameterAnnotation(int parameter,
-                        String descriptor, boolean visible) {
-                    return visitAnnotationCommon(descriptor,
-                            () -> super.visitParameterAnnotation(parameter, descriptor, visible));
-                }
-            };
-        }
-
-        /**
-         * Create an {@link AnnotationVisitor} that removes any annotations from {@link
-         * #stripAnnotationList}.
-         */
-        private AnnotationVisitor visitAnnotationCommon(String annotation,
-                Supplier<AnnotationVisitor> defaultVisitorSupplier) {
-            if (stripAnnotationList.contains(annotation)) {
-                return null;
-            }
-            // Only get() the default AnnotationVisitor if the annotation is to be included.
-            // Invoking super.visitAnnotation(descriptor, visible) causes the annotation to be
-            // included in the output even if the resulting AnnotationVisitor is not returned or
-            // used.
-            return defaultVisitorSupplier.get();
-        }
+      };
     }
+
+    @Override
+    public MethodVisitor visitMethod(
+        int access, String name, String descriptor, String signature, String[] exceptions) {
+      MethodVisitor superVisitor =
+          super.visitMethod(access, name, descriptor, signature, exceptions);
+      return new MethodVisitor(ASM_VERSION, superVisitor) {
+        @Override
+        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+          return visitAnnotationCommon(
+              descriptor, () -> super.visitAnnotation(descriptor, visible));
+        }
+
+        @Override
+        public AnnotationVisitor visitParameterAnnotation(
+            int parameter, String descriptor, boolean visible) {
+          return visitAnnotationCommon(
+              descriptor, () -> super.visitParameterAnnotation(parameter, descriptor, visible));
+        }
+      };
+    }
+
+    /**
+     * Create an {@link AnnotationVisitor} that removes any annotations from {@link
+     * #stripAnnotationList}.
+     */
+    private AnnotationVisitor visitAnnotationCommon(
+        String annotation, Supplier<AnnotationVisitor> defaultVisitorSupplier) {
+      if (stripAnnotationList.contains(annotation)) {
+        return null;
+      }
+      // Only get() the default AnnotationVisitor if the annotation is to be included.
+      // Invoking super.visitAnnotation(descriptor, visible) causes the annotation to be
+      // included in the output even if the resulting AnnotationVisitor is not returned or
+      // used.
+      return defaultVisitorSupplier.get();
+    }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java b/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java
index 5a54737..5c40212 100644
--- a/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java
+++ b/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,41 +16,45 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import java.io.*;
-import java.util.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
-abstract public class AbstractDepHandler implements DepHandler
-{
-    protected final int level;
-    private final Set<List<Object>> seenIt = new HashSet<List<Object>>();
-    
-    protected AbstractDepHandler(int level) {
-        this.level = level;
+public abstract class AbstractDepHandler implements DepHandler {
+  protected final int level;
+  private final Set<List<Object>> seenIt = new HashSet<>();
+
+  protected AbstractDepHandler(int level) {
+    this.level = level;
+  }
+
+  @Override
+  public void handle(PathClass from, PathClass to) throws IOException {
+    List<Object> pair;
+    if (level == LEVEL_JAR) {
+      pair = createPair(from.getClassPath(), to.getClassPath());
+    } else {
+      pair = createPair(from.getClassName(), to.getClassName());
     }
-    
-    public void handle(PathClass from, PathClass to) throws IOException {
-        List<Object> pair;
-        if (level == LEVEL_JAR) {
-            pair = createPair(from.getClassPath(), to.getClassPath());
-        } else {
-            pair = createPair(from.getClassName(), to.getClassName());
-        }
-        if (!seenIt.contains(pair)) {
-            seenIt.add(pair);
-            handle(pair.get(0).toString(), pair.get(1).toString());
-        }
+    if (seenIt.add(pair)) {
+      handle(pair.get(0).toString(), pair.get(1).toString());
     }
+  }
 
-    abstract protected void handle(String from, String to) throws IOException;
+  protected abstract void handle(String from, String to) throws IOException;
 
-    public void handleStart() throws IOException { }
-    public void handleEnd() throws IOException { }
+  @Override
+  public void handleStart() throws IOException {}
 
-    private static List<Object> createPair(Object o1, Object o2) {
-        List<Object> list = new ArrayList<Object>(2);
-        list.add(o1);
-        list.add(o2);
-        return list;
-    }
+  @Override
+  public void handleEnd() throws IOException {}
+
+  private static List<Object> createPair(Object o1, Object o2) {
+    List<Object> list = new ArrayList<>(2);
+    list.add(o1);
+    list.add(o2);
+    return list;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/DepFind.java b/src/main/com/tonicsystems/jarjar/DepFind.java
index 40f68ff..0d13c54 100644
--- a/src/main/com/tonicsystems/jarjar/DepFind.java
+++ b/src/main/com/tonicsystems/jarjar/DepFind.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,65 +16,69 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import java.io.*;
-import java.util.*;
-import java.util.zip.ZipEntry;
+import com.tonicsystems.jarjar.util.ClassHeaderReader;
+import com.tonicsystems.jarjar.util.ClassPathEntry;
+import com.tonicsystems.jarjar.util.ClassPathIterator;
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
 import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
 
-public class DepFind
-{
-    private File curDir = new File(System.getProperty("user.dir"));
+public class DepFind {
+  private File curDir = new File(System.getProperty("user.dir"));
 
-    public void setCurrentDirectory(File curDir) {
-        this.curDir = curDir;
-    }
+  public void setCurrentDirectory(File curDir) {
+    this.curDir = curDir;
+  }
 
-    public void run(String from, String to, DepHandler handler) throws IOException {
-        try {
-            ClassHeaderReader header = new ClassHeaderReader();
-            Map<String, String> classes = new HashMap<String, String>();
-            ClassPathIterator cp = new ClassPathIterator(curDir, to, null);
-            try {
-              while (cp.hasNext()) {
-                ClassPathEntry entry = cp.next();
-                InputStream in = entry.openStream();
-                try {
-                  header.read(in);
-                  classes.put(header.getClassName(), entry.getSource());
-                } catch (Exception e) {
-                  System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
-                } finally {
-                  in.close();
-                }
-              }
-            } finally {
-              cp.close();
-            }
-
-            handler.handleStart();
-            cp = new ClassPathIterator(curDir, from, null);
-            try {
-              while (cp.hasNext()) {
-                ClassPathEntry entry = cp.next();
-                InputStream in = entry.openStream();
-                try {
-                  new ClassReader(in).accept(
-                      new DepFindVisitor(classes, entry.getSource(), handler),
-                      ClassReader.SKIP_DEBUG);
-                } catch (Exception e) {
-                  System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
-                } finally {
-                  in.close();
-                }
-              }
-            } finally {
-              cp.close();
-            }
-            handler.handleEnd();
-        } catch (RuntimeIOException e) {
-            throw (IOException)e.getCause();
+  public void run(String from, String to, DepHandler handler) throws IOException {
+    try {
+      ClassHeaderReader header = new ClassHeaderReader();
+      Map<String, String> classes = new HashMap<>();
+      ClassPathIterator cp = new ClassPathIterator(curDir, to, null);
+      try {
+        while (cp.hasNext()) {
+          ClassPathEntry entry = cp.next();
+          InputStream in = entry.openStream();
+          try {
+            header.read(in);
+            classes.put(header.getClassName(), entry.getSource());
+          } catch (Exception e) {
+            System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
+          } finally {
+            in.close();
+          }
         }
+      } finally {
+        cp.close();
+      }
+
+      handler.handleStart();
+      cp = new ClassPathIterator(curDir, from, null);
+      try {
+        while (cp.hasNext()) {
+          ClassPathEntry entry = cp.next();
+          InputStream in = entry.openStream();
+          try {
+            new ClassReader(in)
+                .accept(
+                    new DepFindVisitor(classes, entry.getSource(), handler),
+                    ClassReader.SKIP_DEBUG);
+          } catch (Exception e) {
+            System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
+          } finally {
+            in.close();
+          }
+        }
+      } finally {
+        cp.close();
+      }
+      handler.handleEnd();
+    } catch (RuntimeIOException e) {
+      throw (IOException) e.getCause();
     }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/DepFindVisitor.java b/src/main/com/tonicsystems/jarjar/DepFindVisitor.java
index bad909e..4b817c9 100644
--- a/src/main/com/tonicsystems/jarjar/DepFindVisitor.java
+++ b/src/main/com/tonicsystems/jarjar/DepFindVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,56 +16,60 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import java.io.*;
-import java.util.*;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.objectweb.asm.*;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.commons.*;
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.IOException;
+import java.util.Map;
+import org.objectweb.asm.commons.ClassRemapper;
+import org.objectweb.asm.commons.Remapper;
 
-class DepFindVisitor extends ClassRemapper
-{
-    public DepFindVisitor(Map<String, String> classes, String source, DepHandler handler) throws IOException {
-        super(null, new DepFindRemapper(classes, source, handler));
+class DepFindVisitor extends ClassRemapper {
+  public DepFindVisitor(Map<String, String> classes, String source, DepHandler handler)
+      throws IOException {
+    super(null, new DepFindRemapper(classes, source, handler));
+  }
+
+  @Override
+  public void visit(
+      int version,
+      int access,
+      String name,
+      String signature,
+      String superName,
+      String[] interfaces) {
+    ((DepFindRemapper) remapper).setClassName(name);
+    super.visit(version, access, name, signature, superName, interfaces);
+  }
+
+  private static class DepFindRemapper extends Remapper {
+    private final Map<String, String> classes;
+    private final String source;
+    private final DepHandler handler;
+    private PathClass curPathClass;
+
+    public DepFindRemapper(Map<String, String> classes, String source, DepHandler handler) {
+      this.classes = classes;
+      this.source = source;
+      this.handler = handler;
     }
 
-    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
-        ((DepFindRemapper)remapper).setClassName(name);
-        super.visit(version, access, name, signature, superName, interfaces);
+    public void setClassName(String name) {
+      curPathClass = new PathClass(source, name);
     }
 
-    private static class DepFindRemapper extends Remapper
-    {
-        private final Map<String, String> classes;
-        private final String source;
-        private final DepHandler handler;
-        private PathClass curPathClass;
-
-        public DepFindRemapper(Map<String, String> classes, String source, DepHandler handler) throws IOException {
-            this.classes = classes;
-            this.source = source;
-            this.handler = handler;
+    @Override
+    public String map(String key) {
+      try {
+        if (classes.containsKey(key)) {
+          String otherSource = classes.get(key);
+          if (!source.equals(otherSource)) {
+            // TODO: some escape mechanism?
+            handler.handle(curPathClass, new PathClass(otherSource, key));
+          }
         }
-
-        public void setClassName(String name) {
-            curPathClass = new PathClass(source, name);
-        }
-
-        public String map(String key) {
-            try {
-                if (classes.containsKey(key)) {
-                    String otherSource = classes.get(key);
-                    if (!source.equals(otherSource)) {
-                        // TODO: some escape mechanism?
-                        handler.handle(curPathClass, new PathClass(otherSource, key));
-                    }
-                }
-            } catch (IOException e) {
-                throw new RuntimeIOException(e);
-            }
-            return null;
-        }
+      } catch (IOException e) {
+        throw new RuntimeIOException(e);
+      }
+      return null;
     }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/DepHandler.java b/src/main/com/tonicsystems/jarjar/DepHandler.java
index 33107d4..4684730 100644
--- a/src/main/com/tonicsystems/jarjar/DepHandler.java
+++ b/src/main/com/tonicsystems/jarjar/DepHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,13 @@
 
 import java.io.IOException;
 
-public interface DepHandler
-{
-    public static final int LEVEL_CLASS = 0;
-    public static final int LEVEL_JAR = 1;
+public interface DepHandler {
+  public static final int LEVEL_CLASS = 0;
+  public static final int LEVEL_JAR = 1;
 
-    void handleStart() throws IOException;
-    void handle(PathClass from, PathClass to) throws IOException;
-    void handleEnd() throws IOException;
+  void handleStart() throws IOException;
+
+  void handle(PathClass from, PathClass to) throws IOException;
+
+  void handleEnd() throws IOException;
 }
diff --git a/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java b/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java
index 9a05516..0dffc4e 100644
--- a/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java
+++ b/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java
@@ -15,36 +15,37 @@
  */
 package com.tonicsystems.jarjar;
 
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
 
 /**
- * An EmptyVisitor replacement
+ * An ASM3 EmptyVisitor replacement
+ *
  * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
  */
 public class EmptyClassVisitor extends ClassVisitor {
 
-    public EmptyClassVisitor() {
-        super(Opcodes.ASM9);
-    }
-    
-    @Override
-    public MethodVisitor visitMethod(int access, String name, String desc,
-            String signature, String[] exceptions) {
-        return new MethodVisitor(Opcodes.ASM9) {};
-    }
-    
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        return new AnnotationVisitor(Opcodes.ASM9) {};
-    }
-    
-    @Override
-    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
-        return new FieldVisitor(Opcodes.ASM9) {};
-    }
+  public EmptyClassVisitor() {
+    super(Opcodes.ASM9);
+  }
 
+  @Override
+  public MethodVisitor visitMethod(
+      int access, String name, String desc, String signature, String[] exceptions) {
+    return new MethodVisitor(Opcodes.ASM9) {};
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+    return new AnnotationVisitor(Opcodes.ASM9) {};
+  }
+
+  @Override
+  public FieldVisitor visitField(
+      int access, String name, String desc, String signature, Object value) {
+    return new FieldVisitor(Opcodes.ASM9) {};
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java b/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java
index 191803f..7b8cbbd 100644
--- a/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,26 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
+import com.tonicsystems.jarjar.util.EntryStruct;
+import com.tonicsystems.jarjar.util.JarProcessor;
 import java.io.IOException;
-import java.util.*;
+import java.util.Set;
 
-class ExcludeProcessor implements JarProcessor
-{
-    private final Set<String> excludes;
-    private final boolean verbose;
+class ExcludeProcessor implements JarProcessor {
+  private final Set<String> excludes;
+  private final boolean verbose;
 
-    public ExcludeProcessor(Set<String> excludes, boolean verbose) {
-        this.excludes = excludes;
-        this.verbose = verbose;
+  public ExcludeProcessor(Set<String> excludes, boolean verbose) {
+    this.excludes = excludes;
+    this.verbose = verbose;
+  }
+
+  @Override
+  public boolean process(EntryStruct struct) throws IOException {
+    boolean toKeep = !excludes.contains(struct.name);
+    if (verbose && !toKeep) {
+      System.err.println("Excluding " + struct.name);
     }
-
-    public boolean process(EntryStruct struct) throws IOException {
-        boolean toKeep = !excludes.contains(struct.name);
-        if (verbose && !toKeep)
-            System.err.println("Excluding " + struct.name);
-        return toKeep;
-    }
+    return toKeep;
+  }
 }
-    
diff --git a/src/main/com/tonicsystems/jarjar/JarJarMojo.java b/src/main/com/tonicsystems/jarjar/JarJarMojo.java
index 9d37b77..2cec5fc 100644
--- a/src/main/com/tonicsystems/jarjar/JarJarMojo.java
+++ b/src/main/com/tonicsystems/jarjar/JarJarMojo.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,31 +23,31 @@
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 
-public class JarJarMojo extends AbstractMojo
-{
-    private File fromJar;
-    private File toJar;
-    private File rulesFile;
-    private String rules;
-    private boolean verbose;
-    
-    public void execute() throws MojoExecutionException {
-        if (!((rulesFile == null || !rulesFile.exists()) ^ (rules == null)))
-            throw new MojoExecutionException("Exactly one of rules or rulesFile is required");
+public class JarJarMojo extends AbstractMojo {
+  private File fromJar;
+  private File toJar;
+  private File rulesFile;
+  private String rules;
+  private boolean verbose;
 
-        try {
-            List<PatternElement> patterns;
-            if (rules != null) {
-                patterns = RulesFileParser.parse(rules);
-            } else {
-                patterns = RulesFileParser.parse(rulesFile);
-            }
-            // TODO: refactor with Main.java
-            MainProcessor proc = new MainProcessor(patterns, verbose, true);
-            StandaloneJarProcessor.run(fromJar, toJar, proc);
-            proc.strip(toJar);
-        } catch (IOException e) {
-            throw new MojoExecutionException(e.getMessage(), e);
-        }
+  public void execute() throws MojoExecutionException {
+    if (!((rulesFile == null || !rulesFile.exists()) ^ (rules == null))) {
+      throw new MojoExecutionException("Exactly one of rules or rulesFile is required");
     }
+
+    try {
+      List<PatternElement> patterns;
+      if (rules != null) {
+        patterns = RulesFileParser.parse(rules);
+      } else {
+        patterns = RulesFileParser.parse(rulesFile);
+      }
+      // TODO: refactor with Main.java
+      MainProcessor proc = new MainProcessor(patterns, verbose, true);
+      StandaloneJarProcessor.run(fromJar, toJar, proc);
+      proc.strip(toJar);
+    } catch (IOException e) {
+      throw new MojoExecutionException(e.getMessage(), e);
+    }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/JarJarTask.java b/src/main/com/tonicsystems/jarjar/JarJarTask.java
index 2c183c9..39e1677 100644
--- a/src/main/com/tonicsystems/jarjar/JarJarTask.java
+++ b/src/main/com/tonicsystems/jarjar/JarJarTask.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,45 +17,47 @@
 package com.tonicsystems.jarjar;
 
 import com.tonicsystems.jarjar.util.*;
-import java.io.File;
 import java.io.IOException;
 import java.util.*;
 import org.apache.tools.ant.BuildException;
 
-public class JarJarTask extends AntJarProcessor
-{
-    private List<PatternElement> patterns = new ArrayList<PatternElement>();
+public class JarJarTask extends AntJarProcessor {
+  private List<PatternElement> patterns = new ArrayList<PatternElement>();
 
-    public void addConfiguredRule(Rule rule) {
-        if (rule.getPattern() == null || rule.getResult() == null)
-            throw new IllegalArgumentException("The <rule> element requires both \"pattern\" and \"result\" attributes.");
-        patterns.add(rule);
+  public void addConfiguredRule(Rule rule) {
+    if (rule.getPattern() == null || rule.getResult() == null) {
+      throw new IllegalArgumentException(
+          "The <rule> element requires both \"pattern\" and \"result\" attributes.");
     }
+    patterns.add(rule);
+  }
 
-    public void addConfiguredZap(Zap zap) {
-        if (zap.getPattern() == null)
-            throw new IllegalArgumentException("The <zap> element requires a \"pattern\" attribute.");
-        patterns.add(zap);
+  public void addConfiguredZap(Zap zap) {
+    if (zap.getPattern() == null) {
+      throw new IllegalArgumentException("The <zap> element requires a \"pattern\" attribute.");
     }
+    patterns.add(zap);
+  }
 
-    public void addConfiguredKeep(Keep keep) {
-        if (keep.getPattern() == null)
-            throw new IllegalArgumentException("The <keep> element requires a \"pattern\" attribute.");
-        patterns.add(keep);
+  public void addConfiguredKeep(Keep keep) {
+    if (keep.getPattern() == null) {
+      throw new IllegalArgumentException("The <keep> element requires a \"pattern\" attribute.");
     }
+    patterns.add(keep);
+  }
 
-    public void execute() throws BuildException {
-        MainProcessor proc = new MainProcessor(patterns, verbose, false);
-        execute(proc);
-        try {
-            proc.strip(getDestFile());
-        } catch (IOException e) {
-            throw new BuildException(e);
-        }
+  public void execute() throws BuildException {
+    MainProcessor proc = new MainProcessor(patterns, verbose, false);
+    execute(proc);
+    try {
+      proc.strip(getDestFile());
+    } catch (IOException e) {
+      throw new BuildException(e);
     }
+  }
 
-    protected void cleanHelper() {
-        super.cleanHelper();
-        patterns.clear();
-    }
+  protected void cleanHelper() {
+    super.cleanHelper();
+    patterns.clear();
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/Keep.java b/src/main/com/tonicsystems/jarjar/Keep.java
index 14b719e..090340e 100644
--- a/src/main/com/tonicsystems/jarjar/Keep.java
+++ b/src/main/com/tonicsystems/jarjar/Keep.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,4 @@
 
 package com.tonicsystems.jarjar;
 
-public class Keep extends PatternElement
-{
-}
+public class Keep extends PatternElement {}
diff --git a/src/main/com/tonicsystems/jarjar/KeepProcessor.java b/src/main/com/tonicsystems/jarjar/KeepProcessor.java
index 3ed4636..90ee682 100644
--- a/src/main/com/tonicsystems/jarjar/KeepProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/KeepProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,97 +16,114 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import java.io.*;
-import java.util.*;
-import org.objectweb.asm.*;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.commons.*;
+import com.tonicsystems.jarjar.util.EntryStruct;
+import com.tonicsystems.jarjar.util.JarProcessor;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.ClassRemapper;
+import org.objectweb.asm.commons.Remapper;
 
 // TODO: this can probably be refactored into JarClassVisitor, etc.
-class KeepProcessor extends Remapper implements JarProcessor
-{
-    private final ClassVisitor cv = new ClassRemapper(new EmptyClassVisitor(), this);
-    private final List<Wildcard> wildcards;
-    private final List<String> roots = new ArrayList<String>();
-    private final Map<String, Set<String>> depend = new HashMap<String, Set<String>>();
-    
-    public KeepProcessor(List<Keep> patterns) {
-        wildcards = PatternElement.createWildcards(patterns);
-    }
+class KeepProcessor extends Remapper implements JarProcessor {
+  private final ClassVisitor cv = new ClassRemapper(new EmptyClassVisitor(), this);
+  private final List<Wildcard> wildcards;
+  private final List<String> roots = new ArrayList<>();
+  private final Map<String, Set<String>> depend = new HashMap<>();
 
-    public boolean isEnabled() {
-        return !wildcards.isEmpty();
-    }
+  public KeepProcessor(List<Keep> patterns) {
+    wildcards = PatternElement.createWildcards(patterns);
+  }
 
-    public Set<String> getExcludes() {
-        Set<String> closure = new HashSet<String>();
-        closureHelper(closure, roots);
-        Set<String> removable = new HashSet<String>(depend.keySet());
-        removable.removeAll(closure);
-        return removable;
-    }
+  public boolean isEnabled() {
+    return !wildcards.isEmpty();
+  }
 
-    private void closureHelper(Set<String> closure, Collection<String> process) {
-        if (process == null)
-            return;
-        for (String name : process) {
-            if (closure.add(name))
-                closureHelper(closure, depend.get(name));
+  public Set<String> getExcludes() {
+    Set<String> closure = new HashSet<>();
+    closureHelper(closure, roots);
+    Set<String> removable = new HashSet<>(depend.keySet());
+    removable.removeAll(closure);
+    return removable;
+  }
+
+  private void closureHelper(Set<String> closure, Collection<String> process) {
+    if (process == null) {
+      return;
+    }
+    for (String name : process) {
+      if (closure.add(name)) {
+        closureHelper(closure, depend.get(name));
+      }
+    }
+  }
+
+  private Set<String> curSet;
+
+  @Override
+  public boolean process(EntryStruct struct) throws IOException {
+    try {
+      if (struct.isClass()) {
+        String name = struct.name.substring(0, struct.name.length() - 6);
+        for (Wildcard wildcard : wildcards) {
+          if (wildcard.matches(name)) {
+            roots.add(name);
+          }
         }
+        depend.put(name, curSet = new HashSet<>());
+        new ClassReader(new ByteArrayInputStream(struct.data))
+            .accept(cv, ClassReader.EXPAND_FRAMES);
+        curSet.remove(name);
+      }
+    } catch (Exception e) {
+      System.err.println("Error reading " + struct.name + ": " + e.getMessage());
     }
+    return true;
+  }
 
-    private Set<String> curSet;
-    private byte[] buf = new byte[0x2000];
-
-    public boolean process(EntryStruct struct) throws IOException {
-        try {
-            if (struct.name.endsWith(".class")) {
-                String name = struct.name.substring(0, struct.name.length() - 6);
-                for (Wildcard wildcard : wildcards)
-                    if (wildcard.matches(name))
-                        roots.add(name);
-                depend.put(name, curSet = new HashSet<String>());
-                new ClassReader(new ByteArrayInputStream(struct.data)).accept(cv,
-                    ClassReader.EXPAND_FRAMES);
-                curSet.remove(name);
-            }
-        } catch (Exception e) {
-          System.err.println("Error reading " + struct.name + ": " + e.getMessage());
-        }
-        return true;
+  @Override
+  public String map(String key) {
+    if (key.startsWith("java/") || key.startsWith("javax/")) {
+      return null;
     }
+    curSet.add(key);
+    return null;
+  }
 
-    public String map(String key) {
-        if (key.startsWith("java/") || key.startsWith("javax/"))
-            return null;
-        curSet.add(key);
-        return null;
+  @Override
+  public Object mapValue(Object value) {
+    if (value instanceof String) {
+      String s = (String) value;
+      if (PackageRemapper.isArrayForName(s)) {
+        mapDesc(s.replace('.', '/'));
+      } else if (isForName(s)) {
+        map(s.replace('.', '/'));
+      }
+      return value;
+    } else {
+      return super.mapValue(value);
     }
+  }
 
-    public Object mapValue(Object value) {
-        if (value instanceof String) {
-            String s = (String)value;
-            if (PackageRemapper.isArrayForName(s)) {
-                mapDesc(s.replace('.', '/'));
-            } else if (isForName(s)) {
-                map(s.replace('.', '/'));
-            }
-            return value;
-        } else {
-            return super.mapValue(value);
-        }
+  // TODO: use this for package remapping too?
+  private static boolean isForName(String value) {
+    if (value.isEmpty()) {
+      return false;
     }
-
-    // TODO: use this for package remapping too?
-    private static boolean isForName(String value) {
-        if (value.equals(""))
-            return false;
-        for (int i = 0, len = value.length(); i < len; i++) {
-            char c = value.charAt(i);
-            if (c != '.' && !Character.isJavaIdentifierPart(c))
-                return false;
-        }
-        return true;
+    for (int i = 0, len = value.length(); i < len; i++) {
+      char c = value.charAt(i);
+      if (c != '.' && !Character.isJavaIdentifierPart(c)) {
+        return false;
+      }
     }
+    return true;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/Main.java b/src/main/com/tonicsystems/jarjar/Main.java
index 1eaa3e3..aa78836 100644
--- a/src/main/com/tonicsystems/jarjar/Main.java
+++ b/src/main/com/tonicsystems/jarjar/Main.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,19 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import java.io.*;
-import java.util.*;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import com.tonicsystems.jarjar.util.StandaloneJarProcessor;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.List;
 
 public class Main {
 
@@ -34,18 +44,15 @@
   }
 
   private static String readIntoString(InputStream in) throws IOException {
-      StringBuilder sb = new StringBuilder();
-      BufferedReader r = new BufferedReader(new InputStreamReader(in, "UTF-8"));
-      String line = null;
-      while ((line = r.readLine()) != null)
-          sb.append(line).append(LINE_SEPARATOR);
-      return sb.toString();
+    StringBuilder sb = new StringBuilder();
+    BufferedReader r = new BufferedReader(new InputStreamReader(in, UTF_8));
+    String line = null;
+    while ((line = r.readLine()) != null) {
+      sb.append(line).append(LINE_SEPARATOR);
+    }
+    return sb.toString();
   }
 
-  private boolean verbose;
-  private List patterns;
-  private int level = DepHandler.LEVEL_CLASS;
-
   public static void main(String[] args) throws Exception {
     MainUtil.runMain(new Main(), args, "help");
   }
@@ -58,7 +65,8 @@
     if (cp == null) {
       throw new IllegalArgumentException("cp is required");
     }
-    new StringDumper().run(cp, new PrintWriter(System.out));
+    new StringDumper()
+        .run(cp, new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out, UTF_8))));
   }
 
   // TODO: make level an enum
@@ -77,7 +85,7 @@
     } else {
       throw new IllegalArgumentException("unknown level " + level);
     }
-    PrintWriter w = new PrintWriter(System.out);
+    PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out, UTF_8)));
     DepHandler handler = new TextDepHandler(w, levelFlag);
     new DepFind().run(cp1, cp2, handler);
     w.flush();
@@ -92,8 +100,8 @@
     boolean skipManifest = Boolean.getBoolean("skipManifest");
     // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
     boolean removeAndroidCompatAnnotations = Boolean.getBoolean("removeAndroidCompatAnnotations");
-    MainProcessor proc = new MainProcessor(rules, verbose, skipManifest,
-            removeAndroidCompatAnnotations);
+    MainProcessor proc =
+        new MainProcessor(rules, verbose, skipManifest, removeAndroidCompatAnnotations);
     // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
     StandaloneJarProcessor.run(inJar, outJar, proc);
     proc.strip(outJar);
diff --git a/src/main/com/tonicsystems/jarjar/MainProcessor.java b/src/main/com/tonicsystems/jarjar/MainProcessor.java
index a0ef4c7..1f676c2 100644
--- a/src/main/com/tonicsystems/jarjar/MainProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/MainProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,118 +16,137 @@
 
 package com.tonicsystems.jarjar;
 
+import com.android.jarjar.RemoveAndroidCompatAnnotationsJarTransformer;
 import com.android.jarjar.StripAnnotation;
-import com.tonicsystems.jarjar.util.*;
+import com.android.jarjar.StripAnnotationsJarTransformer;
+import com.tonicsystems.jarjar.util.EntryStruct;
+import com.tonicsystems.jarjar.util.JarProcessor;
+import com.tonicsystems.jarjar.util.JarProcessorChain;
+import com.tonicsystems.jarjar.util.JarTransformerChain;
+import com.tonicsystems.jarjar.util.RemappingClassTransformer;
+import com.tonicsystems.jarjar.util.StandaloneJarProcessor;
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
-import com.android.jarjar.RemoveAndroidCompatAnnotationsJarTransformer;
-import com.android.jarjar.StripAnnotationsJarTransformer;
+class MainProcessor implements JarProcessor {
+  private final boolean verbose;
+  private final JarProcessorChain chain;
+  private final KeepProcessor kp;
+  private final Map<String, String> renames = new HashMap<>();
 
-class MainProcessor implements JarProcessor
-{
-    private final boolean verbose;
-    private final JarProcessorChain chain;
-    private final KeepProcessor kp;
-    private final Map<String, String> renames = new HashMap<String, String>();
+  // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
+  public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest) {
+    this(patterns, verbose, skipManifest, false /* removeAndroidCompatAnnotations */);
+  }
 
+  public MainProcessor(
+      List<PatternElement> patterns,
+      boolean verbose,
+      boolean skipManifest,
+      boolean removeAndroidCompatAnnotations) {
+    // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
+    this.verbose = verbose;
+    List<Zap> zapList = new ArrayList<>();
+    List<Rule> ruleList = new ArrayList<>();
+    List<Keep> keepList = new ArrayList<>();
+    // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
+    List<StripAnnotation> stripAnnotationList = new ArrayList<StripAnnotation>();
+    // ANDROID-END: b/222743634 Strip annotations from system module stubs
+    for (PatternElement pattern : patterns) {
+      if (pattern instanceof Zap) {
+        zapList.add((Zap) pattern);
+      } else if (pattern instanceof Rule) {
+        ruleList.add((Rule) pattern);
+      } else if (pattern instanceof Keep) {
+        keepList.add((Keep) pattern);
+      // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
+      } else if (pattern instanceof StripAnnotation) {
+        stripAnnotationList.add((StripAnnotation) pattern);
+      }
+      // ANDROID-END: b/222743634 Strip annotations from system module stubs
+    }
+
+    PackageRemapper pr = new PackageRemapper(ruleList, verbose);
+    kp = keepList.isEmpty() ? null : new KeepProcessor(keepList);
+
+    List<JarProcessor> processors = new ArrayList<>();
+    if (skipManifest) {
+      processors.add(ManifestProcessor.getInstance());
+    }
+    if (kp != null) {
+      processors.add(kp);
+    }
+    processors.add(new ZapProcessor(zapList));
     // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
-    public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest) {
-        this(patterns, verbose, skipManifest, false /* removeAndroidCompatAnnotations */);
+    if (removeAndroidCompatAnnotations)
+      processors.add(new RemoveAndroidCompatAnnotationsJarTransformer(pr));
+    // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
+    // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
+    if (!stripAnnotationList.isEmpty()) {
+      processors.add(new StripAnnotationsJarTransformer(stripAnnotationList));
     }
+    // ANDROID-END: b/222743634 Strip annotations from system module stubs
+    processors.add(
+        new JarTransformerChain(
+            new RemappingClassTransformer[] {new RemappingClassTransformer(pr)}));
+    processors.add(new ResourceProcessor(pr));
+    chain = new JarProcessorChain(processors.toArray(new JarProcessor[0]));
+  }
 
-    public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest,
-            boolean removeAndroidCompatAnnotations) {
-        // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
-        this.verbose = verbose;
-        List<Zap> zapList = new ArrayList<Zap>();
-        List<Rule> ruleList = new ArrayList<Rule>();
-        List<Keep> keepList = new ArrayList<Keep>();
-        // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
-        List<StripAnnotation> stripAnnotationList = new ArrayList<StripAnnotation>();
-        // ANDROID-END: b/222743634 Strip annotations from system module stubs
-        for (PatternElement pattern : patterns) {
-            if (pattern instanceof Zap) {
-                zapList.add((Zap) pattern);
-            } else if (pattern instanceof Rule) {
-                ruleList.add((Rule) pattern);
-            } else if (pattern instanceof Keep) {
-                keepList.add((Keep) pattern);
-            // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
-            } else if (pattern instanceof StripAnnotation) {
-                stripAnnotationList.add((StripAnnotation) pattern);
-            }
-            // ANDROID-END: b/222743634 Strip annotations from system module stubs
+  public void strip(File file) throws IOException {
+    if (kp == null) {
+      return;
+    }
+    Set<String> excludes = getExcludes();
+    if (!excludes.isEmpty()) {
+      StandaloneJarProcessor.run(file, file, new ExcludeProcessor(excludes, verbose));
+    }
+  }
+
+  /**
+   * Returns the <code>.class</code> files to delete. As well the root-parameter as the rename ones
+   * are taken in consideration, so that the concerned files are not listed in the result.
+   *
+   * @return the paths of the files in the jar-archive, including the <code>.class</code> suffix
+   */
+  private Set<String> getExcludes() {
+    Set<String> result = new HashSet<>();
+    for (String exclude : kp.getExcludes()) {
+      String name = exclude + ".class";
+      String renamed = renames.get(name);
+      result.add((renamed != null) ? renamed : name);
+    }
+    return result;
+  }
+
+  /**
+   * @param struct
+   * @return <code>true</code> if the entry is to include in the output jar
+   * @throws IOException
+   */
+  public boolean process(EntryStruct struct) throws IOException {
+    String name = struct.name;
+    boolean keepIt = chain.process(struct);
+    if (keepIt) {
+      if (!name.equals(struct.name)) {
+        if (kp != null) {
+          renames.put(name, struct.name);
         }
-
-        PackageRemapper pr = new PackageRemapper(ruleList, verbose);
-        kp = keepList.isEmpty() ? null : new KeepProcessor(keepList);
-
-        List<JarProcessor> processors = new ArrayList<JarProcessor>();
-        if (skipManifest)
-            processors.add(ManifestProcessor.getInstance());
-        if (kp != null)
-            processors.add(kp);
-        processors.add(new ZapProcessor(zapList));
-        // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
-        if (removeAndroidCompatAnnotations)
-            processors.add(new RemoveAndroidCompatAnnotationsJarTransformer(pr));
-        // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
-        // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
-        if (!stripAnnotationList.isEmpty()) {
-            processors.add(new StripAnnotationsJarTransformer(stripAnnotationList));
+        if (verbose) {
+          System.err.println("Renamed " + name + " -> " + struct.name);
         }
-        // ANDROID-END: b/222743634 Strip annotations from system module stubs
-        processors.add(new JarTransformerChain(new RemappingClassTransformer[]{ new RemappingClassTransformer(pr) }));
-        processors.add(new ResourceProcessor(pr));
-        chain = new JarProcessorChain(processors.toArray(new JarProcessor[processors.size()]));
+      }
+    } else {
+      if (verbose) {
+        System.err.println("Removed " + name);
+      }
     }
-
-    public void strip(File file) throws IOException {
-        if (kp == null)
-            return;
-        Set<String> excludes = getExcludes();
-        if (!excludes.isEmpty())
-            StandaloneJarProcessor.run(file, file, new ExcludeProcessor(excludes, verbose));
-    }
-
-    /**
-     * Returns the <code>.class</code> files to delete. As well the root-parameter as the rename ones
-     * are taken in consideration, so that the concerned files are not listed in the result.
-     *
-     * @return the paths of the files in the jar-archive, including the <code>.class</code> suffix
-     */
-    private Set<String> getExcludes() {
-        Set<String> result = new HashSet<String>();
-        for (String exclude : kp.getExcludes()) {
-            String name = exclude + ".class";
-            String renamed = renames.get(name);
-            result.add((renamed != null) ? renamed : name);
-        }
-        return result;
-    }
-
-    /**
-     *
-     * @param struct
-     * @return <code>true</code> if the entry is to include in the output jar
-     * @throws IOException
-     */
-    public boolean process(EntryStruct struct) throws IOException {
-        String name = struct.name;
-        boolean keepIt = chain.process(struct);
-        if (keepIt) {
-            if (!name.equals(struct.name)) {
-                if (kp != null)
-                    renames.put(name, struct.name);
-                if (verbose)
-                    System.err.println("Renamed " + name + " -> " + struct.name);
-            }
-        } else {
-            if (verbose)
-                System.err.println("Removed " + name);
-        }
-        return keepIt;
-    }
+    return keepIt;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/MainUtil.java b/src/main/com/tonicsystems/jarjar/MainUtil.java
index 068ece6..3ad978d 100644
--- a/src/main/com/tonicsystems/jarjar/MainUtil.java
+++ b/src/main/com/tonicsystems/jarjar/MainUtil.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,71 +16,75 @@
 
 package com.tonicsystems.jarjar;
 
+import static java.lang.Math.max;
+
 import java.io.File;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
-class MainUtil
-{
-    public static void runMain(Object main, String[] args, String defCommand) throws Exception {
-        if (args.length > 0) {
-            String command = args[0];
-            Method[] methods = main.getClass().getMethods();
-            for (int i = 0; i < methods.length; i++) {
-                Method method = methods[i];
-                if (method.getName().equals(command)) {
-                    String[] remaining = new String[args.length - 1];
-                    System.arraycopy(args, 1, remaining, 0, remaining.length);
-                    try {
-                        method.invoke(main, bindParameters(method, remaining));
-                    } catch (InvocationTargetException e) {
-                        Throwable cause = e.getCause();
-                        if (cause instanceof IllegalArgumentException) {
-                            System.err.println("Syntax error: " + cause.getMessage());
-                        } else if (cause instanceof Exception) {
-                            throw (Exception) cause;
-                        } else {
-                            throw e;
-                        }
-                    }
-                    return;
-                }
-            }
-        }
-        if (defCommand != null)
-            runMain(main, new String[]{ defCommand }, null);
-    }
-
-    private static Object[] bindParameters(Method method, String[] args) {
-        List<Object> parameters = new ArrayList<Object>();
-        Class[] parameterTypes = method.getParameterTypes();
-        for (int i = 0, len = parameterTypes.length; i < len; i++) {
-            Class type = parameterTypes[i];
-            int remaining = Math.max(0, args.length - i);
-            if (type.equals(String[].class)) {
-                String[] rest = new String[remaining];
-                System.arraycopy(args, 1, rest, 0, remaining);
-                parameters.add(rest);
-            } else if (remaining > 0) {
-                parameters.add(convertParameter(args[i], parameterTypes[i]));
+final class MainUtil {
+  public static void runMain(Object main, String[] args, String defCommand) throws Exception {
+    if (args.length > 0) {
+      String command = args[0];
+      Method[] methods = main.getClass().getMethods();
+      for (int i = 0; i < methods.length; i++) {
+        Method method = methods[i];
+        if (method.getName().equals(command)) {
+          String[] remaining = new String[args.length - 1];
+          System.arraycopy(args, 1, remaining, 0, remaining.length);
+          try {
+            method.invoke(main, bindParameters(method, remaining));
+          } catch (InvocationTargetException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof IllegalArgumentException) {
+              System.err.println("Syntax error: " + cause.getMessage());
+            } else if (cause instanceof Exception) {
+              throw (Exception) cause;
             } else {
-                parameters.add(null);
+              throw e;
             }
+          }
+          return;
         }
-        return parameters.toArray();
+      }
     }
+    if (defCommand != null) {
+      runMain(main, new String[] {defCommand}, null);
+    }
+  }
 
-    private static Object convertParameter(String arg, Class type) {
-        if (type.equals(String.class)) {
-            return arg;
-        } else if (type.equals(Integer.class)) {
-            return Integer.valueOf(arg, 10);
-        } else if (type.equals(File.class)) {
-            return new File(arg);
-        } else {
-            throw new UnsupportedOperationException("Unknown type " + type);
-        }
+  private static Object[] bindParameters(Method method, String[] args) {
+    List<Object> parameters = new ArrayList<>();
+    Class[] parameterTypes = method.getParameterTypes();
+    for (int i = 0, len = parameterTypes.length; i < len; i++) {
+      Class type = parameterTypes[i];
+      int remaining = max(0, args.length - i);
+      if (type.equals(String[].class)) {
+        String[] rest = new String[remaining];
+        System.arraycopy(args, 1, rest, 0, remaining);
+        parameters.add(rest);
+      } else if (remaining > 0) {
+        parameters.add(convertParameter(args[i], parameterTypes[i]));
+      } else {
+        parameters.add(null);
+      }
     }
+    return parameters.toArray();
+  }
+
+  private static Object convertParameter(String arg, Class type) {
+    if (type.equals(String.class)) {
+      return arg;
+    } else if (type.equals(Integer.class)) {
+      return Integer.valueOf(arg, 10);
+    } else if (type.equals(File.class)) {
+      return new File(arg);
+    } else {
+      throw new UnsupportedOperationException("Unknown type " + type);
+    }
+  }
+
+  private MainUtil() {}
 }
diff --git a/src/main/com/tonicsystems/jarjar/ManifestProcessor.java b/src/main/com/tonicsystems/jarjar/ManifestProcessor.java
index 91f1f76..6c33c23 100644
--- a/src/main/com/tonicsystems/jarjar/ManifestProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/ManifestProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,22 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
+import com.tonicsystems.jarjar.util.EntryStruct;
+import com.tonicsystems.jarjar.util.JarProcessor;
 import java.io.IOException;
-import java.util.*;
 
-class ManifestProcessor implements JarProcessor
-{
-    private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
-    private static final ManifestProcessor INSTANCE = new ManifestProcessor();
+class ManifestProcessor implements JarProcessor {
+  private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+  private static final ManifestProcessor INSTANCE = new ManifestProcessor();
 
-    public static ManifestProcessor getInstance() {
-        return INSTANCE;
-    }
-    
-    private ManifestProcessor() {}
+  public static ManifestProcessor getInstance() {
+    return INSTANCE;
+  }
 
-    public boolean process(EntryStruct struct) throws IOException {
-        return !struct.name.equalsIgnoreCase(MANIFEST_PATH);
-    }
+  private ManifestProcessor() {}
+
+  @Override
+  public boolean process(EntryStruct struct) throws IOException {
+    return !struct.name.equalsIgnoreCase(MANIFEST_PATH);
+  }
 }
-    
diff --git a/src/main/com/tonicsystems/jarjar/PackageRemapper.java b/src/main/com/tonicsystems/jarjar/PackageRemapper.java
index e281f24..7533082 100644
--- a/src/main/com/tonicsystems/jarjar/PackageRemapper.java
+++ b/src/main/com/tonicsystems/jarjar/PackageRemapper.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,112 +16,124 @@
 
 package com.tonicsystems.jarjar;
 
-import org.objectweb.asm.commons.*;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
+import org.objectweb.asm.commons.Remapper;
 
-class PackageRemapper extends Remapper
-{
-    private static final String RESOURCE_SUFFIX = "RESOURCE";
-    
-    private static final Pattern ARRAY_FOR_NAME_PATTERN
-        = Pattern.compile("\\[L[\\p{javaJavaIdentifierPart}\\.]+?;");
+class PackageRemapper extends Remapper {
+  private static final String RESOURCE_SUFFIX = "RESOURCE";
 
-    private final WildcardTrie wildcards;
-    private final Map<String, String> typeCache = new HashMap<String, String>();
-    private final Map<String, String> pathCache = new HashMap<String, String>();
-    private final Map<Object, String> valueCache = new HashMap<Object, String>();
-    private final boolean verbose;
+  private static final Pattern ARRAY_FOR_NAME_PATTERN =
+      Pattern.compile("\\[L[\\p{javaJavaIdentifierPart}\\.]+?;");
 
-    public PackageRemapper(List<Rule> ruleList, boolean verbose) {
-        this.verbose = verbose;
-        wildcards = new WildcardTrie(PatternElement.createWildcards(ruleList));
+  private final WildcardTrie wildcards;
+  private final Map<String, String> typeCache = new HashMap<>();
+  private final Map<String, String> pathCache = new HashMap<>();
+  private final Map<Object, String> valueCache = new HashMap<>();
+  private final boolean verbose;
+
+  public PackageRemapper(List<Rule> ruleList, boolean verbose) {
+    this.verbose = verbose;
+    wildcards = new WildcardTrie(PatternElement.createWildcards(ruleList));
+  }
+
+  // also used by KeepProcessor
+  static boolean isArrayForName(String value) {
+    return ARRAY_FOR_NAME_PATTERN.matcher(value).matches();
+  }
+
+  @Override
+  public String map(String key) {
+    String s = typeCache.get(key);
+    if (s == null) {
+      s = replaceHelper(key);
+      if (key.equals(s)) {
+        s = null;
+      }
+      typeCache.put(key, s);
     }
+    return s;
+  }
 
-    // also used by KeepProcessor
-    static boolean isArrayForName(String value) {
-      return ARRAY_FOR_NAME_PATTERN.matcher(value).matches();
+  public String mapPath(String path) {
+    String s = pathCache.get(path);
+    if (s == null) {
+      s = path;
+      int slash = s.lastIndexOf('/');
+      String end;
+      if (slash < 0) {
+        end = s;
+        s = RESOURCE_SUFFIX;
+      } else {
+        end = s.substring(slash + 1);
+        s = s.substring(0, slash + 1) + RESOURCE_SUFFIX;
+      }
+      boolean absolute = s.startsWith("/");
+      if (absolute) {
+        s = s.substring(1);
+      }
+
+      s = replaceHelper(s);
+
+      if (absolute) {
+        s = "/" + s;
+      }
+      if (!s.contains(RESOURCE_SUFFIX)) {
+        return path;
+      }
+      s = s.substring(0, s.length() - RESOURCE_SUFFIX.length()) + end;
+      pathCache.put(path, s);
     }
+    return s;
+  }
 
-    public String map(String key) {
-        String s = typeCache.get(key);
-        if (s == null) {
-            s = replaceHelper(key);
-            if (key.equals(s))
-                s = null;
-            typeCache.put(key, s);
-        }
-        return s;
-    }
-
-    public String mapPath(String path) {
-        String s = pathCache.get(path);
-        if (s == null) {
-            s = path;
-            int slash = s.lastIndexOf('/');
-            String end;
-            if (slash < 0) {
-                end = s;
-                s = RESOURCE_SUFFIX;
-            } else {
-                end = s.substring(slash + 1);
-                s = s.substring(0, slash + 1) + RESOURCE_SUFFIX;
-            }
-            boolean absolute = s.startsWith("/");
-            if (absolute) s = s.substring(1);
-            
-            s = replaceHelper(s);
-            
-            if (absolute) s = "/" + s;
-            if (s.indexOf(RESOURCE_SUFFIX) < 0)
-              return path;
-            s = s.substring(0, s.length() - RESOURCE_SUFFIX.length()) + end;
-            pathCache.put(path, s);
-        }
-        return s;
-    }
-
-    public Object mapValue(Object value) {
-        if (value instanceof String) {
-            String s = valueCache.get(value);
-            if (s == null) {
-                s = (String)value;
-                if (isArrayForName(s)) {
-                    String desc1 = s.replace('.', '/');
-                    String desc2 = mapDesc(desc1);
-                    if (!desc2.equals(desc1))
-                        return desc2.replace('/', '.');
-                } else {
-                    s = mapPath(s);
-                    if (s.equals(value)) {
-                        boolean hasDot = s.indexOf('.') >= 0;
-                        boolean hasSlash = s.indexOf('/') >= 0;
-                        if (!(hasDot && hasSlash)) {
-                            if (hasDot) {
-                                s = replaceHelper(s.replace('.', '/')).replace('/', '.');
-                            } else {
-                                s = replaceHelper(s);
-                            }
-                        }
-                    }
-                }
-                valueCache.put(value, s);
-            }
-            // TODO: add back class name to verbose message
-            if (verbose && !s.equals(value))
-                System.err.println("Changed \"" + value + "\" -> \"" + s + "\"");
-            return s;
+  @Override
+  public Object mapValue(Object value) {
+    if (value instanceof String) {
+      String s = valueCache.get(value);
+      if (s == null) {
+        s = (String) value;
+        if (isArrayForName(s)) {
+          String desc1 = s.replace('.', '/');
+          String desc2 = mapDesc(desc1);
+          if (!desc2.equals(desc1)) {
+            return desc2.replace('/', '.');
+          }
         } else {
-            return super.mapValue(value);
+          s = mapPath(s);
+          if (s.equals(value)) {
+            boolean hasDot = s.indexOf('.') >= 0;
+            boolean hasSlash = s.indexOf('/') >= 0;
+            if (!(hasDot && hasSlash)) {
+              if (hasDot) {
+                s = replaceHelper(s.replace('.', '/')).replace('/', '.');
+              } else {
+                s = replaceHelper(s);
+              }
+            }
+          }
         }
+        valueCache.put(value, s);
+      }
+      // TODO: add back class name to verbose message
+      if (verbose && !s.equals(value)) {
+        System.err.println("Changed \"" + value + "\" -> \"" + s + "\"");
+      }
+      return s;
+    } else {
+      return super.mapValue(value);
     }
+  }
 
-    private String replaceHelper(String value) {
-        for (Wildcard wildcard : wildcards.getPossibleMatches(value)) {
-            String test = wildcard.replace(value);
-            if (test != null)
-                return test;
-        }
-        return value;
+  private String replaceHelper(String value) {
+    for (Wildcard wildcard : wildcards.getPossibleMatches(value)) {
+      String test = wildcard.replace(value);
+      if (test != null) {
+        return test;
+      }
     }
+    return value;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/PathClass.java b/src/main/com/tonicsystems/jarjar/PathClass.java
index fbbb7ed..81a4da2 100644
--- a/src/main/com/tonicsystems/jarjar/PathClass.java
+++ b/src/main/com/tonicsystems/jarjar/PathClass.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,25 @@
 
 package com.tonicsystems.jarjar;
 
-public class PathClass
-{
-    private String classPath;
-    private String className;
-    
-    public PathClass(String classPath, String className) {
-        this.classPath = classPath;
-        this.className = className;
-    }
+public class PathClass {
+  private final String classPath;
+  private final String className;
 
-    public String getClassPath() {
-        return classPath;
-    }
+  public PathClass(String classPath, String className) {
+    this.classPath = classPath;
+    this.className = className;
+  }
 
-    public String getClassName() {
-        return className;
-    }
+  public String getClassPath() {
+    return classPath;
+  }
 
-    public String toString() {
-        return classPath + "!" + className;
-    }
+  public String getClassName() {
+    return className;
+  }
+
+  @Override
+  public String toString() {
+    return classPath + "!" + className;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/PatternElement.java b/src/main/com/tonicsystems/jarjar/PatternElement.java
index 6b852d7..399928d 100644
--- a/src/main/com/tonicsystems/jarjar/PatternElement.java
+++ b/src/main/com/tonicsystems/jarjar/PatternElement.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,31 +16,32 @@
 
 package com.tonicsystems.jarjar;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
 
-abstract public class PatternElement
-{
-    private String pattern;
-    
-    public void setPattern(String pattern) {
-        this.pattern = pattern;
-    }
+public abstract class PatternElement {
+  private String pattern;
 
-    public String getPattern() {
-        return pattern;
-    }
+  public void setPattern(String pattern) {
+    this.pattern = pattern;
+  }
 
-    static List<Wildcard> createWildcards(List<? extends PatternElement> patterns) {
-        List<Wildcard> wildcards = new ArrayList<Wildcard>();
-        int ruleIndex = 0;
-        for (PatternElement pattern : patterns) {
-            String result = (pattern instanceof Rule) ? ((Rule)pattern).getResult() : "";
-            String expr = pattern.getPattern();
-            if (expr.indexOf('/') >= 0)
-                throw new IllegalArgumentException("Patterns cannot contain slashes");
-            wildcards.add(new Wildcard(expr.replace('.', '/'), result, ruleIndex));
-            ruleIndex++;
-        }
-        return wildcards;
+  public String getPattern() {
+    return pattern;
+  }
+
+  static List<Wildcard> createWildcards(List<? extends PatternElement> patterns) {
+    List<Wildcard> wildcards = new ArrayList<>();
+    int ruleIndex = 0;
+    for (PatternElement pattern : patterns) {
+      String result = (pattern instanceof Rule) ? ((Rule) pattern).getResult() : "";
+      String expr = pattern.getPattern();
+      if (expr.indexOf('/') >= 0) {
+        throw new IllegalArgumentException("Patterns cannot contain slashes");
+      }
+      wildcards.add(new Wildcard(expr.replace('.', '/'), result, ruleIndex));
+      ruleIndex++;
     }
+    return wildcards;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/ResourceProcessor.java b/src/main/com/tonicsystems/jarjar/ResourceProcessor.java
index c07f664..8678cec 100644
--- a/src/main/com/tonicsystems/jarjar/ResourceProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/ResourceProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
+import com.tonicsystems.jarjar.util.EntryStruct;
+import com.tonicsystems.jarjar.util.JarProcessor;
 import java.io.IOException;
-import java.util.*;
 
-class ResourceProcessor implements JarProcessor
-{
-    private PackageRemapper pr;
+class ResourceProcessor implements JarProcessor {
+  private final PackageRemapper pr;
 
-    public ResourceProcessor(PackageRemapper pr) {
-        this.pr = pr;
+  public ResourceProcessor(PackageRemapper pr) {
+    this.pr = pr;
+  }
+
+  @Override
+  public boolean process(EntryStruct struct) throws IOException {
+    if (!struct.isClass()) {
+      struct.name = pr.mapPath(struct.name);
     }
-
-    public boolean process(EntryStruct struct) throws IOException {
-        if (!struct.name.endsWith(".class"))
-            struct.name = pr.mapPath(struct.name);
-        return true;
-    }
+    return true;
+  }
 }
-    
diff --git a/src/main/com/tonicsystems/jarjar/Rule.java b/src/main/com/tonicsystems/jarjar/Rule.java
index 2e76ca8..96de530 100644
--- a/src/main/com/tonicsystems/jarjar/Rule.java
+++ b/src/main/com/tonicsystems/jarjar/Rule.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,14 @@
 
 package com.tonicsystems.jarjar;
 
-public class Rule extends PatternElement
-{
-    private String result;
+public class Rule extends PatternElement {
+  private String result;
 
-    public void setResult(String result) {
-        this.result = result;
-    }
+  public void setResult(String result) {
+    this.result = result;
+  }
 
-    public String getResult() {
-        return result;
-    }
+  public String getResult() {
+    return result;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/RulesFileParser.java b/src/main/com/tonicsystems/jarjar/RulesFileParser.java
index c8c6ea4..4297ee7 100644
--- a/src/main/com/tonicsystems/jarjar/RulesFileParser.java
+++ b/src/main/com/tonicsystems/jarjar/RulesFileParser.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,72 +16,85 @@
 
 package com.tonicsystems.jarjar;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import com.android.jarjar.StripAnnotation;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
-import java.io.*;
-import java.util.*;
+class RulesFileParser {
+  private RulesFileParser() {}
 
-class RulesFileParser
-{
-    private RulesFileParser() {
-    }
+  public static List<PatternElement> parse(File file) throws IOException {
+    return parse(Files.newBufferedReader(file.toPath(), UTF_8));
+  }
 
-    public static List<PatternElement> parse(File file) throws IOException {
-        return parse(new FileReader(file));
-    }
+  public static List<PatternElement> parse(String value) throws IOException {
+    return parse(new java.io.StringReader(value));
+  }
 
-    public static List<PatternElement> parse(String value) throws IOException {
-        return parse(new java.io.StringReader(value));
-    }
-
-    private static String stripComment(String in) {
-      int p = in.indexOf("#");
-      return p < 0 ? in : in.substring(0, p);
-    }
-
-    private static List<PatternElement> parse(Reader r) throws IOException {
-      try {
-        List<PatternElement> patterns = new ArrayList<PatternElement>();
-        BufferedReader br = new BufferedReader(r);
-        int c = 1;
-        String line;
-        while ((line = br.readLine()) != null) {
-            line = stripComment(line);
-            if (line.isEmpty())
-                continue;
-            String[] parts = line.split("\\s+");
-            if (parts.length < 2)
-                error(c, parts);
-            String type = parts[0];
-            PatternElement element = null;
-            if (type.equals("rule")) {
-                if (parts.length < 3)
-                    error(c, parts);
-                Rule rule = new Rule();
-                rule.setResult(parts[2]);
-                element = rule;
-            } else if (type.equals("zap")) {
-                element = new Zap();
-            } else if (type.equals("keep")) {
-                element = new Keep();
-            // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
-            } else if (type.equals("strip-annotation")) {
-                element = new StripAnnotation();
-            // ANDROID-END: b/222743634 Strip annotations from system module stubs
-            } else {
-                error(c, parts);
-            }
-            element.setPattern(parts[1]);
-            patterns.add(element);
-            c++;
+  private static List<PatternElement> parse(Reader r) throws IOException {
+    try {
+      List<PatternElement> patterns = new ArrayList<>();
+      BufferedReader br = new BufferedReader(r);
+      int c = 1;
+      String line;
+      while ((line = br.readLine()) != null) {
+        line = stripComment(line);
+        if (line.isEmpty()) {
+          continue;
         }
-        return patterns;
-      } finally {
-        r.close();
+        String[] parts = line.split("\\s+");
+        if (parts.length < 2) {
+          error(c, parts);
+        }
+        String type = parts[0];
+        PatternElement element = null;
+        switch (type) {
+          case "rule":
+            if (parts.length < 3) {
+              error(c, parts);
+            }
+            Rule rule = new Rule();
+            rule.setResult(parts[2]);
+            element = rule;
+            break;
+          case "zap":
+            element = new Zap();
+            break;
+          case "keep":
+            element = new Keep();
+            break;
+          // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs
+          case "strip-annotation":
+            element = new StripAnnotation();
+            break;
+          // ANDROID-END: b/222743634 Strip annotations from system module stubs
+          default:
+            error(c, parts);
+        }
+        element.setPattern(parts[1]);
+        patterns.add(element);
+        c++;
       }
+      return patterns;
+    } finally {
+      r.close();
     }
+  }
 
-    private static void error(int line, String[] parts) {
-      throw new IllegalArgumentException("Error on line " + line + ": " + Arrays.asList(parts));
-    }
+  private static String stripComment(String in) {
+    int p = in.indexOf("#");
+    return p < 0 ? in : in.substring(0, p);
+  }
+
+  private static void error(int line, String[] parts) {
+    throw new IllegalArgumentException("Error on line " + line + ": " + Arrays.asList(parts));
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/StringDumper.java b/src/main/com/tonicsystems/jarjar/StringDumper.java
index 5086314..b428e63 100644
--- a/src/main/com/tonicsystems/jarjar/StringDumper.java
+++ b/src/main/com/tonicsystems/jarjar/StringDumper.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,81 +16,98 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import java.io.*;
-import org.objectweb.asm.*;
+import com.tonicsystems.jarjar.util.ClassPathEntry;
+import com.tonicsystems.jarjar.util.ClassPathIterator;
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import org.objectweb.asm.ClassReader;
 
-class StringDumper
-{
-    public StringDumper() {
-    }
+class StringDumper {
+  public StringDumper() {}
 
-    public void run(String classPath, PrintWriter pw) throws IOException {
-        StringReader stringReader = new DumpStringReader(pw);
-        ClassPathIterator cp = new ClassPathIterator(classPath);
+  public void run(String classPath, PrintWriter pw) throws IOException {
+    StringReader stringReader = new DumpStringReader(pw);
+    ClassPathIterator cp = new ClassPathIterator(classPath);
+    try {
+      while (cp.hasNext()) {
+        ClassPathEntry entry = cp.next();
+        InputStream in = entry.openStream();
         try {
-            while (cp.hasNext()) {
-                ClassPathEntry entry = cp.next();
-                InputStream in = entry.openStream();
-                try {
-                    new ClassReader(in).accept(stringReader, 0);
-                } catch (Exception e) {
-                    System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
-                } finally {
-                    in.close();
-                }
-                pw.flush();
-            }
-        } catch (RuntimeIOException e) {
-            throw (IOException)e.getCause();
+          new ClassReader(in).accept(stringReader, 0);
+        } catch (Exception e) {
+          System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
         } finally {
-          cp.close();
+          in.close();
         }
+        pw.flush();
+      }
+    } catch (RuntimeIOException e) {
+      throw (IOException) e.getCause();
+    } finally {
+      cp.close();
+    }
+  }
+
+  private static class DumpStringReader extends StringReader {
+    private final PrintWriter pw;
+    private String className;
+
+    public DumpStringReader(PrintWriter pw) {
+      this.pw = pw;
     }
 
-    private static class DumpStringReader extends StringReader
-    {
-        private final PrintWriter pw;
-        private String className;
-
-        public DumpStringReader(PrintWriter pw) {
-            this.pw = pw;
+    @Override
+    public void visitString(String className, String value, int line) {
+      if (value.length() > 0) {
+        if (!className.equals(this.className)) {
+          this.className = className;
+          pw.println(className.replace('/', '.'));
         }
-
-        public void visitString(String className, String value, int line) {
-            if (value.length() > 0) {
-                if (!className.equals(this.className)) {
-                    this.className = className;
-                    pw.println(className.replace('/', '.'));
-                }
-                pw.print("\t");
-                if (line >= 0)
-                    pw.print(line + ": ");
-                pw.print(escapeStringLiteral(value));
-                pw.println();
-            }
+        pw.print("\t");
+        if (line >= 0) {
+          pw.print(line + ": ");
         }
-    };
-
-    private static String escapeStringLiteral(String value) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("\"");
-        char[] chars = value.toCharArray();
-        for (int i = 0, size = chars.length; i < size; i++) {
-            char ch = chars[i];
-            switch (ch) {
-            case '\n': sb.append("\\n"); break;
-            case '\r': sb.append("\\r"); break;
-            case '\b': sb.append("\\b"); break;
-            case '\f': sb.append("\\f"); break;
-            case '\t': sb.append("\\t"); break;
-            case '\"': sb.append("\\\""); break;
-            case '\\': sb.append("\\\\"); break;
-            default:
-                sb.append(ch);
-            }
-        }
-        sb.append("\"");
-        return sb.toString();
+        pw.print(escapeStringLiteral(value));
+        pw.println();
+      }
     }
+  }
+
+  private static String escapeStringLiteral(String value) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("\"");
+    char[] chars = value.toCharArray();
+    for (int i = 0, size = chars.length; i < size; i++) {
+      char ch = chars[i];
+      switch (ch) {
+        case '\n':
+          sb.append("\\n");
+          break;
+        case '\r':
+          sb.append("\\r");
+          break;
+        case '\b':
+          sb.append("\\b");
+          break;
+        case '\f':
+          sb.append("\\f");
+          break;
+        case '\t':
+          sb.append("\\t");
+          break;
+        case '\"':
+          sb.append("\\\"");
+          break;
+        case '\\':
+          sb.append("\\\\");
+          break;
+        default:
+          sb.append(ch);
+      }
+    }
+    sb.append("\"");
+    return sb.toString();
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/StringReader.java b/src/main/com/tonicsystems/jarjar/StringReader.java
index c3cc273..07a5ec8 100644
--- a/src/main/com/tonicsystems/jarjar/StringReader.java
+++ b/src/main/com/tonicsystems/jarjar/StringReader.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,85 +16,105 @@
 
 package com.tonicsystems.jarjar;
 
-import org.objectweb.asm.*;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
 
-abstract class StringReader extends ClassVisitor
-{
-    private int line = -1;
-    private String className;
+abstract class StringReader extends ClassVisitor {
+  private int line = -1;
+  private String className;
 
-    public StringReader() {
-        super(Opcodes.ASM9);
+  public StringReader() {
+    super(Opcodes.ASM9);
+  }
+
+  public abstract void visitString(String className, String value, int line);
+
+  private void handleObject(Object value) {
+    if (value instanceof String) {
+      visitString(className, (String) value, line);
     }
-    
-    abstract public void visitString(String className, String value, int line);
+  }
 
-    private void handleObject(Object value) {
-        if (value instanceof String)
-            visitString(className, (String)value, line);
-    }
-    
-    @Override
-    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
-        className = name;
-        line = -1;
-    }
+  @Override
+  public void visit(
+      int version,
+      int access,
+      String name,
+      String signature,
+      String superName,
+      String[] interfaces) {
+    className = name;
+    line = -1;
+  }
 
-    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+  @Override
+  public FieldVisitor visitField(
+      int access, String name, String desc, String signature, Object value) {
+    handleObject(value);
+    return new FieldVisitor(Opcodes.ASM9) {
+      @Override
+      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        return StringReader.this.visitAnnotation(desc, visible);
+      }
+    };
+  }
+
+  @Override
+  public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+    return new AnnotationVisitor(Opcodes.ASM9) {
+      @Override
+      public void visit(String name, Object value) {
         handleObject(value);
-        return new FieldVisitor(Opcodes.ASM9){
-            @Override
-            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-                return StringReader.this.visitAnnotation(desc, visible);
-            }
-        };
-    }
-    
-    @Override
-    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-        return new AnnotationVisitor(Opcodes.ASM9) {
-            @Override
-            public void visit(String name, Object value) {
-                handleObject(value);
-            }
-            @Override
-            public void visitEnum(String name, String desc, String value) {
-                handleObject(value);
-            }
-            @Override
-            public AnnotationVisitor visitAnnotation(String name, String desc) {
-                return this;
-            }
-        };
-    }
-    
-    @Override
-    public MethodVisitor visitMethod(int access, String name, String desc,
-            String signature, String[] exceptions) {
-        MethodVisitor mv = new MethodVisitor(Opcodes.ASM9){
-            @Override
-            public void visitLdcInsn(Object cst) {
-                handleObject(cst);
-            }
-            @Override
-            public void visitLineNumber(int line, Label start) {
-                StringReader.this.line = line;
-            }
-            @Override
-            public void visitInvokeDynamicInsn(String name, String desc,
-                    Handle bsm, Object... bsmArgs) {
-                for (Object bsmArg : bsmArgs) handleObject(bsmArg);
-            }
-            @Override
-            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-                return StringReader.this.visitAnnotation(desc, visible);
-            }
-            @Override
-            public AnnotationVisitor visitParameterAnnotation(int parameter,
-                    String desc, boolean visible) {
-                return StringReader.this.visitAnnotation(desc, visible);
-            }
-        };
-        return mv;
-    }
+      }
+
+      @Override
+      public void visitEnum(String name, String desc, String value) {
+        handleObject(value);
+      }
+
+      @Override
+      public AnnotationVisitor visitAnnotation(String name, String desc) {
+        return this;
+      }
+    };
+  }
+
+  @Override
+  public MethodVisitor visitMethod(
+      int access, String name, String desc, String signature, String[] exceptions) {
+    return new MethodVisitor(Opcodes.ASM9) {
+      @Override
+      public void visitLdcInsn(Object cst) {
+        handleObject(cst);
+      }
+
+      @Override
+      public void visitLineNumber(int line, Label start) {
+        StringReader.this.line = line;
+      }
+
+      @Override
+      public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+        for (Object bsmArg : bsmArgs) {
+          handleObject(bsmArg);
+        }
+      }
+
+      @Override
+      public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        return StringReader.this.visitAnnotation(desc, visible);
+      }
+
+      @Override
+      public AnnotationVisitor visitParameterAnnotation(
+          int parameter, String desc, boolean visible) {
+        return StringReader.this.visitAnnotation(desc, visible);
+      }
+    };
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/TextDepHandler.java b/src/main/com/tonicsystems/jarjar/TextDepHandler.java
index 3551395..82f7d28 100644
--- a/src/main/com/tonicsystems/jarjar/TextDepHandler.java
+++ b/src/main/com/tonicsystems/jarjar/TextDepHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
 
 package com.tonicsystems.jarjar;
 
-import java.io.*;
-import java.util.*;
+import java.io.IOException;
+import java.io.PrintWriter;
 
-public class TextDepHandler extends AbstractDepHandler
-{
-    private PrintWriter w;
-    
-    public TextDepHandler(PrintWriter w, int level) {
-        super(level);
-        this.w = w;
-    }
-    
-    protected void handle(String from, String to) throws IOException {
-        w.println(from + " -> " + to);
-    }
+public class TextDepHandler extends AbstractDepHandler {
+  private final PrintWriter w;
+
+  public TextDepHandler(PrintWriter w, int level) {
+    super(level);
+    this.w = w;
+  }
+
+  @Override
+  protected void handle(String from, String to) throws IOException {
+    w.println(from + " -> " + to);
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/Wildcard.java b/src/main/com/tonicsystems/jarjar/Wildcard.java
index 2522e0d..c5d0c20 100644
--- a/src/main/com/tonicsystems/jarjar/Wildcard.java
+++ b/src/main/com/tonicsystems/jarjar/Wildcard.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,153 +16,172 @@
 
 package com.tonicsystems.jarjar;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
-class Wildcard
-{
-    private static Pattern dstar = Pattern.compile("\\*\\*");
-    private static Pattern star  = Pattern.compile("\\*");
-    private static Pattern estar = Pattern.compile("\\+\\??\\)\\Z");
-    private static Pattern dollar = Pattern.compile("\\$");
-    // Apart from stars and dollar signs, wildcards are plain-text full matches
-    private static Pattern plainTextPrefixPattern = Pattern.compile("^[^*$]*");
+class Wildcard {
+  private static final Pattern DSTAR = Pattern.compile("\\*\\*");
+  private static final Pattern STAR = Pattern.compile("\\*");
+  private static final Pattern ESTAR = Pattern.compile("\\+\\??\\)\\Z");
+  private static final Pattern DOLLAR = Pattern.compile("\\$");
+  // Apart from stars and dollar signs, wildcards are plain-text full matches
+  private static final Pattern PLAIN_TEXT_PREFIX_PATTERN = Pattern.compile("^[^*$]*");
 
-    private final Pattern pattern;
-    private final String plainTextPrefix;
-    private final int ruleIndex;
-    private final int count;
-    private final ArrayList<Object> parts = new ArrayList<Object>(16); // kept for debugging
-    private final String[] strings;
-    private final int[] refs;
+  private final Pattern pattern;
+  private final String plainTextPrefix;
+  private final int ruleIndex;
+  private final int count;
+  private final ArrayList<Object> parts = new ArrayList<>(16); // kept for debugging
+  private final String[] strings;
+  private final int[] refs;
 
-    public Wildcard(String pattern, String result, int ruleIndex) {
-        if (pattern.equals("**"))
-            throw new IllegalArgumentException("'**' is not a valid pattern");
-        if (!checkIdentifierChars(pattern, "/*"))
-            throw new IllegalArgumentException("Not a valid package pattern: " + pattern);
-        if (pattern.indexOf("***") >= 0)
-            throw new IllegalArgumentException("The sequence '***' is invalid in a package pattern");
-        
-        String regex = pattern;
-        regex = replaceAllLiteral(dstar, regex, "(.+?)");
-        regex = replaceAllLiteral(star, regex, "([^/]+)");
-        regex = replaceAllLiteral(estar, regex, "*)");
-        regex = replaceAllLiteral(dollar, regex, "\\$");
-        Matcher prefixMatcher = plainTextPrefixPattern.matcher(pattern);
-        // prefixMatcher will always match, but may match an empty string
-        if (!prefixMatcher.find()) {
-            throw new IllegalArgumentException(plainTextPrefixPattern + " not found in " + pattern);
+  public Wildcard(String pattern, String result, int ruleIndex) {
+    if (pattern.equals("**")) {
+      throw new IllegalArgumentException("'**' is not a valid pattern");
+    }
+    if (!checkIdentifierChars(pattern, "/*-")) {
+      throw new IllegalArgumentException("Not a valid package pattern: " + pattern);
+    }
+    if (pattern.contains("***")) {
+      throw new IllegalArgumentException("The sequence '***' is invalid in a package pattern");
+    }
+
+    String regex = pattern;
+    regex = replaceAllLiteral(DSTAR, regex, "(.+?)");
+    regex = replaceAllLiteral(STAR, regex, "([^/]+)");
+    regex = replaceAllLiteral(ESTAR, regex, "*)");
+    regex = replaceAllLiteral(DOLLAR, regex, "\\$");
+    Matcher prefixMatcher = PLAIN_TEXT_PREFIX_PATTERN.matcher(pattern);
+    // prefixMatcher will always match, but may match an empty string
+    if (!prefixMatcher.find()) {
+      throw new IllegalArgumentException(PLAIN_TEXT_PREFIX_PATTERN + " not found in " + pattern);
+    }
+    this.plainTextPrefix = prefixMatcher.group();
+    this.ruleIndex = ruleIndex;
+    this.pattern = Pattern.compile("\\A" + regex + "\\Z");
+    this.count = this.pattern.matcher("foo").groupCount();
+
+    // TODO: check for illegal characters
+    char[] chars = result.toCharArray();
+    int max = 0;
+    for (int i = 0, mark = 0, state = 0, len = chars.length; i < len + 1; i++) {
+      char ch = (i == len) ? '@' : chars[i];
+      if (state == 0) {
+        if (ch == '@') {
+          parts.add(new String(chars, mark, i - mark));
+          mark = i + 1;
+          state = 1;
         }
-        this.plainTextPrefix = prefixMatcher.group();
-        this.ruleIndex = ruleIndex;
-        this.pattern = Pattern.compile("\\A" + regex + "\\Z");
-        this.count = this.pattern.matcher("foo").groupCount();
-
-        // TODO: check for illegal characters
-        char[] chars = result.toCharArray();
-        int max = 0;
-        for (int i = 0, mark = 0, state = 0, len = chars.length; i < len + 1; i++) {
-            char ch = (i == len) ? '@' : chars[i];
-            if (state == 0) {
-                if (ch == '@') {
-                    parts.add(new String(chars, mark, i - mark));
-                    mark = i + 1;
-                    state = 1;
-                }
-            } else {
-                switch (ch) {
-                case '0': case '1': case '2': case '3': case '4':
-                case '5': case '6': case '7': case '8': case '9':
-                    break;
-                default:
-                    if (i == mark)
-                        throw new IllegalArgumentException("Backslash not followed by a digit");
-                    int n = Integer.parseInt(new String(chars, mark, i - mark));
-                    if (n > max)
-                        max = n;
-                    parts.add(new Integer(n));
-                    mark = i--;
-                    state = 0;
-                }
+      } else {
+        switch (ch) {
+          case '0':
+          case '1':
+          case '2':
+          case '3':
+          case '4':
+          case '5':
+          case '6':
+          case '7':
+          case '8':
+          case '9':
+            break;
+          default:
+            if (i == mark) {
+              throw new IllegalArgumentException("Backslash not followed by a digit");
             }
-        }
-        int size = parts.size();
-        strings = new String[size];
-        refs = new int[size];
-        Arrays.fill(refs, -1);
-        for (int i = 0; i < size; i++) {
-            Object v = parts.get(i);
-            if (v instanceof String) {
-                strings[i] = ((String)v).replace('.', '/');
-            } else {
-                refs[i] = ((Integer)v).intValue();
+            int n = Integer.parseInt(new String(chars, mark, i - mark));
+            if (n > max) {
+              max = n;
             }
+            parts.add(Integer.valueOf(n));
+            mark = i--;
+            state = 0;
         }
-        if (count < max)
-            throw new IllegalArgumentException("Result includes impossible placeholder \"@" + max + "\": " + result);
-        // System.err.println(this);
-    }
-
-    public String getPlainTextPrefix() {
-        return plainTextPrefix;
-    }
-
-    public int getRuleIndex() {
-        return ruleIndex;
-    }
-
-    public boolean matches(String value) {
-        return getMatcher(value) != null;
-    }
-
-    public String replace(String value) {
-        Matcher matcher = getMatcher(value);
-        if (matcher != null) {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < strings.length; i++)
-                sb.append((refs[i] >= 0) ? matcher.group(refs[i]) : strings[i]);
-            return sb.toString();
-        }
-        return null;
-    }
-
-    private Matcher getMatcher(String value) {
-        Matcher matcher = pattern.matcher(value);
-        if (matcher.matches() && checkIdentifierChars(value, "/"))
-            return matcher;
-        return null;
-    }
-
-    private static boolean checkIdentifierChars(String expr, String extra) {
-      // package-info violates the spec for Java Identifiers.
-      // Nevertheless, expressions that end with this string are still legal.
-      // See 7.4.1.1 of the Java language spec for discussion.
-      if (expr.endsWith("package-info")) {
-          expr = expr.substring(0, expr.length() - "package-info".length());
       }
-      // Android-changed: also include module-info
-      if (expr.endsWith("module-info")) {
-          expr = expr.substring(0, expr.length() - "module-info".length());
+    }
+    int size = parts.size();
+    strings = new String[size];
+    refs = new int[size];
+    Arrays.fill(refs, -1);
+    for (int i = 0; i < size; i++) {
+      Object v = parts.get(i);
+      if (v instanceof String) {
+        strings[i] = ((String) v).replace('.', '/');
+      } else {
+        refs[i] = ((Integer) v).intValue();
       }
-      for (int i = 0, len = expr.length(); i < len; i++) {
-          char c = expr.charAt(i);
-          if (extra.indexOf(c) >= 0)
-              continue;
-          if (!Character.isJavaIdentifierPart(c))
-              return false;
+    }
+    if (count < max) {
+      throw new IllegalArgumentException(
+          "Result includes impossible placeholder \"@" + max + "\": " + result);
+    }
+    // System.err.println(this);
+  }
+
+  public String getPlainTextPrefix() {
+    return plainTextPrefix;
+  }
+
+  public int getRuleIndex() {
+    return ruleIndex;
+  }
+
+  public boolean matches(String value) {
+    return getMatcher(value) != null;
+  }
+
+  public String replace(String value) {
+    Matcher matcher = getMatcher(value);
+    if (matcher != null) {
+      StringBuilder sb = new StringBuilder();
+      for (int i = 0; i < strings.length; i++) {
+        sb.append((refs[i] >= 0) ? matcher.group(refs[i]) : strings[i]);
       }
-      return true;
+      return sb.toString();
     }
+    return null;
+  }
 
-    private static String replaceAllLiteral(Pattern pattern, String value, String replace) {
-        replace = replace.replaceAll("([$\\\\])", "\\\\$0");
-        return pattern.matcher(value).replaceAll(replace);
+  private Matcher getMatcher(String value) {
+    Matcher matcher = pattern.matcher(value);
+    if (matcher.matches() && checkIdentifierChars(value, "/-")) {
+      return matcher;
     }
+    return null;
+  }
 
-    public String toString() {
-        return "Wildcard{pattern=" + pattern + ",parts=" + parts + "}";
+  private static boolean checkIdentifierChars(String expr, String extra) {
+    // package-info violates the spec for Java Identifiers.
+    // Nevertheless, expressions that end with this string are still legal.
+    // See 7.4.1.1 of the Java language spec for discussion.
+    if (expr.endsWith("package-info")) {
+      expr = expr.substring(0, expr.length() - "package-info".length());
     }
+    // Android-changed: also include module-info
+    if (expr.endsWith("module-info")) {
+      expr = expr.substring(0, expr.length() - "module-info".length());
+    }
+    for (int i = 0, len = expr.length(); i < len; i++) {
+      char c = expr.charAt(i);
+      if (extra.indexOf(c) >= 0) {
+        continue;
+      }
+      if (!Character.isJavaIdentifierPart(c)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private static String replaceAllLiteral(Pattern pattern, String value, String replace) {
+    replace = replace.replaceAll("([$\\\\])", "\\\\$0");
+    return pattern.matcher(value).replaceAll(replace);
+  }
+
+  @Override
+  public String toString() {
+    return "Wildcard{pattern=" + pattern + ",parts=" + parts + "}";
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/WildcardTrie.java b/src/main/com/tonicsystems/jarjar/WildcardTrie.java
index e80dbc9..c1e9b2e 100644
--- a/src/main/com/tonicsystems/jarjar/WildcardTrie.java
+++ b/src/main/com/tonicsystems/jarjar/WildcardTrie.java
@@ -23,69 +23,71 @@
 import java.util.TreeMap;
 
 /**
- * A prefix trie of {@link Wildcard}, where the prefix is obtained from
- * {@link Wildcard#getPlainTextPrefix()}.
+ * A prefix trie of {@link Wildcard}, where the prefix is obtained from {@link
+ * Wildcard#getPlainTextPrefix()}.
  *
- * This allows quick lookup of applicable wildcards in the common case where wildcards have a
+ * <p>This allows quick lookup of applicable wildcards in the common case where wildcards have a
  * non-empty plain-text prefix.
  */
 public class WildcardTrie {
-    private final TreeMap<String, WildcardTrie> subTries = new TreeMap<>();
-    private final List<Wildcard> wildcards = new ArrayList<>();
-    private final String prefix;
+  private final TreeMap<String, WildcardTrie> subTries = new TreeMap<>();
+  private final List<Wildcard> wildcards = new ArrayList<>();
+  private final String prefix;
 
-    public WildcardTrie(List<Wildcard> wildcards) {
-        this("");
-        final ArrayList<Wildcard> lst = new ArrayList<>(wildcards);
-        // Sort values to ensure that wildcards that prefix others are added first
-        lst.sort(Comparator.comparing(Wildcard::getPlainTextPrefix));
-        for (Wildcard w : lst) {
-            final String prefix = w.getPlainTextPrefix();
-            final WildcardTrie prefixTrie = findSubTrieWhichPrefixes(prefix, this);
-            if (prefixTrie.prefix.equals(prefix)) {
-                prefixTrie.wildcards.add(w);
-            } else {
-                final WildcardTrie newTrie = new WildcardTrie(prefix);
-                newTrie.wildcards.add(w);
-                prefixTrie.subTries.put(prefix, newTrie);
-            }
+  public WildcardTrie(List<Wildcard> wildcards) {
+    this("");
+    final ArrayList<Wildcard> lst = new ArrayList<>(wildcards);
+    // Sort values to ensure that wildcards that prefix others are added first
+    lst.sort(Comparator.comparing(Wildcard::getPlainTextPrefix));
+    for (Wildcard w : lst) {
+      final String prefix = w.getPlainTextPrefix();
+      final WildcardTrie prefixTrie = findSubTrieWhichPrefixes(prefix, this);
+      if (prefixTrie.prefix.equals(prefix)) {
+        prefixTrie.wildcards.add(w);
+      } else {
+        final WildcardTrie newTrie = new WildcardTrie(prefix);
+        newTrie.wildcards.add(w);
+        prefixTrie.subTries.put(prefix, newTrie);
+      }
+    }
+  }
+
+  private WildcardTrie(String prefix) {
+    this.prefix = prefix;
+  }
+
+  private static WildcardTrie findSubTrieWhichPrefixes(String value, WildcardTrie baseTrie) {
+    final String possiblePrefix = baseTrie.subTries.floorKey(value);
+    // Because each level of the trie does not contain keys that are prefixes of each other,
+    // there can be at most one prefix of the value at that level, and that prefix will be the
+    // highest key ordered before the value (any non-prefix key would have a character
+    // difference with the prefix and so be ordered before the prefix or after the value).
+    if (possiblePrefix != null && value.startsWith(possiblePrefix)) {
+      return findSubTrieWhichPrefixes(value, baseTrie.subTries.get(possiblePrefix));
+    }
+    return baseTrie;
+  }
+
+  public List<Wildcard> getPossibleMatches(String value) {
+    WildcardTrie baseTrie = this;
+    List<Wildcard> prefixMatches =
+        wildcards.isEmpty()
+            // If there's no match, don't even allocate a list and use the singleton emptyList
+            ? Collections.emptyList()
+            : new ArrayList<>(wildcards);
+    while (true) {
+      final String possiblePrefix = baseTrie.subTries.floorKey(value);
+      if (possiblePrefix != null && value.startsWith(possiblePrefix)) {
+        baseTrie = baseTrie.subTries.get(possiblePrefix);
+        if (prefixMatches.isEmpty()) {
+          prefixMatches = new ArrayList<>(baseTrie.wildcards);
+        } else {
+          prefixMatches.addAll(baseTrie.wildcards);
         }
+      } else {
+        prefixMatches.sort(Comparator.comparing(Wildcard::getRuleIndex));
+        return prefixMatches;
+      }
     }
-
-    private WildcardTrie(String prefix) {
-        this.prefix = prefix;
-    }
-
-    private static WildcardTrie findSubTrieWhichPrefixes(String value, WildcardTrie baseTrie) {
-        final String possiblePrefix = baseTrie.subTries.floorKey(value);
-        // Because each level of the trie does not contain keys that are prefixes of each other,
-        // there can be at most one prefix of the value at that level, and that prefix will be the
-        // highest key ordered before the value (any non-prefix key would have a character
-        // difference with the prefix and so be ordered before the prefix or after the value).
-        if (possiblePrefix != null && value.startsWith(possiblePrefix)) {
-            return findSubTrieWhichPrefixes(value, baseTrie.subTries.get(possiblePrefix));
-        }
-        return baseTrie;
-    }
-
-    public List<Wildcard> getPossibleMatches(String value) {
-        WildcardTrie baseTrie = this;
-        List<Wildcard> prefixMatches = wildcards.isEmpty()
-                // If there's no match, don't even allocate a list and use the singleton emptyList
-                ? Collections.emptyList() : new ArrayList<>(wildcards);
-        while (true) {
-            final String possiblePrefix = baseTrie.subTries.floorKey(value);
-            if (possiblePrefix != null && value.startsWith(possiblePrefix)) {
-                baseTrie = baseTrie.subTries.get(possiblePrefix);
-                if (prefixMatches.isEmpty()) {
-                    prefixMatches = new ArrayList<>(baseTrie.wildcards);
-                } else {
-                    prefixMatches.addAll(baseTrie.wildcards);
-                }
-            } else {
-                prefixMatches.sort(Comparator.comparing(Wildcard::getRuleIndex));
-                return prefixMatches;
-            }
-        }
-    }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/Zap.java b/src/main/com/tonicsystems/jarjar/Zap.java
index ed5c828..30a341d 100644
--- a/src/main/com/tonicsystems/jarjar/Zap.java
+++ b/src/main/com/tonicsystems/jarjar/Zap.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,4 @@
 
 package com.tonicsystems.jarjar;
 
-public class Zap extends PatternElement
-{
-}
+public class Zap extends PatternElement {}
diff --git a/src/main/com/tonicsystems/jarjar/ZapProcessor.java b/src/main/com/tonicsystems/jarjar/ZapProcessor.java
index 5b6b680..5c2c845 100644
--- a/src/main/com/tonicsystems/jarjar/ZapProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/ZapProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,34 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
+import com.tonicsystems.jarjar.util.EntryStruct;
+import com.tonicsystems.jarjar.util.JarProcessor;
 import java.io.IOException;
-import java.util.*;
+import java.util.List;
 
-class ZapProcessor implements JarProcessor
-{
-    private List<Wildcard> wildcards;
+class ZapProcessor implements JarProcessor {
+  private final List<Wildcard> wildcards;
 
-    public ZapProcessor(List<Zap> zapList) {
-        wildcards = PatternElement.createWildcards(zapList);
+  public ZapProcessor(List<Zap> zapList) {
+    wildcards = PatternElement.createWildcards(zapList);
+  }
+
+  @Override
+  public boolean process(EntryStruct struct) throws IOException {
+    String name = struct.name;
+    if (struct.isClass()) {
+      return !zap(name.substring(0, name.length() - 6));
     }
+    return true;
+  }
 
-    public boolean process(EntryStruct struct) throws IOException {
-        String name = struct.name;
-        if (name.endsWith(".class"))
-            return !zap(name.substring(0, name.length() - 6));
+  private boolean zap(String desc) {
+    // TODO: optimize
+    for (Wildcard wildcard : wildcards) {
+      if (wildcard.matches(desc)) {
         return true;
+      }
     }
-    
-    private boolean zap(String desc) {
-        // TODO: optimize
-        for (Wildcard wildcard : wildcards) {
-            if (wildcard.matches(desc))
-                return true;
-        }
-        return false;
-    }
+    return false;
+  }
 }
-    
diff --git a/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java b/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java
index ac30418..85bbe6c 100644
--- a/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,83 +25,86 @@
 import org.apache.tools.zip.ZipExtraField;
 import org.apache.tools.zip.ZipOutputStream;
 
-abstract public class AntJarProcessor extends Jar
-{
-    private EntryStruct struct = new EntryStruct();
-    private JarProcessor proc;
-    private byte[] buf = new byte[0x2000];
+public abstract class AntJarProcessor extends Jar {
+  private EntryStruct struct = new EntryStruct();
+  private JarProcessor proc;
+  private byte[] buf = new byte[0x2000];
 
-    private Set<String> dirs = new HashSet<String>();
-    private boolean filesOnly;
+  private Set<String> dirs = new HashSet<String>();
+  private boolean filesOnly;
 
-    protected boolean verbose;
+  protected boolean verbose;
 
-    private static final ZipExtraField[] JAR_MARKER = new ZipExtraField[] {
-        JarMarker.getInstance()
-    };
+  private static final ZipExtraField[] JAR_MARKER = new ZipExtraField[] {JarMarker.getInstance()};
 
-    public void setVerbose(boolean verbose) {
-        this.verbose = verbose;
+  public void setVerbose(boolean verbose) {
+    this.verbose = verbose;
+  }
+
+  public abstract void execute() throws BuildException;
+
+  public void execute(JarProcessor proc) throws BuildException {
+    this.proc = proc;
+    super.execute();
+  }
+
+  public void setFilesonly(boolean f) {
+    super.setFilesonly(f);
+    filesOnly = f;
+  }
+
+  protected void zipDir(File dir, ZipOutputStream zOut, String vPath, int mode)
+      throws IOException {}
+
+  protected void zipFile(
+      InputStream is,
+      ZipOutputStream zOut,
+      String vPath,
+      long lastModified,
+      File fromArchive,
+      int mode)
+      throws IOException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    IoUtil.pipe(is, baos, buf);
+    struct.data = baos.toByteArray();
+    struct.name = vPath;
+    struct.time = lastModified;
+    if (proc.process(struct)) {
+      if (mode == 0) {
+        mode = ZipFileSet.DEFAULT_FILE_MODE;
+      }
+      if (!filesOnly) {
+        addParentDirs(struct.name, zOut);
+      }
+      super.zipFile(
+          new ByteArrayInputStream(struct.data), zOut, struct.name, struct.time, fromArchive, mode);
     }
+  }
 
-    public abstract void execute() throws BuildException;
-
-    public void execute(JarProcessor proc) throws BuildException {
-        this.proc = proc;
-        super.execute();
-    }
-
-    public void setFilesonly(boolean f) {
-        super.setFilesonly(f);
-        filesOnly = f;
-    }
-
-    protected void zipDir(File dir, ZipOutputStream zOut, String vPath, int mode)
-        throws IOException {
-    }
-
-    protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath,
-                                     long lastModified, File fromArchive, int mode) throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        IoUtil.pipe(is, baos, buf);
-        struct.data = baos.toByteArray();
-        struct.name = vPath;
-        struct.time = lastModified;
-        if (proc.process(struct)) {
-            if (mode == 0)
-                mode = ZipFileSet.DEFAULT_FILE_MODE;
-            if (!filesOnly) {
-              addParentDirs(struct.name, zOut);
-            }
-            super.zipFile(new ByteArrayInputStream(struct.data),
-                          zOut, struct.name, struct.time, fromArchive, mode);
-        }
-    }
-
-    private void addParentDirs(String file, ZipOutputStream zOut) throws IOException {
-      int slash = file.lastIndexOf('/');
-      if (slash >= 0) {
-        String dir = file.substring(0, slash);
-        if (dirs.add(dir)) {
-          addParentDirs(dir, zOut);
-          super.zipDir((File) null, zOut, dir + "/", ZipFileSet.DEFAULT_DIR_MODE, JAR_MARKER);
-        }
+  private void addParentDirs(String file, ZipOutputStream zOut) throws IOException {
+    int slash = file.lastIndexOf('/');
+    if (slash >= 0) {
+      String dir = file.substring(0, slash);
+      if (dirs.add(dir)) {
+        addParentDirs(dir, zOut);
+        super.zipDir((File) null, zOut, dir + "/", ZipFileSet.DEFAULT_DIR_MODE, JAR_MARKER);
       }
     }
+  }
 
-    public void reset() {
-        super.reset();
-        cleanHelper();
-    }
+  public void reset() {
+    super.reset();
+    cleanHelper();
+  }
 
-    protected void cleanUp() {
-        super.cleanUp();
-        cleanHelper();
-    }
+  protected void cleanUp() {
+    super.cleanUp();
+    cleanHelper();
+  }
 
-    protected void cleanHelper() {
-        verbose = false;
-        filesOnly = false;
-        dirs.clear();
-    }
+  protected void cleanHelper() {
+    verbose = false;
+    filesOnly = false;
+    dirs.clear();
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java b/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
index 6e448be..793b270 100644
--- a/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
+++ b/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,171 +16,180 @@
 
 package com.tonicsystems.jarjar.util;
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.Array;
-import java.util.*;
 
-public class ClassHeaderReader
-{
-    private int access;
-    private String thisClass;
-    private String superClass;
-    private String[] interfaces;
+public class ClassHeaderReader {
+  private int access;
+  private String thisClass;
+  private String superClass;
+  private String[] interfaces;
 
-    private InputStream in;
-    private byte[] b = new byte[0x2000];
-    private int[] items = new int[1000];
-    private int bsize = 0;
-    private MyByteArrayInputStream bin = new MyByteArrayInputStream();
-    private DataInputStream data = new DataInputStream(bin);
+  private InputStream in;
+  private byte[] b = new byte[0x2000];
+  private int[] items = new int[1000];
+  private int bsize = 0;
+  private final MyByteArrayInputStream bin = new MyByteArrayInputStream();
+  private final DataInputStream data = new DataInputStream(bin);
 
-    public int getAccess() {
-        return access;
-    }
-    
-    public String getClassName() {
-        return thisClass;
-    }
+  public int getAccess() {
+    return access;
+  }
 
-    public String getSuperName() {
-        return superClass;
-    }
+  public String getClassName() {
+    return thisClass;
+  }
 
-    public String[] getInterfaces() {
-        return interfaces;
-    }
+  public String getSuperName() {
+    return superClass;
+  }
 
-    public void read(InputStream in) throws IOException {
-        try {
-            this.in = in;
-            bsize = 0;
-            access = 0;
-            thisClass = superClass = null;
-            interfaces = null;
+  public String[] getInterfaces() {
+    return interfaces;
+  }
 
-            try {
-                buffer(4);
-            } catch (IOException e) {
-                // ignore
-            }
-            if (b[0] != (byte)0xCA || b[1] != (byte)0xFE || b[2] != (byte)0xBA || b[3] != (byte)0xBE)
-                throw new ClassFormatError("Bad magic number");
+  public void read(InputStream in) throws IOException {
+    try {
+      this.in = in;
+      bsize = 0;
+      access = 0;
+      thisClass = superClass = null;
+      interfaces = null;
 
-            buffer(6);
-            readUnsignedShort(4); // minorVersion
-            readUnsignedShort(6); // majorVersion
-            // TODO: check version
-            int constant_pool_count = readUnsignedShort(8);
-            items = (int[])resizeArray(items, constant_pool_count);
+      try {
+        buffer(4);
+      } catch (IOException e) {
+        // ignore
+      }
+      if (b[0] != (byte) 0xCA
+          || b[1] != (byte) 0xFE
+          || b[2] != (byte) 0xBA
+          || b[3] != (byte) 0xBE) {
+        throw new ClassFormatError("Bad magic number");
+      }
 
-            int index = 10;
-            for (int i = 1; i < constant_pool_count; i++) {
-                int size;
-                buffer(index + 3); // TODO: reduce calls to buffer
-                int tag = b[index];
-                items[i] = index + 1;
-                switch (tag) {
-                case 9:  // Fieldref
-                case 10: // Methodref
-                case 11: // InterfaceMethodref
-                case 3:  // Integer
-                case 4:  // Float
-                case 12: // NameAndType
-                    size = 4;
-                    break;
-                case 5:  // Long
-                case 6:  // Double
-                    size = 8;
-                    i++;
-                    break;
-                case 1:  // Utf8
-                    size = 2 + readUnsignedShort(index + 1);
-                    break;
-                case 7:  // Class
-                case 8:  // String
-                    size = 2;
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown constant pool tag " + tag);
-                }
-                index += size + 1;
-            }
-            buffer(index + 8);
-            access = readUnsignedShort(index);
-            thisClass = readClass(index + 2);
-            superClass = readClass(index + 4);
-            int interfaces_count = readUnsignedShort(index + 6);
-        
-            index += 8;
-            buffer(index + interfaces_count * 2);
-            interfaces = new String[interfaces_count];
-            for (int i = 0; i < interfaces_count; i++) {
-                interfaces[i] = readClass(index);
-                index += 2;
-            }
-        } finally {
-            in.close();
+      buffer(6);
+      readUnsignedShort(4); // minorVersion
+      readUnsignedShort(6); // majorVersion
+      // TODO: check version
+      int constantPoolCount = readUnsignedShort(8);
+      items = (int[]) resizeArray(items, constantPoolCount);
+
+      int index = 10;
+      for (int i = 1; i < constantPoolCount; i++) {
+        int size;
+        buffer(index + 3); // TODO: reduce calls to buffer
+        int tag = b[index];
+        items[i] = index + 1;
+        switch (tag) {
+          case 9: // Fieldref
+          case 10: // Methodref
+          case 11: // InterfaceMethodref
+          case 3: // Integer
+          case 4: // Float
+          case 12: // NameAndType
+            size = 4;
+            break;
+          case 5: // Long
+          case 6: // Double
+            size = 8;
+            i++;
+            break;
+          case 1: // Utf8
+            size = 2 + readUnsignedShort(index + 1);
+            break;
+          case 7: // Class
+          case 8: // String
+            size = 2;
+            break;
+          default:
+            throw new IllegalStateException("Unknown constant pool tag " + tag);
         }
+        index += size + 1;
+      }
+      buffer(index + 8);
+      access = readUnsignedShort(index);
+      thisClass = readClass(index + 2);
+      superClass = readClass(index + 4);
+      int interfacesCount = readUnsignedShort(index + 6);
+
+      index += 8;
+      buffer(index + interfacesCount * 2);
+      interfaces = new String[interfacesCount];
+      for (int i = 0; i < interfacesCount; i++) {
+        interfaces[i] = readClass(index);
+        index += 2;
+      }
+    } finally {
+      in.close();
+    }
+  }
+
+  private static int read(InputStream in, byte[] b, int off, int len) throws IOException {
+    int total = 0;
+    while (total < len) {
+      int result = in.read(b, off + total, len - total);
+      if (result == -1) {
+        break;
+      }
+      total += result;
+    }
+    return total;
+  }
+
+  private String readClass(int index) throws IOException {
+    index = readUnsignedShort(index);
+    if (index == 0) {
+      return null;
+    }
+    index = readUnsignedShort(items[index]);
+    bin.readFrom(b, items[index]);
+    return data.readUTF();
+  }
+
+  private int readUnsignedShort(int index) {
+    byte[] b = this.b;
+    return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
+  }
+
+  private static final int CHUNK = 2048;
+
+  private void buffer(int amount) throws IOException {
+    if (amount > b.length) {
+      b = (byte[]) resizeArray(b, b.length * 2);
+    }
+    if (amount > bsize) {
+      int rounded = (int) (CHUNK * Math.ceil((float) amount / CHUNK));
+      bsize += read(in, b, bsize, rounded - bsize);
+      if (amount > bsize) {
+        throw new EOFException();
+      }
+    }
+  }
+
+  private static Object resizeArray(Object array, int length) {
+    if (Array.getLength(array) < length) {
+      Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
+      System.arraycopy(array, 0, newArray, 0, Array.getLength(array));
+      return newArray;
+    } else {
+      return array;
+    }
+  }
+
+  private static class MyByteArrayInputStream extends ByteArrayInputStream {
+    public MyByteArrayInputStream() {
+      super(new byte[0]);
     }
 
-    private String readClass(int index) throws IOException {
-        index = readUnsignedShort(index);
-        if (index == 0)
-            return null;
-        index = readUnsignedShort(items[index]);
-        bin.readFrom(b, items[index]);
-        return data.readUTF();
+    public void readFrom(byte[] buf, int pos) {
+      this.buf = buf;
+      this.pos = pos;
+      count = buf.length;
     }
-
-    private int readUnsignedShort(int index) {
-        byte[] b = this.b;
-        return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
-    }
-
-    private static final int CHUNK = 2048;
-    private void buffer(int amount) throws IOException {
-        if (amount > b.length)
-            b = (byte[])resizeArray(b, b.length * 2);
-        if (amount > bsize) {
-            int rounded = (int)(CHUNK * Math.ceil((float)amount / CHUNK));
-            bsize += read(in, b, bsize, rounded - bsize);
-            if (amount > bsize)
-                throw new EOFException();
-        }
-    }
-
-    private static int read(InputStream in, byte[] b, int off, int len) throws IOException {
-        int total = 0;
-        while (total < len) {
-            int result = in.read(b, off + total, len - total);
-            if (result == -1)
-                break;
-            total += result;
-        }
-        return total;
-    }
-
-    private static Object resizeArray(Object array, int length)
-    {
-        if (Array.getLength(array) < length) {
-            Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
-            System.arraycopy(array, 0, newArray, 0, Array.getLength(array));
-            return newArray;
-        } else {
-            return array;
-        }
-    }
-
-    private static class MyByteArrayInputStream extends ByteArrayInputStream
-    {
-        public MyByteArrayInputStream() {
-            super(new byte[0]);
-        }
-
-        public void readFrom(byte[] buf, int pos) {
-            this.buf = buf;
-            this.pos = pos;
-            count = buf.length;
-        }
-    }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java b/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java
index d8de708..e90fd8c 100644
--- a/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java
+++ b/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,13 @@
 
 package com.tonicsystems.jarjar.util;
 
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 public interface ClassPathEntry {
   String getSource() throws IOException;
+
   String getName();
+
   InputStream openStream() throws IOException;
-}
\ No newline at end of file
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java b/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java
index f4f54f0..6c166a2 100644
--- a/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java
+++ b/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,219 +16,256 @@
 
 package com.tonicsystems.jarjar.util;
 
-import java.util.*;
-import java.util.zip.*;
-import java.io.*;
-import java.util.jar.*;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
-public class ClassPathIterator implements Iterator<ClassPathEntry>
-{
-    private static final FileFilter CLASS_FILTER = new FileFilter() {
+public class ClassPathIterator implements Iterator<ClassPathEntry> {
+  private static final FileFilter CLASS_FILTER =
+      new FileFilter() {
+        @Override
         public boolean accept(File file) {
-            return file.isDirectory() || isClass(file.getName());
+          return file.isDirectory() || isClass(file.getName());
         }
-    };
+      };
 
-    private static final FileFilter JAR_FILTER = new FileFilter() {
+  private static final FileFilter JAR_FILTER =
+      new FileFilter() {
+        @Override
         public boolean accept(File file) {
-            return hasExtension(file.getName(), ".jar");
+          return hasExtension(file.getName(), ".jar");
         }
-    };
-    
-    private final Iterator<File> files;
-    private Iterator<ClassPathEntry> entries = Collections.<ClassPathEntry>emptyList().iterator();
-    private ClassPathEntry next;
-    private List<ZipFile> zips = new ArrayList<ZipFile>();
+      };
 
-    public ClassPathIterator(String classPath) throws IOException {
-        this(new File(System.getProperty("user.dir")), classPath, null);
+  private final Iterator<File> files;
+  private Iterator<ClassPathEntry> entries = Collections.emptyIterator();
+  private ClassPathEntry next;
+  private final List<ZipFile> zips = new ArrayList<>();
+
+  public ClassPathIterator(String classPath) throws IOException {
+    this(new File(System.getProperty("user.dir")), classPath, null);
+  }
+
+  public ClassPathIterator(File parent, String classPath, String delim) throws IOException {
+    if (delim == null) {
+      delim = System.getProperty("path.separator");
     }
-    
-    public ClassPathIterator(File parent, String classPath, String delim) throws IOException {
-        if (delim == null) {
-            delim = System.getProperty("path.separator");
+    StringTokenizer st = new StringTokenizer(classPath, delim);
+    List<File> fileList = new ArrayList<>();
+    while (st.hasMoreTokens()) {
+      String part = (String) st.nextElement();
+      boolean wildcard = false;
+      if (part.endsWith("/*")) {
+        part = part.substring(0, part.length() - 1);
+        if (part.indexOf('*') >= 0) {
+          throw new IllegalArgumentException("Multiple wildcards are not allowed: " + part);
         }
-        StringTokenizer st = new StringTokenizer(classPath, delim);
-        List<File> fileList = new ArrayList<File>();
-        while (st.hasMoreTokens()) {
-            String part = (String)st.nextElement();
-            boolean wildcard = false;
-            if (part.endsWith("/*")) {
-                part = part.substring(0, part.length() - 1);
-                if (part.indexOf('*') >= 0)
-                    throw new IllegalArgumentException("Multiple wildcards are not allowed: " + part);
-                wildcard = true;
-            } else if (part.indexOf('*') >= 0) {
-                throw new IllegalArgumentException("Incorrect wildcard usage: " + part);
-            }
-                
-            File file = new File(part);
-            if (!file.isAbsolute())
-                file = new File(parent, part);
-            if (!file.exists())
-                throw new IllegalArgumentException("File " + file + " does not exist");
+        wildcard = true;
+      } else if (part.indexOf('*') >= 0) {
+        throw new IllegalArgumentException("Incorrect wildcard usage: " + part);
+      }
 
-            if (wildcard) {
-                if (!file.isDirectory())
-                    throw new IllegalArgumentException("File " + file + " + is not a directory");
-                fileList.addAll(findFiles(file, JAR_FILTER, false, new ArrayList<File>()));
-            } else {
-                fileList.add(file);
-            }
+      File file = new File(part);
+      if (!file.isAbsolute()) {
+        file = new File(parent, part);
+      }
+      if (!file.exists()) {
+        throw new IllegalArgumentException("File " + file + " does not exist");
+      }
+
+      if (wildcard) {
+        if (!file.isDirectory()) {
+          throw new IllegalArgumentException("File " + file + " + is not a directory");
         }
-        this.files = fileList.iterator();
-        advance();
+        fileList.addAll(findFiles(file, JAR_FILTER, false, new ArrayList<File>()));
+      } else {
+        fileList.add(file);
+      }
+    }
+    this.files = fileList.iterator();
+    advance();
+  }
+
+  @Override
+  public boolean hasNext() {
+    return next != null;
+  }
+
+  /** Closes all zip files opened by this iterator. */
+  public void close() throws IOException {
+    next = null;
+    for (ZipFile zip : zips) {
+      zip.close();
+    }
+  }
+
+  @Override
+  public void remove() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public ClassPathEntry next() {
+    if (!hasNext()) {
+      throw new NoSuchElementException();
+    }
+    ClassPathEntry result = next;
+    try {
+      advance();
+    } catch (IOException e) {
+      throw new RuntimeIOException(e);
+    }
+    return result;
+  }
+
+  private void advance() throws IOException {
+    if (!entries.hasNext()) {
+      if (!files.hasNext()) {
+        next = null;
+        return;
+      }
+      File file = files.next();
+      if (hasExtension(file.getName(), ".jar")) {
+        ZipFile zip = new JarFile(file);
+        zips.add(zip);
+        entries = new ZipIterator(zip);
+      } else if (hasExtension(file.getName(), ".zip")) {
+        ZipFile zip = new ZipFile(file);
+        zips.add(zip);
+        entries = new ZipIterator(zip);
+      } else if (file.isDirectory()) {
+        entries = new FileIterator(file);
+      } else {
+        throw new IllegalArgumentException("Do not know how to handle " + file);
+      }
     }
 
+    boolean foundClass = false;
+    while (!foundClass && entries.hasNext()) {
+      next = entries.next();
+      foundClass = isClass(next.getName());
+    }
+    if (!foundClass) {
+      advance();
+    }
+  }
+
+  private static class ZipIterator implements Iterator<ClassPathEntry> {
+    private final ZipFile zip;
+    private final Enumeration<? extends ZipEntry> entries;
+
+    ZipIterator(ZipFile zip) {
+      this.zip = zip;
+      this.entries = zip.entries();
+    }
+
+    @Override
     public boolean hasNext() {
-        return next != null;
+      return entries.hasMoreElements();
     }
 
-    /** Closes all zip files opened by this iterator. */
-    public void close() throws IOException {
-      next = null;
-      for (ZipFile zip : zips) {
-        zip.close();
-      }
-    }
-
+    @Override
     public void remove() {
-        throw new UnsupportedOperationException();
+      throw new UnsupportedOperationException();
     }
 
+    @Override
     public ClassPathEntry next() {
-        if (!hasNext())
-            throw new NoSuchElementException();
-        ClassPathEntry result = next;
-        try {
-            advance();
-        } catch (IOException e) {
-            throw new RuntimeIOException(e);
-        }
-        return result;
-    }
-
-    private void advance() throws IOException {
-        if (!entries.hasNext()) {
-            if (!files.hasNext()) {
-                next = null;
-                return;
-            }
-            File file = files.next();
-            if (hasExtension(file.getName(), ".jar")) {
-                ZipFile zip = new JarFile(file);
-                zips.add(zip);
-                entries = new ZipIterator(zip);
-            } else if (hasExtension(file.getName(), ".zip")) {
-                ZipFile zip = new ZipFile(file);
-                zips.add(zip);
-                entries = new ZipIterator(zip);
-            } else if (file.isDirectory()) {
-                entries = new FileIterator(file);
-            } else {
-                throw new IllegalArgumentException("Do not know how to handle " + file);
-            }
+      final ZipEntry entry = entries.nextElement();
+      return new ClassPathEntry() {
+        @Override
+        public String getSource() {
+          return zip.getName();
         }
 
-        boolean foundClass = false;
-        while (!foundClass && entries.hasNext()) {
-          next = entries.next();
-          foundClass = isClass(next.getName());
+        @Override
+        public String getName() {
+          return entry.getName();
         }
-        if (!foundClass) {
-          advance();
+
+        @Override
+        public InputStream openStream() throws IOException {
+          return zip.getInputStream(entry);
         }
+      };
+    }
+  }
+
+  private static class FileIterator implements Iterator<ClassPathEntry> {
+    private final File dir;
+    private final Iterator<File> entries;
+
+    FileIterator(File dir) {
+      this.dir = dir;
+      this.entries = findFiles(dir, CLASS_FILTER, true, new ArrayList<File>()).iterator();
     }
 
-    private static class ZipIterator implements Iterator<ClassPathEntry> {
-      private final ZipFile zip;
-      private final Enumeration<? extends ZipEntry> entries;
-
-      ZipIterator(ZipFile zip) {
-        this.zip = zip;
-        this.entries = zip.entries();
-      }
-
-      public boolean hasNext() {
-        return entries.hasMoreElements();
-      }
-
-      public void remove() {
-        throw new UnsupportedOperationException();
-      }
-
-      public ClassPathEntry next() {
-        final ZipEntry entry = entries.nextElement();
-        return new ClassPathEntry() {
-          public String getSource() {
-            return zip.getName();
-          }
-
-          public String getName() {
-            return entry.getName();
-          }
-
-          public InputStream openStream() throws IOException {
-            return zip.getInputStream(entry);
-          }
-        };
-      }
+    @Override
+    public boolean hasNext() {
+      return entries.hasNext();
     }
 
-    private static class FileIterator implements Iterator<ClassPathEntry> {
-      private final File dir;
-      private final Iterator<File> entries;
-
-      FileIterator(File dir) {
-        this.dir = dir;
-        this.entries = findFiles(dir, CLASS_FILTER, true, new ArrayList<File>()).iterator();
-      }
-
-      public boolean hasNext() {
-        return entries.hasNext();
-      }
-
-      public void remove() {
-        throw new UnsupportedOperationException();
-      }
-      
-      public ClassPathEntry next() {
-        final File file = entries.next();
-        return new ClassPathEntry() {
-          public String getSource() throws IOException {
-            return dir.getCanonicalPath();
-          }
-
-          public String getName() {
-            return file.getName();
-          }
-
-          public InputStream openStream() throws IOException {
-            return new BufferedInputStream(new FileInputStream(file));
-          }
-        };
-      }
+    @Override
+    public void remove() {
+      throw new UnsupportedOperationException();
     }
 
-    private static List<File> findFiles(File dir, FileFilter filter, boolean recurse, List<File> collect) {
-        for (File file : dir.listFiles(filter)) {
-            if (recurse && file.isDirectory()) {
-                findFiles(file, filter, recurse, collect);
-            } else {
-                collect.add(file);
-            }
+    @Override
+    public ClassPathEntry next() {
+      final File file = entries.next();
+      return new ClassPathEntry() {
+        @Override
+        public String getSource() throws IOException {
+          return dir.getCanonicalPath();
         }
-        return collect;
-    }
 
-    private static boolean isClass(String name) {
-        return hasExtension(name, ".class");
-    }
+        @Override
+        public String getName() {
+          return file.getName();
+        }
 
-    private static boolean hasExtension(String name, String ext) {
-        if (name.length() <  ext.length())
-            return false;
-        String actual = name.substring(name.length() - ext.length());
-        return actual.equals(ext) || actual.equals(ext.toUpperCase());
+        @Override
+        public InputStream openStream() throws IOException {
+          return new BufferedInputStream(new FileInputStream(file));
+        }
+      };
     }
+  }
+
+  private static List<File> findFiles(
+      File dir, FileFilter filter, boolean recurse, List<File> collect) {
+    for (File file : dir.listFiles(filter)) {
+      if (recurse && file.isDirectory()) {
+        findFiles(file, filter, recurse, collect);
+      } else {
+        collect.add(file);
+      }
+    }
+    return collect;
+  }
+
+  private static boolean isClass(String name) {
+    return hasExtension(name, ".class");
+  }
+
+  private static boolean hasExtension(String name, String ext) {
+    if (name.length() < ext.length()) {
+      return false;
+    }
+    String actual = name.substring(name.length() - ext.length());
+    return actual.equals(ext) || actual.equals(ext.toUpperCase());
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/EntryStruct.java b/src/main/com/tonicsystems/jarjar/util/EntryStruct.java
index 93f7622..9478ac8 100644
--- a/src/main/com/tonicsystems/jarjar/util/EntryStruct.java
+++ b/src/main/com/tonicsystems/jarjar/util/EntryStruct.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,20 @@
 
 package com.tonicsystems.jarjar.util;
 
-import java.io.InputStream;
-import java.io.File;
+public class EntryStruct {
+  public byte[] data;
+  public String name;
+  public long time;
 
-public class EntryStruct
-{
-    public byte[] data;
-    public String name;
-    public long time;
+  /** Returns true if the entry is a class file. */
+  public boolean isClass() {
+    if (!name.endsWith(".class")) {
+      return false;
+    }
+    if (name.startsWith("META-INF/version")) {
+      // TODO(b/69678527): handle multi-release jar files
+      return false;
+    }
+    return true;
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java b/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java
index cd2cc9b..b2a8bb4 100644
--- a/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java
+++ b/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,34 @@
 
 package com.tonicsystems.jarjar.util;
 
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.Opcodes;
 
-public class GetNameClassWriter extends ClassVisitor
-{
-    private String className;
-    
-    public GetNameClassWriter(int flags) {
-        super(Opcodes.ASM9,new ClassWriter(flags));
-    }
+public class GetNameClassWriter extends ClassVisitor {
+  private String className;
 
-    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
-        className = name;
-        super.visit(version, access, name, signature, superName, interfaces);
-    }
-    
-    public String getClassName() {
-        return className;
-    }
-    
-    public byte[] toByteArray() {
-        return ((ClassWriter) cv).toByteArray();
-    }
+  public GetNameClassWriter(int flags) {
+    super(Opcodes.ASM9, new ClassWriter(flags));
+  }
+
+  @Override
+  public void visit(
+      int version,
+      int access,
+      String name,
+      String signature,
+      String superName,
+      String[] interfaces) {
+    className = name;
+    super.visit(version, access, name, signature, superName, interfaces);
+  }
+
+  public String getClassName() {
+    return className;
+  }
+
+  public byte[] toByteArray() {
+    return ((ClassWriter) cv).toByteArray();
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/IoUtil.java b/src/main/com/tonicsystems/jarjar/util/IoUtil.java
index aef7ade..e26b485 100644
--- a/src/main/com/tonicsystems/jarjar/util/IoUtil.java
+++ b/src/main/com/tonicsystems/jarjar/util/IoUtil.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2008 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,13 @@
 
 package com.tonicsystems.jarjar.util;
 
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -26,106 +32,88 @@
 import java.util.zip.ZipOutputStream;
 
 class IoUtil {
-    private IoUtil() {}
+  private IoUtil() {}
 
-    public static void pipe(InputStream is, OutputStream out, byte[] buf) throws IOException {
-        for (;;) {
-            int amt = is.read(buf);
-            if (amt < 0)
-                break;
-            out.write(buf, 0, amt);
-        }
+  public static void pipe(InputStream is, OutputStream out, byte[] buf) throws IOException {
+    for (; ; ) {
+      int amt = is.read(buf);
+      if (amt < 0) {
+        break;
+      }
+      out.write(buf, 0, amt);
     }
+  }
 
-    public static void copy(File from, File to, byte[] buf) throws IOException {
-        InputStream in = new FileInputStream(from);
-        try {
-            OutputStream out = new FileOutputStream(to);
-            try {
-                pipe(in, out, buf);
-            } finally {
-                out.close();
-            }
-        } finally {
-            in.close();
-        }
+  public static void copy(File from, File to, byte[] buf) throws IOException {
+    try (InputStream in = new FileInputStream(from);
+        OutputStream out = new FileOutputStream(to)) {
+      pipe(in, out, buf);
     }
+  }
 
-    /**
-     * Create a copy of an zip file without its empty directories.
-     * @param inputFile
-     * @param outputFile
-     * @throws IOException
-     */
-    public static void copyZipWithoutEmptyDirectories(final File inputFile, final File outputFile) throws IOException
-    {
-        final byte[] buf = new byte[0x2000];
+  /**
+   * Create a copy of an zip file without its empty directories.
+   *
+   * @param inputFile the input file
+   * @param outputFile the output file
+   * @throws IOException
+   */
+  public static void copyZipWithoutEmptyDirectories(final File inputFile, final File outputFile)
+      throws IOException {
+    final byte[] buf = new byte[0x2000];
 
-        final ZipFile inputZip = new ZipFile(inputFile);
-        final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile));
-        try
-        {
-            // read a the entries of the input zip file and sort them
-            final Enumeration<? extends ZipEntry> e = inputZip.entries();
-            final ArrayList<ZipEntry> sortedList = new ArrayList<ZipEntry>();
-            while (e.hasMoreElements()) {
-                final ZipEntry entry = e.nextElement();
-                sortedList.add(entry);
+    final ZipFile inputZip = new ZipFile(inputFile);
+    final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile));
+    try {
+      // read a the entries of the input zip file and sort them
+      final Enumeration<? extends ZipEntry> e = inputZip.entries();
+      final ArrayList<ZipEntry> sortedList = new ArrayList<>();
+      while (e.hasMoreElements()) {
+        final ZipEntry entry = e.nextElement();
+        sortedList.add(entry);
+      }
+
+      Collections.sort(
+          sortedList,
+          new Comparator<ZipEntry>() {
+            @Override
+            public int compare(ZipEntry o1, ZipEntry o2) {
+              return o1.getName().compareTo(o2.getName());
             }
+          });
 
-            Collections.sort(sortedList, new Comparator<ZipEntry>()
-            {
-                public int compare(ZipEntry o1, ZipEntry o2)
-                {
-                    return o1.getName().compareTo(o2.getName());
-                }
-            });
-
-            // treat them again and write them in output, wenn they not are empty directories
-            for (int i = sortedList.size()-1; i>=0; i--)
-            {
-                final ZipEntry inputEntry = sortedList.get(i);
-                final String name = inputEntry.getName();
-                final boolean isEmptyDirectory;
-                if (inputEntry.isDirectory())
-                {
-                    if (i == sortedList.size()-1)
-                    {
-                        // no item afterwards; it was an empty directory
-                        isEmptyDirectory = true;
-                    }
-                    else
-                    {
-                        final String nextName = sortedList.get(i+1).getName();
-                        isEmptyDirectory  = !nextName.startsWith(name);
-                    }
-                }
-                else
-                {
-                    isEmptyDirectory = false;
-                }
-
-
-                // write the entry
-                if (isEmptyDirectory)
-                {
-                    sortedList.remove(inputEntry);
-                }
-                else
-                {
-                    final ZipEntry outputEntry = new ZipEntry(inputEntry);
-                    outputStream.putNextEntry(outputEntry);
-                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                    final InputStream is = inputZip.getInputStream(inputEntry);
-                    IoUtil.pipe(is, baos, buf);
-                    is.close();
-                    outputStream.write(baos.toByteArray());
-                }
-            }
-        } finally {
-            outputStream.close();
+      // treat them again and write them in output, wenn they not are empty directories
+      for (int i = sortedList.size() - 1; i >= 0; i--) {
+        final ZipEntry inputEntry = sortedList.get(i);
+        final String name = inputEntry.getName();
+        final boolean isEmptyDirectory;
+        if (inputEntry.isDirectory()) {
+          if (i == sortedList.size() - 1) {
+            // no item afterwards; it was an empty directory
+            isEmptyDirectory = true;
+          } else {
+            final String nextName = sortedList.get(i + 1).getName();
+            isEmptyDirectory = !nextName.startsWith(name);
+          }
+        } else {
+          isEmptyDirectory = false;
         }
 
+        // write the entry
+        if (isEmptyDirectory) {
+          sortedList.remove(inputEntry);
+        } else {
+          final ZipEntry outputEntry = new ZipEntry(inputEntry);
+          outputStream.putNextEntry(outputEntry);
+          ByteArrayOutputStream baos = new ByteArrayOutputStream();
+          try (final InputStream is = inputZip.getInputStream(inputEntry)) {
+            IoUtil.pipe(is, baos, buf);
+          }
+          baos.writeTo(outputStream);
+        }
+      }
+    } finally {
+      outputStream.close();
     }
-
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/JarProcessor.java b/src/main/com/tonicsystems/jarjar/util/JarProcessor.java
index 1560696..9e41fb6 100644
--- a/src/main/com/tonicsystems/jarjar/util/JarProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/util/JarProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,18 +18,16 @@
 
 import java.io.IOException;
 
-public interface JarProcessor
-{
-    /**
-     * Process the entry (p.ex. rename the file)
-     * <p>
-     * Returns <code>true</code> if the processor has has changed the entry. In this case, the entry can be removed
-     * from the jar file in a future time. Return <code>false</code> for the entries which do not have been changed and
-     * there fore are not to be deleted
-     *
-     * @param struct
-     * @return <code>true</code> if he process chain can continue after this process
-     * @throws IOException
-     */
-    boolean process(EntryStruct struct) throws IOException;
+public interface JarProcessor {
+  /**
+   * Process the entry (p.ex. rename the file)
+   *
+   * <p>Returns <code>true</code> if the processor has has changed the entry. In this case, the
+   * entry can be removed from the jar file in a future time. Return <code>false</code> for the
+   * entries which do not have been changed and there fore are not to be deleted
+   *
+   * @param struct the struct
+   * @return <code>true</code> if he process chain can continue after this process
+   */
+  boolean process(EntryStruct struct) throws IOException;
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java b/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java
index 06ac85d..6360a3f 100644
--- a/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java
+++ b/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,31 +18,25 @@
 
 import java.io.IOException;
 
-public class JarProcessorChain implements JarProcessor
-{
-    private final JarProcessor[] chain;
+public class JarProcessorChain implements JarProcessor {
+  private final JarProcessor[] chain;
 
-    public JarProcessorChain(JarProcessor[] chain)
-    {
-        this.chain = chain.clone();
+  public JarProcessorChain(JarProcessor[] chain) {
+    this.chain = chain.clone();
+  }
+
+  /**
+   * @param struct
+   * @return <code>true</code> if the entry has run the complete chain
+   * @throws IOException
+   */
+  public boolean process(EntryStruct struct) throws IOException {
+
+    for (JarProcessor aChain : chain) {
+      if (!aChain.process(struct)) {
+        return false;
+      }
     }
-
-    /**
-     * @param struct
-     * @return <code>true</code> if the entry has run the complete chain
-     * @throws IOException
-     */
-    public boolean process(EntryStruct struct) throws IOException
-    {
-
-        for (JarProcessor aChain : chain)
-        {
-            if (!aChain.process(struct))
-            {
-                return false;
-            }
-        }
-        return true;
-    }
+    return true;
+  }
 }
-  
diff --git a/src/main/com/tonicsystems/jarjar/util/JarTransformer.java b/src/main/com/tonicsystems/jarjar/util/JarTransformer.java
index d22f7bd..aced2ad 100644
--- a/src/main/com/tonicsystems/jarjar/util/JarTransformer.java
+++ b/src/main/com/tonicsystems/jarjar/util/JarTransformer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,35 +16,42 @@
 
 package com.tonicsystems.jarjar.util;
 
-import java.io.*;
+import java.io.IOException;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 
-abstract public class JarTransformer implements JarProcessor
-{
-    public boolean process(EntryStruct struct) throws IOException {
-        // Android-changed: exclude META-INF files, so they don't get moved into the root.
-        if (struct.name.endsWith(".class") && !struct.name.startsWith("META-INF")) {
-            ClassReader reader;
-            try {
-                reader = new ClassReader(struct.data);
-            } catch (Exception e) {
-                // Android-changed: Made this failure fatal to highlight class version issues.
-                // http://b/27637680
-                throw new RuntimeException("Failed to load " + struct.name, e);
-            }
-            GetNameClassWriter w = new GetNameClassWriter(ClassWriter.COMPUTE_MAXS);
-            reader.accept(transform(w), ClassReader.EXPAND_FRAMES);
-            struct.data = w.toByteArray();
-            struct.name = pathFromName(w.getClassName());
-        }
-        return true;
-    }
+public abstract class JarTransformer implements JarProcessor {
+  @Override
+  public boolean process(EntryStruct struct) throws IOException {
+    if (struct.isClass() && !struct.name.startsWith("META-INF")) {
+      ClassReader reader;
+      try {
+        reader = new ClassReader(struct.data);
+      } catch (RuntimeException e) {
+        // Android-changed: Made this failure fatal to highlight class version issues.
+        // http://b/27637680
+        throw new RuntimeException("Failed to load " + struct.name, e);
+      }
+      GetNameClassWriter w = new GetNameClassWriter(ClassWriter.COMPUTE_MAXS);
+      ClassVisitor visitor = transform(w);
+      reader.accept(visitor, ClassReader.EXPAND_FRAMES);
 
-    abstract protected ClassVisitor transform(ClassVisitor v);
-
-    private static String pathFromName(String className) {
-        return className.replace('.', '/') + ".class";
+      boolean updateData = true;
+      if (visitor instanceof RemappingClassTransformer) {
+        updateData = ((RemappingClassTransformer) visitor).didRemap();
+      }
+      if (updateData) {
+        struct.data = w.toByteArray();
+        struct.name = pathFromName(w.getClassName());
+      }
     }
+    return true;
+  }
+
+  protected abstract ClassVisitor transform(ClassVisitor v);
+
+  private static String pathFromName(String className) {
+    return className.replace('.', '/') + ".class";
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java b/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java
index be16d9b..056422a 100644
--- a/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java
+++ b/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,19 +18,19 @@
 
 import org.objectweb.asm.ClassVisitor;
 
-public class JarTransformerChain extends JarTransformer
-{
-    private final RemappingClassTransformer[] chain;
-    
-    public JarTransformerChain(RemappingClassTransformer[] chain) {
-        this.chain = chain.clone();
-        for (int i = chain.length - 1; i > 0; i--) {
-            chain[i - 1].setTarget(chain[i]);
-        }
-    }
+public class JarTransformerChain extends JarTransformer {
+  private final RemappingClassTransformer[] chain;
 
-    protected ClassVisitor transform(ClassVisitor v) {
-        chain[chain.length - 1].setTarget(v);
-        return chain[0];
+  public JarTransformerChain(RemappingClassTransformer[] chain) {
+    this.chain = chain.clone();
+    for (int i = chain.length - 1; i > 0; i--) {
+      chain[i - 1].setTarget(chain[i]);
     }
+  }
+
+  @Override
+  protected ClassVisitor transform(ClassVisitor v) {
+    chain[chain.length - 1].setTarget(v);
+    return chain[0];
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java b/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java
index 9c1d4c9..0579f71 100644
--- a/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java
+++ b/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,105 @@
 
 package com.tonicsystems.jarjar.util;
 
+import com.tonicsystems.jarjar.EmptyClassVisitor;
+import java.util.Objects;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.commons.ClassRemapper;
 import org.objectweb.asm.commons.Remapper;
 
-import com.tonicsystems.jarjar.EmptyClassVisitor;
+public class RemappingClassTransformer extends ClassRemapper {
+  public RemappingClassTransformer(Remapper pr) {
+    super(new EmptyClassVisitor(), new RemapperTracker(pr));
+  }
 
-public class RemappingClassTransformer extends ClassRemapper
-{
-    public RemappingClassTransformer(Remapper pr) {
-        super(new EmptyClassVisitor(), pr);
+  public void setTarget(ClassVisitor target) {
+    ((RemapperTracker) remapper).didRemap = false;
+    cv = target;
+  }
+
+  public boolean didRemap() {
+    return ((RemapperTracker) remapper).didRemap;
+  }
+
+  public static class RemapperTracker extends Remapper {
+
+    private final Remapper delegate;
+    public boolean didRemap;
+
+    RemapperTracker(Remapper delegate) {
+      this.delegate = delegate;
+      this.didRemap = false;
     }
-        
-    public void setTarget(ClassVisitor target) {
-        cv = target;
+
+    @Override
+    public String mapDesc(String desc) {
+      String output = delegate.mapDesc(desc);
+      didRemap = didRemap || !Objects.equals(output, desc);
+      return output;
     }
+
+    @Override
+    public String mapType(String type) {
+      String output = delegate.mapType(type);
+      didRemap = didRemap || !Objects.equals(output, type);
+      return output;
+    }
+
+    @Override
+    public String[] mapTypes(String[] types) {
+      String[] localTypes = types.clone();
+      String[] output = delegate.mapTypes(types);
+      didRemap = didRemap || !Objects.deepEquals(output, localTypes);
+      return output;
+    }
+
+    @Override
+    public String mapMethodDesc(String desc) {
+      String output = delegate.mapMethodDesc(desc);
+      didRemap = didRemap || !Objects.equals(output, desc);
+      return output;
+    }
+
+    @Override
+    public Object mapValue(Object value) {
+      Object output = delegate.mapValue(value);
+      didRemap = didRemap || !Objects.equals(output, value);
+      return output;
+    }
+
+    @Override
+    public String mapSignature(String signature, boolean typeSignature) {
+      String output = delegate.mapSignature(signature, typeSignature);
+      didRemap = didRemap || !Objects.equals(output, signature);
+      return output;
+    }
+
+    @Override
+    public String mapMethodName(String owner, String name, String desc) {
+      String output = delegate.mapMethodName(owner, name, desc);
+      didRemap = didRemap || !Objects.equals(output, name);
+      return output;
+    }
+
+    @Override
+    public String mapInvokeDynamicMethodName(String name, String desc) {
+      String output = delegate.mapInvokeDynamicMethodName(name, desc);
+      didRemap = didRemap || !Objects.equals(output, name);
+      return output;
+    }
+
+    @Override
+    public String mapFieldName(String owner, String name, String desc) {
+      String output = delegate.mapFieldName(owner, name, desc);
+      didRemap = didRemap || !Objects.equals(output, name);
+      return output;
+    }
+
+    @Override
+    public String map(String typeName) {
+      String output = delegate.map(typeName);
+      didRemap = didRemap || !Objects.equals(output, typeName);
+      return output;
+    }
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java b/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java
index 9b5d4a8..0cf0a15 100644
--- a/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java
+++ b/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,11 +18,10 @@
 
 import java.io.IOException;
 
-public class RuntimeIOException extends RuntimeException
-{
-    private static final long serialVersionUID = 0L;
+public class RuntimeIOException extends RuntimeException {
+  private static final long serialVersionUID = 0L;
 
-    public RuntimeIOException(IOException e) {
-        super(e);
-    }
+  public RuntimeIOException(IOException e) {
+    super(e);
+  }
 }
diff --git a/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java b/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java
index 70b169b..b91b6f9 100644
--- a/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,56 +16,59 @@
 
 package com.tonicsystems.jarjar.util;
 
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.jar.JarOutputStream;
-import java.util.Enumeration;
-import java.io.*;
-import java.util.*;
 
-public class StandaloneJarProcessor
-{
-    public static void run(File from, File to, JarProcessor proc) throws IOException {
-        byte[] buf = new byte[0x2000];
+public final class StandaloneJarProcessor {
+  public static void run(File from, File to, JarProcessor proc) throws IOException {
+    byte[] buf = new byte[0x2000];
 
-        JarFile in = new JarFile(from);
-        final File tmpTo = File.createTempFile("jarjar", ".jar");
-        JarOutputStream out = new JarOutputStream(new FileOutputStream(tmpTo));
-        Set<String> entries = new HashSet<String>();
-        try {
-            EntryStruct struct = new EntryStruct();
-            Enumeration<JarEntry> e = in.entries();
-            while (e.hasMoreElements()) {
-                JarEntry entry = e.nextElement();
-                struct.name = entry.getName();
-                struct.time = entry.getTime();
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                IoUtil.pipe(in.getInputStream(entry), baos, buf);
-                struct.data = baos.toByteArray();
-                if (proc.process(struct)) {
-                    if (entries.add(struct.name)) {
-                        entry = new JarEntry(struct.name);
-                        entry.setTime(struct.time);
-                        entry.setCompressedSize(-1);
-                        out.putNextEntry(entry);
-                        out.write(struct.data);
-                    } else if (struct.name.endsWith("/")) {
-                        // TODO(chrisn): log
-                    } else {
-                        throw new IllegalArgumentException("Duplicate jar entries: " + struct.name);
-                    }
-                }
-            }
-
+    JarFile in = new JarFile(from);
+    final File tmpTo = File.createTempFile("jarjar", ".jar");
+    JarOutputStream out = new JarOutputStream(new FileOutputStream(tmpTo));
+    Set<String> entries = new HashSet<>();
+    try {
+      EntryStruct struct = new EntryStruct();
+      Enumeration<JarEntry> e = in.entries();
+      while (e.hasMoreElements()) {
+        JarEntry entry = e.nextElement();
+        struct.name = entry.getName();
+        struct.time = entry.getTime();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IoUtil.pipe(in.getInputStream(entry), baos, buf);
+        struct.data = baos.toByteArray();
+        if (proc.process(struct)) {
+          if (entries.add(struct.name)) {
+            entry = new JarEntry(struct.name);
+            entry.setTime(struct.time);
+            entry.setCompressedSize(-1);
+            out.putNextEntry(entry);
+            out.write(struct.data);
+          } else if (struct.name.endsWith("/")) {
+            // TODO(chrisn): log
+          } else {
+            throw new IllegalArgumentException("Duplicate jar entries: " + struct.name);
+          }
         }
-        finally {
-            in.close();
-            out.close();
-        }
+      }
 
-         // delete the empty directories
-        IoUtil.copyZipWithoutEmptyDirectories(tmpTo, to);
-        tmpTo.delete();
-
+    } finally {
+      in.close();
+      out.close();
     }
+
+    // delete the empty directories
+    IoUtil.copyZipWithoutEmptyDirectories(tmpTo, to);
+    tmpTo.delete();
+  }
+
+  private StandaloneJarProcessor() {}
 }
diff --git a/src/test/com/tonicsystems/jarjar/GenericsTest.java b/src/test/com/tonicsystems/jarjar/GenericsTest.java
index 1996a24..29e2c6e 100644
--- a/src/test/com/tonicsystems/jarjar/GenericsTest.java
+++ b/src/test/com/tonicsystems/jarjar/GenericsTest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,29 +16,30 @@
 
 package com.tonicsystems.jarjar;
 
-import com.tonicsystems.jarjar.util.*;
-import junit.framework.*;
-import java.util.*;
+import com.tonicsystems.jarjar.util.RemappingClassTransformer;
+import java.util.Arrays;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 import org.objectweb.asm.ClassReader;
 
-public class GenericsTest
-extends TestCase
-{
-    public void testTransform() throws Exception {
-         Rule rule = new Rule();
-         rule.setPattern("java.lang.String");
-         rule.setResult("com.tonicsystems.String");
-         RemappingClassTransformer t = new RemappingClassTransformer(new PackageRemapper(Arrays.asList(rule), false));
-         t.setTarget(new EmptyClassVisitor());
-         ClassReader reader = new ClassReader(getClass().getResourceAsStream("/Generics.class"));
-         reader.accept(t, 0);
-    }
+public class GenericsTest extends TestCase {
+  public void testTransform() throws Exception {
+    Rule rule = new Rule();
+    rule.setPattern("java.lang.String");
+    rule.setResult("com.tonicsystems.String");
+    RemappingClassTransformer t =
+        new RemappingClassTransformer(new PackageRemapper(Arrays.asList(rule), false));
+    t.setTarget(new EmptyClassVisitor());
+    ClassReader reader = new ClassReader(getClass().getResourceAsStream("/Generics.class"));
+    reader.accept(t, 0);
+  }
 
-    public GenericsTest(String name) {
-        super(name);
-    }
+  public GenericsTest(String name) {
+    super(name);
+  }
 
-    public static Test suite() {
-        return new TestSuite(GenericsTest.class);
-    }
+  public static Test suite() {
+    return new TestSuite(GenericsTest.class);
+  }
 }
diff --git a/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java b/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java
index aea9d46..a097931 100644
--- a/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java
+++ b/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,44 +16,42 @@
 
 package com.tonicsystems.jarjar;
 
-import junit.framework.*;
-
 import java.util.Collections;
+import junit.framework.TestCase;
 
-public class PackageRemapperTest
-extends TestCase
-{
-    protected PackageRemapper remapper;
+public class PackageRemapperTest extends TestCase {
+  protected PackageRemapper remapper;
 
-    protected void setUp() {
-        Rule rule = new Rule();
-        rule.setPattern("org.**");
-        rule.setResult("foo.@1");
-        remapper = new PackageRemapper(Collections.singletonList(rule), false);
-    }
+  @Override
+  protected void setUp() {
+    Rule rule = new Rule();
+    rule.setPattern("org.**");
+    rule.setResult("foo.@1");
+    remapper = new PackageRemapper(Collections.singletonList(rule), false);
+  }
 
-    public void testMapValue() {
-      assertUnchangedValue("[^\\s;/@&=,.?:+$]");
-      assertUnchangedValue("[Ljava/lang/Object;");
-      assertUnchangedValue("[Lorg/example/Object;");
-      assertUnchangedValue("[Ljava.lang.Object;");
-      assertUnchangedValue("[Lorg.example/Object;");
-      assertUnchangedValue("[L;");
-      assertUnchangedValue("[Lorg.example.Object;;");
-      assertUnchangedValue("[Lorg.example.Obj ct;");
-      assertUnchangedValue("org.example/Object");
+  public void testMapValue() {
+    assertUnchangedValue("[^\\s;/@&=,.?:+$]");
+    assertUnchangedValue("[Ljava/lang/Object;");
+    assertUnchangedValue("[Lorg/example/Object;");
+    assertUnchangedValue("[Ljava.lang.Object;");
+    assertUnchangedValue("[Lorg.example/Object;");
+    assertUnchangedValue("[L;");
+    assertUnchangedValue("[Lorg.example.Object;;");
+    assertUnchangedValue("[Lorg.example.Obj ct;");
+    assertUnchangedValue("org.example/Object");
 
-      assertEquals("[Lfoo.example.Object;", remapper.mapValue("[Lorg.example.Object;"));
-      assertEquals("foo.example.Object", remapper.mapValue("org.example.Object"));
-      assertEquals("foo/example/Object", remapper.mapValue("org/example/Object"));
-      assertEquals("foo/example.Object", remapper.mapValue("org/example.Object")); // path match
+    assertEquals("[Lfoo.example.Object;", remapper.mapValue("[Lorg.example.Object;"));
+    assertEquals("foo.example.Object", remapper.mapValue("org.example.Object"));
+    assertEquals("foo/example/Object", remapper.mapValue("org/example/Object"));
+    assertEquals("foo/example.Object", remapper.mapValue("org/example.Object")); // path match
 
-      assertEquals("foo.example.package-info", remapper.mapValue("org.example.package-info"));
-      assertEquals("foo/example/package-info", remapper.mapValue("org/example/package-info"));
-      assertEquals("foo/example.package-info", remapper.mapValue("org/example.package-info"));
-    }
+    assertEquals("foo.example.package-info", remapper.mapValue("org.example.package-info"));
+    assertEquals("foo/example/package-info", remapper.mapValue("org/example/package-info"));
+    assertEquals("foo/example.package-info", remapper.mapValue("org/example.package-info"));
+  }
 
-    private void assertUnchangedValue(String value) {
-        assertEquals(value, remapper.mapValue(value));
-    }
+  private void assertUnchangedValue(String value) {
+    assertEquals(value, remapper.mapValue(value));
+  }
 }
diff --git a/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java b/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java
index 4a4c371..5b3b9cd 100644
--- a/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java
+++ b/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,20 @@
 
 package com.tonicsystems.jarjar;
 
-import junit.framework.*;
-import java.io.*;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
-public class RulesFileParserTest
-extends TestCase
-{
-    public void testSimple() throws Exception {
-        // TODO
-    }
+public class RulesFileParserTest extends TestCase {
+  public void testSimple() throws Exception {
+    // TODO
+  }
 
-    public RulesFileParserTest(String name) {
-        super(name);
-    }
+  public RulesFileParserTest(String name) {
+    super(name);
+  }
 
-    public static Test suite() {
-        return new TestSuite(RulesFileParserTest.class);
-    }
+  public static Test suite() {
+    return new TestSuite(RulesFileParserTest.class);
+  }
 }
diff --git a/src/test/com/tonicsystems/jarjar/WildcardTest.java b/src/test/com/tonicsystems/jarjar/WildcardTest.java
index f41b2f5..d08d75c 100644
--- a/src/test/com/tonicsystems/jarjar/WildcardTest.java
+++ b/src/test/com/tonicsystems/jarjar/WildcardTest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright 2007 Google Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,35 +16,43 @@
 
 package com.tonicsystems.jarjar;
 
-import junit.framework.*;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
-public class WildcardTest
-extends TestCase
-{
-    public void testWildcards() {
-        wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/proxy/Mixin$Generator",
-            "foo/proxy/Mixin$Generator");
-        wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
-        wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar/Baz", "foo/Bar/Baz");
-        wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/", "foo/");
-        wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/!", null);
-        wildcard("net/sf/cglib/*", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
-        wildcard("net/sf/cglib/*/*", "foo/@2/@1", "net/sf/cglib/Bar/Baz", "foo/Baz/Bar");
-        wildcard("**/package-info", "bar/baz/@1/package-info", "foo/package-info", "bar/baz/foo/package-info");
-        wildcard("**/module-info", "bar/baz/@1/module-info", "foo/module-info", "bar/baz/foo/module-info");
-    }
+public class WildcardTest extends TestCase {
+  public void testWildcards() {
+    wildcard(
+        "net/sf/cglib/**",
+        "foo/@1",
+        "net/sf/cglib/proxy/Mixin$Generator",
+        "foo/proxy/Mixin$Generator");
+    wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
+    wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar/Baz", "foo/Bar/Baz");
+    wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/", "foo/");
+    wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/!", null);
+    wildcard("net/sf/cglib/*", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
+    wildcard("net/sf/cglib/*/*", "foo/@2/@1", "net/sf/cglib/Bar/Baz", "foo/Baz/Bar");
+    wildcard(
+        "**/package-info",
+        "bar/baz/@1/package-info",
+        "foo/package-info",
+        "bar/baz/foo/package-info");
+    wildcard(
+        "**/module-info", "bar/baz/@1/module-info", "foo/module-info", "bar/baz/foo/module-info");
+  }
 
-    private void wildcard(String pattern, String result, String value, String expect) {
-        Wildcard wc = new Wildcard(pattern, result, 0);
-        // System.err.println(wc);
-        assertEquals(expect, wc.replace(value));
-    }
-    
-    public WildcardTest(String name) {
-        super(name);
-    }
+  private void wildcard(String pattern, String result, String value, String expect) {
+    Wildcard wc = new Wildcard(pattern, result, 0);
+    // System.err.println(wc);
+    assertEquals(expect, wc.replace(value));
+  }
 
-    public static Test suite() {
-        return new TestSuite(WildcardTest.class);
-    }
+  public WildcardTest(String name) {
+    super(name);
+  }
+
+  public static Test suite() {
+    return new TestSuite(WildcardTest.class);
+  }
 }
diff --git a/src/test/com/tonicsystems/jarjar/example/Example.java b/src/test/com/tonicsystems/jarjar/example/Example.java
index 2129962..feedf09 100644
--- a/src/test/com/tonicsystems/jarjar/example/Example.java
+++ b/src/test/com/tonicsystems/jarjar/example/Example.java
@@ -1,5 +1,19 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.tonicsystems.jarjar.example;
 
-public class Example
-{
-}
+public class Example {}