Upgrade google-smali to 3.0.4

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/google-smali
For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I30f33256daf82dc2644921e569bbaa1d01d6458f
diff --git a/METADATA b/METADATA
index 293b194..2d0a8a9 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,19 @@
 # This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update google-smali
+# Usage: tools/external_updater/updater.sh update external/google-smali
 # For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
 
 name: "google-smali"
 description: "smali/baksmali is an assembler/disassembler for the dex format used by dalvik, Android\'s Java VM implementation."
 third_party {
-  url {
-    type: GIT
-    value: "https://github.com/google/smali"
-  }
-  version: "3.0.3"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 7
-    day: 24
+    year: 2024
+    month: 2
+    day: 7
+  }
+  identifier {
+    type: "Git"
+    value: "https://github.com/google/smali"
+    version: "3.0.4"
   }
 }
diff --git a/baksmali/build.gradle b/baksmali/build.gradle
index 7a44f93..1644c09 100644
--- a/baksmali/build.gradle
+++ b/baksmali/build.gradle
@@ -61,10 +61,13 @@
 
 // Build a separate jar that contains all dependencies
 task fatJar(type: Jar) {
+    dependsOn ':dexlib2:jar'
+    dependsOn ':util:jar'
     from sourceSets.main.output
     from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
 
-    classifier = 'fat'
+    duplicatesStrategy = 'exclude'
+    archiveClassifier = 'fat'
 
     manifest {
         attributes('Main-Class': 'com.android.tools.smali.baksmali.Main')
@@ -132,4 +135,4 @@
 
 tasks.getByPath('test').onlyIf({
     !gradle.taskGraph.hasTask(fastbuild)
-})
\ No newline at end of file
+})
diff --git a/baksmali/src/main/java/com/android/tools/smali/baksmali/DumpCommand.java b/baksmali/src/main/java/com/android/tools/smali/baksmali/DumpCommand.java
index ac653ed..a4fca66 100644
--- a/baksmali/src/main/java/com/android/tools/smali/baksmali/DumpCommand.java
+++ b/baksmali/src/main/java/com/android/tools/smali/baksmali/DumpCommand.java
@@ -94,9 +94,8 @@
      */
     public static void dump(@Nonnull DexBackedDexFile dexFile, @Nonnull OutputStream output)
             throws IOException {
-        Writer writer = new BufferedWriter(new OutputStreamWriter(output));
 
-        try {
+        try (Writer writer = new BufferedWriter(new OutputStreamWriter(output))) {
             int consoleWidth = ConsoleUtil.getConsoleWidth();
             if (consoleWidth <= 0) {
                 consoleWidth = 120;
@@ -104,8 +103,6 @@
 
             DexAnnotator annotator = new DexAnnotator(dexFile, consoleWidth);
             annotator.writeAnnotations(writer);
-        } finally {
-            writer.close();
         }
     }
 }
diff --git a/baksmali/src/test/java/com/android/tools/smali/baksmali/AnalysisTest.java b/baksmali/src/test/java/com/android/tools/smali/baksmali/AnalysisTest.java
index a144d46..d41e307 100644
--- a/baksmali/src/test/java/com/android/tools/smali/baksmali/AnalysisTest.java
+++ b/baksmali/src/test/java/com/android/tools/smali/baksmali/AnalysisTest.java
@@ -32,7 +32,6 @@
 
 import com.google.common.base.Charsets;
 import com.google.common.io.Resources;
-import junit.framework.Assert;
 import com.android.tools.smali.baksmali.Adaptors.ClassDefinition;
 import com.android.tools.smali.baksmali.formatter.BaksmaliWriter;
 import com.android.tools.smali.dexlib2.DexFileFactory;
@@ -41,6 +40,7 @@
 import com.android.tools.smali.dexlib2.analysis.ClassProvider;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.DexFile;
+import org.junit.Assert;
 import org.junit.Test;
 
 import javax.annotation.Nonnull;
diff --git a/baksmali/src/test/java/com/android/tools/smali/baksmali/BaksmaliTestUtils.java b/baksmali/src/test/java/com/android/tools/smali/baksmali/BaksmaliTestUtils.java
index 1796ea7..50b6360 100644
--- a/baksmali/src/test/java/com/android/tools/smali/baksmali/BaksmaliTestUtils.java
+++ b/baksmali/src/test/java/com/android/tools/smali/baksmali/BaksmaliTestUtils.java
@@ -31,18 +31,20 @@
 package com.android.tools.smali.baksmali;
 
 import com.google.common.io.ByteStreams;
-import junit.framework.Assert;
 import org.antlr.runtime.RecognitionException;
 import com.android.tools.smali.baksmali.Adaptors.ClassDefinition;
 import com.android.tools.smali.baksmali.formatter.BaksmaliWriter;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.smali.SmaliTestUtils;
+import org.junit.Assert;
 import org.junit.Test;
 
 import javax.annotation.Nonnull;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -109,11 +111,11 @@
 
     @Nonnull
     public static String readResourceFully(@Nonnull String fileName) throws IOException {
-        return readResourceFully(fileName, "UTF-8");
+        return readResourceFully(fileName, StandardCharsets.UTF_8);
     }
 
     @Nonnull
-    public static String readResourceFully(@Nonnull String fileName, @Nonnull String encoding)
+    public static String readResourceFully(@Nonnull String fileName, @Nonnull Charset encoding)
             throws IOException {
         return new String(readResourceBytesFully(fileName), encoding);
     }
diff --git a/build.gradle b/build.gradle
index c758163..ecc1f84 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,7 +30,7 @@
 
 apply plugin: 'idea'
 
-version = '3.0.3'
+version = '3.0.4'
 def jcommanderVersion = ''
 
 if (!('release' in gradle.startParameter.taskNames)) {
@@ -105,7 +105,7 @@
                 antlr: 'org.antlr:antlr:3.5.2',
                 stringtemplate: 'org.antlr:stringtemplate:3.2.1',
                 jflex_plugin: 'org.xbib.gradle.plugin:gradle-plugin-jflex:1.1.0',
-                proguard_gradle: 'net.sf.proguard:proguard-gradle:6.2.2',
+                proguard_gradle: 'com.guardsquare:proguard-gradle:7.1.0',
                 dx: 'com.google.android.tools:dx:1.7',
                 gson: 'com.google.code.gson:gson:2.3.1',
                 jcommander: jcommanderVersion
@@ -205,6 +205,6 @@
 }
 
 wrapper {
-    gradleVersion = '6.8.2'
+    gradleVersion = '8.5'
     distributionType = Wrapper.DistributionType.ALL
 }
diff --git a/dexlib2/accessorTestGenerator/src/main/java/com/android/tools/smali/dexlib2/AccessorTestGenerator.java b/dexlib2/accessorTestGenerator/src/main/java/com/android/tools/smali/dexlib2/AccessorTestGenerator.java
index f98583e..76baa6c 100644
--- a/dexlib2/accessorTestGenerator/src/main/java/com/android/tools/smali/dexlib2/AccessorTestGenerator.java
+++ b/dexlib2/accessorTestGenerator/src/main/java/com/android/tools/smali/dexlib2/AccessorTestGenerator.java
@@ -127,14 +127,8 @@
         ST fileSt = stg.getInstanceOf("file");
         fileSt.add("types", types);
 
-        PrintWriter w = null;
-        try {
-            w = new PrintWriter(new BufferedWriter(new FileWriter(args[0])));
+        try (PrintWriter w = new PrintWriter(new BufferedWriter(new FileWriter(args[0])))) {
             w.print(fileSt.render());
-        } finally {
-            if (w != null) {
-                w.close();
-            }
         }
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java
index f59b107..c464c47 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java
@@ -30,14 +30,12 @@
 
 package com.android.tools.smali.dexlib2;
 
+import static java.util.Collections.unmodifiableList;
+
 import com.android.tools.smali.dexlib2.iface.DexFile;
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer.DexEntry;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Files;
+
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile.NotADexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedOdexFile;
@@ -48,6 +46,8 @@
 import com.android.tools.smali.dexlib2.dexbacked.ZipDexContainer.NotAZipFileException;
 import com.android.tools.smali.dexlib2.writer.pool.DexPool;
 import com.android.tools.smali.util.ExceptionWithContext;
+import com.android.tools.smali.util.InputStreamUtil;
+import com.android.tools.smali.util.StringUtils;
 
 import java.io.BufferedInputStream;
 import java.io.File;
@@ -57,6 +57,8 @@
 import java.io.InputStream;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.ArrayList;
 import java.util.List;
 
 public final class DexFileFactory {
@@ -95,11 +97,10 @@
             // eat it and continue
         }
 
-        InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
-        try {
+        try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
             try {
                 return DexBackedDexFile.fromInputStream(opcodes, inputStream);
-            } catch (DexBackedDexFile.NotADexFile ex) {
+            } catch (NotADexFile ex) {
                 // just eat it
             }
 
@@ -132,8 +133,6 @@
 
                 return oatDexFiles.get(0);
             }
-        } finally {
-            inputStream.close();
         }
 
         throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath());
@@ -195,8 +194,7 @@
             // eat it and continue
         }
 
-        InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
-        try {
+        try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
             OatFile oatFile = null;
             try {
                 oatFile = OatFile.fromInputStream(inputStream, new FilenameVdexProvider(file));
@@ -217,8 +215,6 @@
 
                 return new DexEntryFinder(file.getPath(), oatFile).findEntry(dexEntry, exactMatch);
             }
-        } finally {
-            inputStream.close();
         }
 
         throw new UnsupportedFileTypeException("%s is not an apk or oat file.", file.getPath());
@@ -247,12 +243,11 @@
             return zipDexContainer;
         }
 
-        InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
-        try {
+        try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
             try {
                 DexBackedDexFile dexFile = DexBackedDexFile.fromInputStream(opcodes, inputStream);
                 return new SingletonMultiDexContainer(file.getPath(), dexFile);
-            } catch (DexBackedDexFile.NotADexFile ex) {
+            } catch (NotADexFile ex) {
                 // just eat it
             }
 
@@ -280,8 +275,6 @@
                 }
                 return oatFile;
             }
-        } finally {
-            inputStream.close();
         }
 
         throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath());
@@ -404,10 +397,10 @@
             }
 
             // find all full and partial matches
-            List<String> fullMatches = Lists.newArrayList();
-            List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> fullEntries = Lists.newArrayList();
-            List<String> partialMatches = Lists.newArrayList();
-            List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> partialEntries = Lists.newArrayList();
+            List<String> fullMatches = new ArrayList<>();
+            List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> fullEntries = new ArrayList<>();
+            List<String> partialMatches = new ArrayList<>();
+            List<MultiDexContainer.DexEntry<? extends DexBackedDexFile>> partialEntries = new ArrayList<>();
             for (String entry: dexContainer.getDexEntryNames()) {
                 if (fullEntryMatch(entry, targetEntry)) {
                     // We want to grab all full matches, regardless of whether they're actually a dex file.
@@ -439,7 +432,8 @@
                 // only by an initial path separator. e.g. "/blah/blah.dex" and "blah/blah.dex"
                 throw new MultipleMatchingDexEntriesException(String.format(
                         "Multiple entries in %s match %s: %s", filename, targetEntry,
-                        Joiner.on(", ").join(fullMatches)));
+                        StringUtils.join(fullMatches, ", ")
+                        ));
             }
 
             if (partialEntries.size() == 0) {
@@ -449,7 +443,8 @@
             if (partialEntries.size() > 1) {
                 throw new MultipleMatchingDexEntriesException(String.format(
                         "Multiple dex entries in %s match %s: %s", filename, targetEntry,
-                        Joiner.on(", ").join(partialMatches)));
+                        StringUtils.join(partialMatches, ", ")
+                        ));
             }
             return partialEntries.get(0);
         }
@@ -465,7 +460,7 @@
         }
 
         @Nonnull @Override public List<String> getDexEntryNames() {
-            return ImmutableList.of(entryName);
+            return unmodifiableList(List.of(entryName));
         }
 
         @Nullable @Override public DexEntry<DexBackedDexFile> getEntry(@Nonnull String entryName) {
@@ -503,7 +498,7 @@
 
         public FilenameVdexProvider(File oatFile) {
             File oatParent = oatFile.getAbsoluteFile().getParentFile();
-            String baseName = Files.getNameWithoutExtension(oatFile.getAbsolutePath());
+            String baseName = getNameWithoutExtension(oatFile.getAbsolutePath());
             vdexFile = new File(oatParent, baseName + ".vdex");
         }
 
@@ -524,7 +519,7 @@
 
                 if (candidateFile.exists()) {
                     try {
-                        buf = ByteStreams.toByteArray(new FileInputStream(candidateFile));
+                        buf = InputStreamUtil.toByteArray(new FileInputStream(candidateFile));
                     } catch (FileNotFoundException e) {
                         buf = null;
                     } catch (IOException ex) {
@@ -536,5 +531,11 @@
 
             return buf;
         }
+
+        public static String getNameWithoutExtension(String file) {
+            String fileName = new File(file).getName();
+            int dotIndex = fileName.lastIndexOf('.');
+            return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
+          }
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java
index 2f1683a..f1e697d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/HiddenApiRestriction.java
@@ -30,10 +30,10 @@
 
 package com.android.tools.smali.dexlib2;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
+import static java.util.Collections.unmodifiableSet;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringJoiner;
@@ -107,19 +107,20 @@
 
     public static Set<HiddenApiRestriction> getAllFlags(int value) {
         HiddenApiRestriction normalRestriction = hiddenApiFlags[value & HIDDENAPI_FLAG_MASK];
+        HashSet restrictionSet = new HashSet<HiddenApiRestriction>();
 
         int domainSpecificPart = (value & ~HIDDENAPI_FLAG_MASK);
         if (domainSpecificPart == 0) {
-            return ImmutableSet.of(normalRestriction);
+            restrictionSet.add(normalRestriction);
+            return unmodifiableSet(restrictionSet);
         }
-        Builder<HiddenApiRestriction> builder = ImmutableSet.builder();
-        builder.add(normalRestriction);
+        restrictionSet.add(normalRestriction);
         for (HiddenApiRestriction domainSpecificApiFlag : domainSpecificApiFlags) {
             if (domainSpecificApiFlag.isSet(value)) {
-                builder.add(domainSpecificApiFlag);
+                restrictionSet.add(domainSpecificApiFlag);
             }
         }
-        return builder.build();
+        return unmodifiableSet(restrictionSet);
     }
 
     public static String formatHiddenRestrictions(int value) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java
index 27a6b61..6ba1726 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java
@@ -30,8 +30,11 @@
 
 package com.android.tools.smali.dexlib2;
 
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableBiMap;
+import static java.util.Collections.unmodifiableMap;
+
+import java.util.HashMap;
+import java.util.Map;
+
 import com.android.tools.smali.util.ExceptionWithContext;
 
 import javax.annotation.Nonnull;
@@ -47,17 +50,26 @@
     public static final int INVOKE_DIRECT = 7;
     public static final int INVOKE_INTERFACE = 8;
 
-    private static final BiMap<Integer, String> methodHandleTypeNames = new ImmutableBiMap.Builder<Integer, String>()
-            .put(STATIC_PUT, "static-put")
-            .put(STATIC_GET, "static-get")
-            .put(INSTANCE_PUT, "instance-put")
-            .put(INSTANCE_GET, "instance-get")
-            .put(INVOKE_STATIC, "invoke-static")
-            .put(INVOKE_INSTANCE, "invoke-instance")
-            .put(INVOKE_CONSTRUCTOR, "invoke-constructor")
-            .put(INVOKE_DIRECT, "invoke-direct")
-            .put(INVOKE_INTERFACE, "invoke-interface")
-            .build();
+    private static final Map<Integer, String> methodHandleTypeNames = unmodifiableMap(Map.of(
+            STATIC_PUT, "static-put",
+            STATIC_GET, "static-get",
+            INSTANCE_PUT, "instance-put",
+            INSTANCE_GET, "instance-get",
+            INVOKE_STATIC, "invoke-static",
+            INVOKE_INSTANCE, "invoke-instance",
+            INVOKE_CONSTRUCTOR, "invoke-constructor",
+            INVOKE_DIRECT, "invoke-direct",
+            INVOKE_INTERFACE, "invoke-interface"));
+
+    private static final Map<String, Integer> inverse = getInverse();
+
+    private static Map<String, Integer> getInverse() {
+        HashMap<String, Integer> namesToTypes = new HashMap<>();
+        for (Map.Entry<Integer, String> entry : methodHandleTypeNames.entrySet()) {
+            namesToTypes.put(entry.getValue(), entry.getKey());
+        }
+        return unmodifiableMap(namesToTypes);
+    }
 
     @Nonnull public static String toString(int methodHandleType) {
         String val = methodHandleTypeNames.get(methodHandleType);
@@ -68,7 +80,7 @@
     }
 
     public static int getMethodHandleType(String methodHandleType) {
-        Integer ret = methodHandleTypeNames.inverse().get(methodHandleType);
+        Integer ret = inverse.get(methodHandleType);
         if (ret == null) {
             throw new ExceptionWithContext("Invalid method handle type: %s", methodHandleType);
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java
index 5a88b0d..176c517 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java
@@ -30,7 +30,6 @@
 
 package com.android.tools.smali.dexlib2;
 
-import com.google.common.collect.Maps;
 import com.google.common.collect.RangeMap;
 
 import javax.annotation.Nonnull;
@@ -94,7 +93,7 @@
         }
 
         opcodeValues = new EnumMap<Opcode, Short>(Opcode.class);
-        opcodesByName = Maps.newHashMap();
+        opcodesByName = new HashMap<>();
 
         int version;
         if (isArt()) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java
index d431588..f7282d7 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VerificationError.java
@@ -30,7 +30,6 @@
 
 package com.android.tools.smali.dexlib2;
 
-import com.google.common.collect.Maps;
 import com.android.tools.smali.util.ExceptionWithContext;
 
 import javax.annotation.Nullable;
@@ -47,7 +46,7 @@
     public static final int CLASS_CHANGE_ERROR = 8;
     public static final int INSTANTIATION_ERROR = 9;
 
-    private static final HashMap<String, Integer> verificationErrorNames = Maps.newHashMap();
+    private static final HashMap<String, Integer> verificationErrorNames = new HashMap<>();
 
     static {
         verificationErrorNames.put("generic-error", GENERIC);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java
index 2534f40..7c59c4b 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java
@@ -45,6 +45,7 @@
 import java.io.StringReader;
 import javax.annotation.Nonnull;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -84,7 +85,7 @@
     }
 
     public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull File inlineTable) throws IOException {
-        this(classPath, Files.toString(inlineTable, Charset.forName("UTF-8")));
+        this(classPath, Files.asCharSource(inlineTable, StandardCharsets.UTF_8).read());
     }
 
     @Override
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java
index b203361..b6174a2 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java
@@ -478,7 +478,7 @@
         List<? extends TryBlock<? extends ExceptionHandler>> tries = methodImpl.getTryBlocks();
         tries = TryListBuilder.massageTryBlocks(tries);
         int triesIndex = 0;
-        TryBlock currentTry = null;
+        TryBlock<? extends ExceptionHandler> currentTry = null;
         AnalyzedInstruction[] currentExceptionHandlers = null;
         AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][];
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java
index 5dd2e60..f271c42 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseAnnotation.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.base;
 
 import com.android.tools.smali.dexlib2.iface.Annotation;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.util.CollectionUtils;
 
 import java.util.Comparator;
@@ -57,7 +56,7 @@
 
     @Override
     public int compareTo(Annotation o) {
-        int res = Ints.compare(getVisibility(), o.getVisibility());
+        int res = Integer.compare(getVisibility(), o.getVisibility());
         if (res != 0) return res;
         res = getType().compareTo(o.getType());
         if (res != 0) return res;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java
index 32ca007..5f6d098 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseExceptionHandler.java
@@ -31,14 +31,13 @@
 package com.android.tools.smali.dexlib2.base;
 
 import com.android.tools.smali.dexlib2.iface.ExceptionHandler;
-import com.google.common.base.Objects;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Comparator;
+import java.util.Objects;
 
 public abstract class BaseExceptionHandler implements ExceptionHandler {
     @Nullable @Override public TypeReference getExceptionTypeReference() {
@@ -65,7 +64,7 @@
     public boolean equals(@Nullable Object o) {
         if (o instanceof ExceptionHandler) {
             ExceptionHandler other = (ExceptionHandler)o;
-            return Objects.equal(getExceptionType(), other.getExceptionType()) &&
+            return Objects.equals(getExceptionType(), other.getExceptionType()) &&
                    (getHandlerCodeAddress() == other.getHandlerCodeAddress());
         }
         return false;
@@ -87,7 +86,7 @@
             res = exceptionType.compareTo(o.getExceptionType());
             if (res != 0) return res;
         }
-        return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
+        return Integer.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
     }
 
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseTryBlock.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseTryBlock.java
index 13267e6..0dc049e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseTryBlock.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/BaseTryBlock.java
@@ -36,7 +36,7 @@
 public abstract class BaseTryBlock<EH extends ExceptionHandler> implements TryBlock<EH> {
     @Override public boolean equals(Object o) {
         if (o instanceof TryBlock) {
-            TryBlock other = (TryBlock)o;
+            TryBlock<? extends ExceptionHandler> other = (TryBlock<? extends ExceptionHandler>)o;
             return getStartCodeAddress() == other.getStartCodeAddress() &&
                     getCodeUnitCount() == other.getCodeUnitCount() &&
                     getExceptionHandlers().equals(other.getExceptionHandlers());
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java
index e14b23a..f2d4e84 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodHandleReference.java
@@ -34,7 +34,6 @@
 import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 import com.android.tools.smali.dexlib2.iface.reference.Reference;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -60,7 +59,7 @@
 
     @Override
     public int compareTo(@Nonnull MethodHandleReference o) {
-        int res = Ints.compare(getMethodHandleType(), o.getMethodHandleType());
+        int res = Integer.compare(getMethodHandleType(), o.getMethodHandleType());
         if (res != 0) return res;
 
         Reference reference = getMemberReference();
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java
index 4a1309e..b43e664 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodProtoReference.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference;
 import com.android.tools.smali.util.CharSequenceUtils;
 import com.android.tools.smali.util.CollectionUtils;
-import com.google.common.collect.Ordering;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -62,7 +61,8 @@
     public int compareTo(@Nonnull MethodProtoReference o) {
         int res = getReturnType().compareTo(o.getReturnType());
         if (res != 0) return res;
-        return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes());
+        return CollectionUtils.compareAsIterable(
+            CollectionUtils.usingToStringOrdering(), getParameterTypes(), o.getParameterTypes());
     }
 
     @Override public String toString() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java
index 079b073..5fda22a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/reference/BaseMethodReference.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 import com.android.tools.smali.util.CharSequenceUtils;
 import com.android.tools.smali.util.CollectionUtils;
-import com.google.common.collect.Ordering;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -68,7 +67,8 @@
         if (res != 0) return res;
         res = getReturnType().compareTo(o.getReturnType());
         if (res != 0) return res;
-        return CollectionUtils.compareAsIterable(Ordering.usingToString(), getParameterTypes(), o.getParameterTypes());
+        return CollectionUtils.compareAsIterable(
+            CollectionUtils.usingToStringOrdering(), getParameterTypes(), o.getParameterTypes());
     }
 
     @Override public String toString() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue.java
index b0eb59f..b04e014 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue.java
@@ -34,7 +34,6 @@
 import com.android.tools.smali.dexlib2.iface.value.AnnotationEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.util.CollectionUtils;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -59,7 +58,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         AnnotationEncodedValue other = (AnnotationEncodedValue)o;
         res = getType().compareTo(other.getType());
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue.java
index ea7bc5b..4c9e3f9 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue.java
@@ -34,7 +34,6 @@
 import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.util.CollectionUtils;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
     }
 
     @Override public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return CollectionUtils.compareAsList(getValue(), ((ArrayEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue.java
index 08e20bf..c4590e5 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue.java
@@ -33,8 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.BooleanEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
-import com.google.common.primitives.Booleans;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -56,9 +54,9 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
-        return Booleans.compare(getValue(), ((BooleanEncodedValue)o).getValue());
+        return Boolean.compare(getValue(), ((BooleanEncodedValue)o).getValue());
     }
 
     public int getValueType() { return ValueType.BOOLEAN; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue.java
index d80abd9..28315f7 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.ByteEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,9 +54,9 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
-        return Ints.compare(getValue(), ((ByteEncodedValue)o).getValue());
+        return Integer.compare(getValue(), ((ByteEncodedValue)o).getValue());
     }
 
     public int getValueType() { return ValueType.BYTE; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue.java
index e6885a4..c942709 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue.java
@@ -33,8 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.CharEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
-import com.google.common.primitives.Chars;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -56,9 +54,9 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
-        return Chars.compare(getValue(), ((CharEncodedValue)o).getValue());
+        return Character.compare(getValue(), ((CharEncodedValue)o).getValue());
     }
 
     public int getValueType() { return ValueType.CHAR; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue.java
index 71bd204..5ca790f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.DoubleEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -57,7 +56,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return Double.compare(getValue(), ((DoubleEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue.java
index a70f4c0..29dbc54 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EnumEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((EnumEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue.java
index eb994ba..12abfd3 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.FieldEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((FieldEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue.java
index d5164eb..74b2a90 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.FloatEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return Float.compare(getValue(), ((FloatEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue.java
index 58038e5..58f4c42 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.IntEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,9 +54,9 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
-        return Ints.compare(getValue(), ((IntEncodedValue)o).getValue());
+        return Integer.compare(getValue(), ((IntEncodedValue)o).getValue());
     }
 
     public int getValueType() { return ValueType.INT; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue.java
index 908133d..0adc5ae 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue.java
@@ -33,8 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.LongEncodedValue;
-import com.google.common.primitives.Ints;
-import com.google.common.primitives.Longs;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -58,9 +56,9 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
-        return Longs.compare(getValue(), ((LongEncodedValue)o).getValue());
+        return Long.compare(getValue(), ((LongEncodedValue)o).getValue());
     }
 
     public int getValueType() { return ValueType.LONG; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue.java
index e14ffdd..930a117 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.MethodEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((MethodEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue.java
index 856c6b9..6278e5a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.MethodHandleEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -54,7 +53,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((MethodHandleEncodedValue) o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue.java
index 39b9ced..3f1faff 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.MethodTypeEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -54,7 +53,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((MethodTypeEncodedValue) o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue.java
index 4383cb7..992e8f0 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.NullEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -52,7 +51,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        return Ints.compare(getValueType(), o.getValueType());
+        return Integer.compare(getValueType(), o.getValueType());
     }
 
     public int getValueType() { return ValueType.NULL; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue.java
index 0ddb93c..47beb48 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue.java
@@ -33,8 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.ShortEncodedValue;
-import com.google.common.primitives.Ints;
-import com.google.common.primitives.Shorts;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -56,9 +54,9 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
-        return Shorts.compare(getValue(), ((ShortEncodedValue)o).getValue());
+        return Short.compare(getValue(), ((ShortEncodedValue)o).getValue());
     }
 
     public int getValueType() { return ValueType.SHORT; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue.java
index fdaa9b9..7e05e38 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((StringEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue.java
index 74459d9..962004a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 
 import javax.annotation.Nonnull;
@@ -55,7 +54,7 @@
 
     @Override
     public int compareTo(@Nonnull EncodedValue o) {
-        int res = Ints.compare(getValueType(), o.getValueType());
+        int res = Integer.compare(getValueType(), o.getValueType());
         if (res != 0) return res;
         return getValue().compareTo(((TypeEncodedValue)o).getValue());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/CDexBackedMethodImplementation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/CDexBackedMethodImplementation.java
index d6acffd..99df58e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/CDexBackedMethodImplementation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/CDexBackedMethodImplementation.java
@@ -121,7 +121,7 @@
 
         int debugOffsetsOffset = cdexFile.getDataBuffer().readSmallUint(debugTableOffset + debugTableItemOffset);
 
-        DexReader reader = cdexFile.getDataBuffer().readerAt(debugInfoOffsetsPos + debugOffsetsOffset);
+        DexReader<? extends DexBuffer> reader = cdexFile.getDataBuffer().readerAt(debugInfoOffsetsPos + debugOffsetsOffset);
 
         int bitMask = reader.readUbyte() << 8;
         bitMask += reader.readUbyte();
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotation.java
index 943b85d..c25e8f5 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotation.java
@@ -47,7 +47,7 @@
                                int annotationOffset) {
         this.dexFile = dexFile;
 
-        DexReader reader = dexFile.getDataBuffer().readerAt(annotationOffset);
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(annotationOffset);
         this.visibility = reader.readUbyte();
         this.typeIndex = reader.readSmallUleb128();
         this.elementsOffset = reader.getOffset();
@@ -59,13 +59,13 @@
     @Nonnull
     @Override
     public Set<? extends DexBackedAnnotationElement> getElements() {
-        DexReader reader = dexFile.getDataBuffer().readerAt(elementsOffset);
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(elementsOffset);
         final int size = reader.readSmallUleb128();
 
         return new VariableSizeSet<DexBackedAnnotationElement>(dexFile.getDataBuffer(), reader.getOffset(), size) {
             @Nonnull
             @Override
-            protected DexBackedAnnotationElement readNextItem(@Nonnull DexReader reader, int index) {
+            protected DexBackedAnnotationElement readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                 return new DexBackedAnnotationElement(dexFile, reader);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotationElement.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotationElement.java
index ce9a595..d286668 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotationElement.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedAnnotationElement.java
@@ -41,7 +41,7 @@
     public final int nameIndex;
     @Nonnull public final EncodedValue value;
 
-    public DexBackedAnnotationElement(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public DexBackedAnnotationElement(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         this.dexFile = dexFile;
         this.nameIndex = reader.readSmallUleb128();
         this.value = DexBackedEncodedValue.readFrom(dexFile, reader);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedCatchAllExceptionHandler.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedCatchAllExceptionHandler.java
index cb1d727..2cf08ea 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedCatchAllExceptionHandler.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedCatchAllExceptionHandler.java
@@ -36,7 +36,7 @@
 public class DexBackedCatchAllExceptionHandler extends DexBackedExceptionHandler {
     private final int handlerCodeAddress;
 
-    public DexBackedCatchAllExceptionHandler(@Nonnull DexReader reader) {
+    public DexBackedCatchAllExceptionHandler(@Nonnull DexReader<? extends DexBuffer> reader) {
         this.handlerCodeAddress = reader.readSmallUleb128();
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedClassDef.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedClassDef.java
index 4c709ad..059771f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedClassDef.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedClassDef.java
@@ -43,13 +43,12 @@
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableFieldReference;
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference;
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
+import com.android.tools.smali.util.ChainedIterator;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.AbstractList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -87,7 +86,7 @@
             directMethodCount = 0;
             virtualMethodCount = 0;
         } else {
-            DexReader reader = dexFile.getDataBuffer().readerAt(classDataOffset);
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(classDataOffset);
             staticFieldCount = reader.readSmallUleb128();
             instanceFieldCount = reader.readSmallUleb128();
             directMethodCount = reader.readSmallUleb128();
@@ -146,7 +145,7 @@
                 @Override public int size() { return size; }
             };
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     @Nonnull
@@ -192,7 +191,7 @@
 
                         @Nullable
                         @Override
-                        protected DexBackedField readNextItem(@Nonnull DexReader reader) {
+                        protected DexBackedField readNextItem(@Nonnull DexReader<? extends DexBuffer> reader) {
                             while (true) {
                                 if (++count > staticFieldCount) {
                                     instanceFieldsOffset = reader.getOffset();
@@ -225,7 +224,7 @@
             };
         } else {
             instanceFieldsOffset = staticFieldsOffset;
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
     }
 
@@ -238,7 +237,7 @@
     @Nonnull
     public Iterable<? extends DexBackedField> getInstanceFields(final boolean skipDuplicates) {
         if (instanceFieldCount > 0) {
-            DexReader reader = dexFile.getDataBuffer().readerAt(getInstanceFieldsOffset());
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(getInstanceFieldsOffset());
 
             final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory();
             final int fieldsStartOffset = reader.getOffset();
@@ -261,7 +260,7 @@
 
                         @Nullable
                         @Override
-                        protected DexBackedField readNextItem(@Nonnull DexReader reader) {
+                        protected DexBackedField readNextItem(@Nonnull DexReader<? extends DexBuffer> reader) {
                             while (true) {
                                 if (++count > instanceFieldCount) {
                                     directMethodsOffset = reader.getOffset();
@@ -295,14 +294,14 @@
             if (instanceFieldsOffset > 0) {
                 directMethodsOffset = instanceFieldsOffset;
             }
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
     }
 
     @Nonnull
     @Override
     public Iterable<? extends DexBackedField> getFields() {
-        return Iterables.concat(getStaticFields(), getInstanceFields());
+        return new ChainedIterator(getStaticFields(), getInstanceFields());
     }
 
     @Nonnull
@@ -314,7 +313,7 @@
     @Nonnull
     public Iterable<? extends DexBackedMethod> getDirectMethods(final boolean skipDuplicates) {
         if (directMethodCount > 0) {
-            DexReader reader = dexFile.getDataBuffer().readerAt(getDirectMethodsOffset());
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(getDirectMethodsOffset());
 
             final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory();
             final int methodsStartOffset = reader.getOffset();
@@ -339,7 +338,7 @@
 
                         @Nullable
                         @Override
-                        protected DexBackedMethod readNextItem(@Nonnull DexReader reader) {
+                        protected DexBackedMethod readNextItem(@Nonnull DexReader<? extends DexBuffer> reader) {
                             while (true) {
                                 if (++count > directMethodCount) {
                                     virtualMethodsOffset = reader.getOffset();
@@ -374,14 +373,14 @@
             if (directMethodsOffset > 0) {
                 virtualMethodsOffset = directMethodsOffset;
             }
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
     }
 
     @Nonnull
     public Iterable<? extends DexBackedMethod> getVirtualMethods(final boolean skipDuplicates) {
         if (virtualMethodCount > 0) {
-            DexReader reader = dexFile.getDataBuffer().readerAt(getVirtualMethodsOffset());
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(getVirtualMethodsOffset());
 
             final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory();
             final int methodsStartOffset = reader.getOffset();
@@ -406,7 +405,7 @@
 
                         @Nullable
                         @Override
-                        protected DexBackedMethod readNextItem(@Nonnull DexReader reader) {
+                        protected DexBackedMethod readNextItem(@Nonnull DexReader<? extends DexBuffer> reader) {
                             while (true) {
                                 if (++count > virtualMethodCount) {
                                     return endOfData();
@@ -436,7 +435,7 @@
                 }
             };
         } else {
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
     }
 
@@ -449,7 +448,7 @@
     @Nonnull
     @Override
     public Iterable<? extends DexBackedMethod> getMethods() {
-        return Iterables.concat(getDirectMethods(), getVirtualMethods());
+        return new ChainedIterator(getDirectMethods(), getVirtualMethods());
     }
 
     private AnnotationsDirectory getAnnotationsDirectory() {
@@ -465,7 +464,7 @@
         if (instanceFieldsOffset > 0) {
             return instanceFieldsOffset;
         }
-        DexReader reader = dexFile.getDataBuffer().readerAt(staticFieldsOffset);
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(staticFieldsOffset);
         DexBackedField.skipFields(reader, staticFieldCount);
         instanceFieldsOffset = reader.getOffset();
         return instanceFieldsOffset;
@@ -475,7 +474,7 @@
         if (directMethodsOffset > 0) {
             return directMethodsOffset;
         }
-        DexReader reader = dexFile.getDataBuffer().readerAt(getInstanceFieldsOffset());
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(getInstanceFieldsOffset());
         DexBackedField.skipFields(reader, instanceFieldCount);
         directMethodsOffset = reader.getOffset();
         return directMethodsOffset;
@@ -485,7 +484,7 @@
         if (virtualMethodsOffset > 0) {
             return virtualMethodsOffset;
         }
-        DexReader reader = dexFile.getDataBuffer().readerAt(getDirectMethodsOffset());
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(getDirectMethodsOffset());
         DexBackedMethod.skipMethods(reader, directMethodCount);
         virtualMethodsOffset = reader.getOffset();
         return virtualMethodsOffset;
@@ -528,14 +527,14 @@
         int staticInitialValuesOffset =
             dexFile.getBuffer().readSmallUint(classDefOffset + ClassDefItem.STATIC_VALUES_OFFSET);
         if (staticInitialValuesOffset != 0) {
-            DexReader reader = dexFile.getDataBuffer().readerAt(staticInitialValuesOffset);
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(staticInitialValuesOffset);
             size += reader.peekSmallUleb128Size(); //encoded_array size field
         }
 
         //class_data_item
         int classDataOffset = dexFile.getBuffer().readSmallUint(classDefOffset + ClassDefItem.CLASS_DATA_OFFSET);
         if (classDataOffset > 0) {
-            DexReader reader = dexFile.getDataBuffer().readerAt(classDataOffset);
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(classDataOffset);
             reader.readSmallUleb128(); //staticFieldCount
             reader.readSmallUleb128(); //instanceFieldCount
             reader.readSmallUleb128(); //directMethodCount
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
index 7ea7c69..260ae6c 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
@@ -57,10 +57,11 @@
 import com.android.tools.smali.dexlib2.iface.reference.Reference;
 import com.android.tools.smali.dexlib2.util.DexUtil;
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.io.ByteStreams;
+import com.android.tools.smali.util.InputStreamUtil;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.AbstractList;
@@ -193,7 +194,7 @@
             throws IOException {
         DexUtil.verifyDexHeader(is);
 
-        byte[] buf = ByteStreams.toByteArray(is);
+        byte[] buf = InputStreamUtil.toByteArray(is);
         return new DexBackedDexFile(opcodes, buf, 0, false);
     }
 
@@ -320,7 +321,7 @@
         public String get(int index) {
             int stringOffset = getOffset(index);
             int stringDataOffset = dexBuffer.readSmallUint(stringOffset);
-            DexReader reader = dataBuffer.readerAt(stringDataOffset);
+            DexReader<? extends DexBuffer> reader = dataBuffer.readerAt(stringDataOffset);
             int utf16Length = reader.readSmallUleb128();
             return reader.readString(utf16Length);
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedField.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedField.java
index 96dcce6..1db123f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedField.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedField.java
@@ -41,10 +41,11 @@
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.Field;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.Set;
 
@@ -64,7 +65,7 @@
     private int fieldIdItemOffset;
 
     public DexBackedField(@Nonnull DexBackedDexFile dexFile,
-                          @Nonnull DexReader reader,
+                          @Nonnull DexReader<? extends DexBuffer> reader,
                           @Nonnull DexBackedClassDef classDef,
                           int previousFieldIndex,
                           @Nonnull EncodedArrayItemIterator staticInitialValueIterator,
@@ -87,7 +88,7 @@
     }
 
     public DexBackedField(@Nonnull DexBackedDexFile dexFile,
-                          @Nonnull DexReader reader,
+                          @Nonnull DexReader<? extends DexBuffer> reader,
                           @Nonnull DexBackedClassDef classDef,
                           int previousFieldIndex,
                           @Nonnull AnnotationIterator annotationIterator,
@@ -136,7 +137,7 @@
     @Override
     public Set<HiddenApiRestriction> getHiddenApiRestrictions() {
         if (hiddenApiRestrictions == DexBackedClassDef.NO_HIDDEN_API_RESTRICTIONS) {
-            return ImmutableSet.of();
+            return Collections.emptySet();
         } else {
             return EnumSet.copyOf(HiddenApiRestriction.getAllFlags(hiddenApiRestrictions));
         }
@@ -148,7 +149,7 @@
      * @param reader The reader to skip
      * @param count The number of encoded_field structures to skip over
      */
-    public static void skipFields(@Nonnull DexReader reader, int count) {
+    public static void skipFields(@Nonnull DexReader<? extends DexBuffer> reader, int count) {
         for (int i=0; i<count; i++) {
             reader.skipUleb128();
             reader.skipUleb128();
@@ -172,7 +173,7 @@
      */
     public int getSize() {
         int size = 0;
-        DexReader reader = dexFile.getBuffer().readerAt(startOffset);
+        DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(startOffset);
         reader.readLargeUleb128(); //field_idx_diff
         reader.readSmallUleb128(); //access_flags
         size += reader.getOffset() - startOffset;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java
index 78a4b0b..84e6e83 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java
@@ -30,6 +30,8 @@
 
 package com.android.tools.smali.dexlib2.dexbacked;
 
+import static java.util.Collections.unmodifiableList;
+
 import com.android.tools.smali.dexlib2.HiddenApiRestriction;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.dexbacked.raw.MethodIdItem;
@@ -44,11 +46,11 @@
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
 import com.android.tools.smali.util.AbstractForwardSequentialList;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
@@ -73,7 +75,7 @@
     private int parametersOffset = -1;
 
     public DexBackedMethod(@Nonnull DexBackedDexFile dexFile,
-                           @Nonnull DexReader reader,
+                           @Nonnull DexReader<? extends DexBuffer> reader,
                            @Nonnull DexBackedClassDef classDef,
                            int previousMethodIndex,
                            int hiddenApiRestrictions) {
@@ -94,7 +96,7 @@
     }
 
     public DexBackedMethod(@Nonnull DexBackedDexFile dexFile,
-                           @Nonnull DexReader reader,
+                           @Nonnull DexReader<? extends DexBuffer> reader,
                            @Nonnull DexBackedClassDef classDef,
                            int previousMethodIndex,
                            @Nonnull AnnotationIterator methodAnnotationIterator,
@@ -153,7 +155,7 @@
                 }
             };
         }
-        return ImmutableList.of();
+        return unmodifiableList(List.of());
     }
 
     @Nonnull
@@ -167,7 +169,7 @@
         if (methodImpl != null) {
             return methodImpl.getParameterNames(null);
         }
-        return ImmutableSet.<String>of().iterator();
+        return Collections.emptyIterator();
     }
 
     @Nonnull
@@ -186,7 +188,7 @@
                 @Override public int size() { return parameterCount; }
             };
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     @Nonnull
@@ -199,7 +201,7 @@
     @Override
     public Set<HiddenApiRestriction> getHiddenApiRestrictions() {
         if (hiddenApiRestrictions == DexBackedClassDef.NO_HIDDEN_API_RESTRICTIONS) {
-            return ImmutableSet.of();
+            return Collections.emptySet();
         } else {
             return EnumSet.copyOf(HiddenApiRestriction.getAllFlags(hiddenApiRestrictions));
         }
@@ -243,7 +245,7 @@
      * @param reader The reader to skip
      * @param count The number of encoded_method structures to skip over
      */
-    public static void skipMethods(@Nonnull DexReader reader, int count) {
+    public static void skipMethods(@Nonnull DexReader<? extends DexBuffer> reader, int count) {
         for (int i=0; i<count; i++) {
             reader.skipUleb128();
             reader.skipUleb128();
@@ -262,7 +264,7 @@
     public int getSize() {
         int size = 0;
 
-        DexReader reader = dexFile.getDataBuffer().readerAt(startOffset);
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(startOffset);
         reader.readLargeUleb128(); //method_idx_diff
         reader.readSmallUleb128(); //access_flags
         reader.readSmallUleb128(); //code_off
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethodImplementation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethodImplementation.java
index e7c6d4b..a231cfb 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethodImplementation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethodImplementation.java
@@ -41,10 +41,11 @@
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
 import com.android.tools.smali.dexlib2.util.AlignmentUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
@@ -85,7 +86,7 @@
                 return new VariableSizeLookaheadIterator<Instruction>(
                         dexFile.getDataBuffer(), instructionsStartOffset) {
                     @Override
-                    protected Instruction readNextItem(@Nonnull DexReader reader) {
+                    protected Instruction readNextItem(@Nonnull DexReader<? extends DexBuffer> reader) {
                         if (reader.getOffset() >= endOffset) {
                             return endOfData();
                         }
@@ -133,7 +134,7 @@
                 }
             };
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     protected int getDebugOffset() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedOdexFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedOdexFile.java
index d6f7f6d..c9665e5 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedOdexFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedOdexFile.java
@@ -34,7 +34,7 @@
 import com.android.tools.smali.dexlib2.dexbacked.raw.OdexHeaderItem;
 import com.android.tools.smali.dexlib2.dexbacked.util.VariableSizeList;
 import com.android.tools.smali.dexlib2.util.DexUtil;
-import com.google.common.io.ByteStreams;
+import com.android.tools.smali.util.InputStreamUtil;
 
 import javax.annotation.Nonnull;
 import java.io.IOException;
@@ -67,7 +67,7 @@
 
         return new VariableSizeList<String>(
                 this.getDataBuffer(), dependencyOffset + DEPENDENCY_START_OFFSET, dependencyCount) {
-            @Override protected String readNextItem(@Nonnull DexReader reader, int index) {
+            @Override protected String readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                 int length = reader.readInt();
                 int offset = reader.getOffset();
                 reader.moveRelative(length + 20);
@@ -86,13 +86,13 @@
 
         is.reset();
         byte[] odexBuf = new byte[OdexHeaderItem.ITEM_SIZE];
-        ByteStreams.readFully(is, odexBuf);
+        InputStreamUtil.readFully(is, odexBuf);
         int dexOffset = OdexHeaderItem.getDexOffset(odexBuf);
         if (dexOffset > OdexHeaderItem.ITEM_SIZE) {
-            ByteStreams.skipFully(is, dexOffset - OdexHeaderItem.ITEM_SIZE);
+            InputStreamUtil.skipFully(is, dexOffset - OdexHeaderItem.ITEM_SIZE);
         }
 
-        byte[] dexBuf = ByteStreams.toByteArray(is);
+        byte[] dexBuf = InputStreamUtil.toByteArray(is);
 
         return new DexBackedOdexFile(opcodes, odexBuf, dexBuf);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTryBlock.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTryBlock.java
index d801523..a34e973 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTryBlock.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTryBlock.java
@@ -61,7 +61,7 @@
     @Nonnull
     @Override
     public List<? extends DexBackedExceptionHandler> getExceptionHandlers() {
-        DexReader reader = dexFile.getDataBuffer().readerAt(
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(
                 handlersStartOffset + dexFile.getDataBuffer().readUshort(tryItemOffset + CodeItem.TryItem.HANDLER_OFFSET));
         final int encodedSize = reader.readSleb128();
 
@@ -71,7 +71,7 @@
                     dexFile.getDataBuffer(), reader.getOffset(), encodedSize) {
                 @Nonnull
                 @Override
-                protected DexBackedTypedExceptionHandler readNextItem(@Nonnull DexReader reader, int index) {
+                protected DexBackedTypedExceptionHandler readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                     return new DexBackedTypedExceptionHandler(dexFile, reader);
                 }
             };
@@ -82,7 +82,7 @@
                     dexFile.getDataBuffer(), reader.getOffset(), sizeWithCatchAll) {
                 @Nonnull
                 @Override
-                protected DexBackedExceptionHandler readNextItem(@Nonnull DexReader dexReader, int index) {
+                protected DexBackedExceptionHandler readNextItem(@Nonnull DexReader<? extends DexBuffer> dexReader, int index) {
                     if (index == sizeWithCatchAll-1) {
                         return new DexBackedCatchAllExceptionHandler(dexReader);
                     } else {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTypedExceptionHandler.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTypedExceptionHandler.java
index 5104c06..c880357 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTypedExceptionHandler.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedTypedExceptionHandler.java
@@ -37,7 +37,7 @@
     private final int typeId;
     private final int handlerCodeAddress;
 
-    public DexBackedTypedExceptionHandler(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public DexBackedTypedExceptionHandler(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         this.dexFile = dexFile;
         this.typeId = reader.readSmallUleb128();
         this.handlerCodeAddress = reader.readSmallUleb128();
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java
index 451da3b..a6011b4 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java
@@ -36,14 +36,15 @@
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
 import com.android.tools.smali.dexlib2.util.DexUtil;
 import com.android.tools.smali.util.AbstractForwardSequentialList;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterators;
-import com.google.common.io.ByteStreams;
+import com.android.tools.smali.util.InputStreamUtil;
+import com.android.tools.smali.util.TransformedIterator;
+
+import java.util.function.Function;
 import com.android.tools.smali.dexlib2.dexbacked.OatFile.SymbolTable.Symbol;
 
 import java.util.AbstractList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -136,7 +137,7 @@
         is.mark(4);
         byte[] partialHeader = new byte[4];
         try {
-            ByteStreams.readFully(is, partialHeader);
+            InputStreamUtil.readFully(is, partialHeader);
         } catch (EOFException ex) {
             throw new NotAnOatFileException();
         } finally {
@@ -147,7 +148,7 @@
 
         is.reset();
 
-        byte[] buf = ByteStreams.toByteArray(is);
+        byte[] buf = InputStreamUtil.toByteArray(is);
         return new OatFile(buf, vdexProvider);
     }
 
@@ -169,11 +170,11 @@
     @Nonnull
     public List<String> getBootClassPath() {
         if (getOatVersion() < 75) {
-            return ImmutableList.of();
+            return Collections.unmodifiableList(List.of());
         }
         String bcp = oatHeader.getKeyValue("bootclasspath");
         if (bcp == null) {
-            return ImmutableList.of();
+            return Collections.unmodifiableList(List.of());
         }
         return Arrays.asList(bcp.split(":"));
     }
@@ -181,18 +182,18 @@
     @Nonnull
     public List<DexBackedDexFile> getDexFiles() {
         return new AbstractForwardSequentialList<DexBackedDexFile>() {
+
             @Override public int size() {
-                return Iterators.size(Iterators.filter(new DexEntryIterator(), Objects::nonNull));
+                DexEntryIterator it = new DexEntryIterator();
+                return it.getSize();
             }
 
             @Nonnull @Override public Iterator<DexBackedDexFile> iterator() {
-                return Iterators.transform(
-                    Iterators.filter(new DexEntryIterator(), Objects::nonNull),
-                        new Function<OatDexEntry, DexBackedDexFile>() {
-                            @Nullable @Override public DexBackedDexFile apply(OatDexEntry dexEntry) {
-                                return dexEntry.getDexFile();
-                            }
-                        });
+                return new TransformedIterator<OatDexEntry, DexBackedDexFile>(new DexEntryIterator(), new Function<OatDexEntry, DexBackedDexFile>() {
+                    @Nullable @Override public DexBackedDexFile apply(OatDexEntry dexEntry) {
+                        return dexEntry.getDexFile();
+                    }
+                });
             }
         };
     }
@@ -200,17 +201,16 @@
     @Nonnull @Override public List<String> getDexEntryNames() throws IOException {
         return new AbstractForwardSequentialList<String>() {
             @Override public int size() {
-                return Iterators.size(Iterators.filter(new DexEntryIterator(), Objects::nonNull));
+                DexEntryIterator it = new DexEntryIterator();
+                return it.getSize();
             }
 
             @Nonnull @Override public Iterator<String> iterator() {
-                return Iterators.transform(
-                    Iterators.filter(new DexEntryIterator(), Objects::nonNull),
-                        new Function<OatDexEntry, String>() {
-                            @Nullable @Override public String apply(OatDexEntry dexEntry) {
-                                return dexEntry.entryName;
-                            }
-                        });
+                return new TransformedIterator<OatDexEntry, String>(new DexEntryIterator(), new Function<OatDexEntry, String>() {
+                    @Nullable @Override public String apply(OatDexEntry dexEntry) {
+                        return dexEntry.entryName;
+                    }
+                });
             }
         };
     }
@@ -677,6 +677,20 @@
         @Override public void remove() {
             throw new UnsupportedOperationException();
         }
+
+        /**
+         * Returns the number of elements remaining in {@code iterator}. The iterator will be left
+         * exhausted: its {@code hasNext()} method will return {@code false}.
+         */
+        public int getSize() {
+            int count = 0;
+            while (hasNext()) {
+                if (Objects.nonNull(next())) {
+                    count++;
+                }
+            }
+            return count;
+        }
     }
 
     public static class InvalidOatFileException extends RuntimeException {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java
index 31d115c..50d0bdf 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java
@@ -36,8 +36,8 @@
 import com.android.tools.smali.dexlib2.util.DexUtil;
 import com.android.tools.smali.dexlib2.util.DexUtil.InvalidFile;
 import com.android.tools.smali.dexlib2.util.DexUtil.UnsupportedFile;
-import com.google.common.collect.Lists;
-import com.google.common.io.ByteStreams;
+import com.android.tools.smali.util.InputStreamUtil;
+
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile.NotADexFile;
 
 import java.io.BufferedInputStream;
@@ -87,8 +87,7 @@
           return entries;
         }
         entries = new TreeMap<String, DexBackedDexFile>();
-        ZipFile zipFile = getZipFile();
-        try {
+        try (ZipFile zipFile = getZipFile()) {
             Enumeration<? extends ZipEntry> entriesEnumeration = zipFile.entries();
 
             while (entriesEnumeration.hasMoreElements()) {
@@ -99,22 +98,17 @@
                 }
 
                 // There might be several dex files in zip entry since DEX v41.
-                InputStream inputStream = zipFile.getInputStream(entry);
-                try {
-                    byte[] buf = ByteStreams.toByteArray(inputStream);
+                try (InputStream inputStream = zipFile.getInputStream(entry)) {
+                    byte[] buf = InputStreamUtil.toByteArray(inputStream);
                     for (int offset = 0, i = 1; offset < buf.length; i++) {
                       DexBackedDexFile dex = new DexBackedDexFile(opcodes, buf, 0, true, offset);
                       entries.put(entry.getName() + (i > 1 ? ("/" + i) : ""), dex);
                       offset += dex.getFileSize();
                     };
-                } finally {
-                    inputStream.close();
                 }
             }
 
             return entries;
-        } finally {
-            zipFile.close();
         }
     }
 
@@ -152,28 +146,18 @@
     }
 
     public boolean isZipFile() {
-        ZipFile zipFile = null;
-        try {
-            zipFile = getZipFile();
+        try (ZipFile zipFile = getZipFile()) {
             return true;
         } catch (IOException ex) {
             return false;
         } catch (NotAZipFileException ex) {
             return false;
-        } finally {
-            if(zipFile != null) {
-                try {
-                    zipFile.close();
-                } catch (IOException ex) {
-                    // just eat it
-                }
-            }
         }
+        // just eat it
     }
 
     protected boolean isDex(@Nonnull ZipFile zipFile, @Nonnull ZipEntry zipEntry) throws IOException {
-        InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry));
-        try {
+        try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) {
             DexUtil.verifyDexHeader(inputStream);
         } catch (NotADexFile ex) {
             return false;
@@ -181,8 +165,6 @@
             return false;
         } catch (UnsupportedFile ex) {
             return false;
-        } finally {
-            inputStream.close();
         }
         return true;
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java
index 34cad36..ec93d9a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java
@@ -33,12 +33,12 @@
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.iface.instruction.formats.ArrayPayload;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.util.FixedSizeList;
 
 import javax.annotation.Nonnull;
 import java.util.List;
+import java.util.Collections;
 
 public class DexBackedArrayPayload extends DexBackedInstruction implements ArrayPayload {
     public static final Opcode OPCODE = Opcode.ARRAY_PAYLOAD;
@@ -81,7 +81,7 @@
         }
 
         if (elementCount == 0) {
-            return ImmutableList.of();
+            return Collections.unmodifiableList(List.of());
         }
 
         switch (elementWidth) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedInstruction.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedInstruction.java
index 04d8f1e..6df0a95 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedInstruction.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedInstruction.java
@@ -31,6 +31,7 @@
 package com.android.tools.smali.dexlib2.dexbacked.instruction;
 
 import com.android.tools.smali.dexlib2.Opcode;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.util.ExceptionWithContext;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
@@ -56,7 +57,7 @@
     @Override public int getCodeUnits() { return opcode.format.size / 2; }
 
     @Nonnull
-    public static Instruction readFrom(DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public static Instruction readFrom(DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         int opcodeValue = reader.peekUbyte();
 
         if (opcodeValue == 0) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/AnnotationItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/AnnotationItem.java
index 518c4fc..dfb5720 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/AnnotationItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/AnnotationItem.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.raw;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -54,7 +55,7 @@
                 int visibility = dexFile.getBuffer().readUbyte(out.getCursor());
                 out.annotate(1, "visibility = %d: %s", visibility, getAnnotationVisibility(visibility));
 
-                DexReader reader = dexFile.getBuffer().readerAt(out.getCursor());
+                DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor());
 
                 EncodedValue.annotateEncodedAnnotation(dexFile, out, reader);
             }
@@ -76,7 +77,7 @@
 
     public static String getReferenceAnnotation(@Nonnull DexBackedDexFile dexFile, int annotationItemOffset) {
         try {
-            DexReader reader = dexFile.getDataBuffer().readerAt(annotationItemOffset);
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(annotationItemOffset);
             reader.readUbyte();
             int typeIndex = reader.readSmallUleb128();
             String annotationType = dexFile.getTypeSection().get(typeIndex);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CdexDebugOffsetTable.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CdexDebugOffsetTable.java
index da0075f..eb7404e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CdexDebugOffsetTable.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CdexDebugOffsetTable.java
@@ -67,7 +67,7 @@
 public class CdexDebugOffsetTable {
     @Nonnull
     public static void annotate(@Nonnull DexAnnotator annotator, DexBuffer buffer) {
-        DexReader reader = buffer.readerAt(annotator.getCursor());
+        DexReader<? extends DexBuffer> reader = buffer.readerAt(annotator.getCursor());
 
         SectionAnnotator debugInfoAnnotator = annotator.getAnnotator(ItemType.DEBUG_INFO_ITEM);
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDataItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDataItem.java
index b26547a..7638da8 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDataItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDataItem.java
@@ -31,9 +31,14 @@
 package com.android.tools.smali.dexlib2.dexbacked.raw;
 
 import com.android.tools.smali.dexlib2.AccessFlags;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
-import com.google.common.base.Joiner;
+import com.android.tools.smali.util.StringUtils;
+
+import java.util.Arrays;
+import java.util.List;
+
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 
@@ -57,7 +62,7 @@
 
             @Override
             protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
-                DexReader reader = dexFile.getBuffer().readerAt(out.getCursor());
+                DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor());
 
                 int staticFieldsSize = reader.readSmallUleb128();
                 out.annotateTo(reader.getOffset(), "static_fields_size = %d", staticFieldsSize);
@@ -125,7 +130,7 @@
             }
 
             private int annotateEncodedField(@Nonnull AnnotatedBytes out, @Nonnull DexBackedDexFile dexFile,
-                                             @Nonnull DexReader reader, int previousIndex) {
+                                             @Nonnull DexReader<? extends DexBuffer> reader, int previousIndex) {
                 // large values may be used for the index delta, which cause the cumulative index to overflow upon
                 // addition, effectively allowing out of order entries.
                 int indexDelta = reader.readLargeUleb128();
@@ -135,13 +140,13 @@
 
                 int accessFlags = reader.readSmallUleb128();
                 out.annotateTo(reader.getOffset(), "access_flags = 0x%x: %s", accessFlags,
-                        Joiner.on('|').join(AccessFlags.getAccessFlagsForField(accessFlags)));
+                        StringUtils.join(Arrays.asList(AccessFlags.getAccessFlagsForField(accessFlags)), "|"));
 
                 return fieldIndex;
             }
 
             private int annotateEncodedMethod(@Nonnull AnnotatedBytes out, @Nonnull DexBackedDexFile dexFile,
-                                              @Nonnull DexReader reader, int previousIndex) {
+                                              @Nonnull DexReader<? extends DexBuffer> reader, int previousIndex) {
                 // large values may be used for the index delta, which cause the cumulative index to overflow upon
                 // addition, effectively allowing out of order entries.
                 int indexDelta = reader.readLargeUleb128();
@@ -151,7 +156,7 @@
 
                 int accessFlags = reader.readSmallUleb128();
                 out.annotateTo(reader.getOffset(), "access_flags = 0x%x: %s", accessFlags,
-                        Joiner.on('|').join(AccessFlags.getAccessFlagsForMethod(accessFlags)));
+                    StringUtils.join(Arrays.asList(AccessFlags.getAccessFlagsForField(accessFlags)), "|"));
 
                 int codeOffset = reader.readSmallUleb128();
                 if (codeOffset == 0) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDefItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDefItem.java
index 617599e..b09d614 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDefItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/ClassDefItem.java
@@ -33,7 +33,10 @@
 import com.android.tools.smali.dexlib2.AccessFlags;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
-import com.google.common.base.Joiner;
+import com.android.tools.smali.util.StringUtils;
+
+import java.util.Arrays;
+
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 
 import javax.annotation.Nonnull;
@@ -72,7 +75,7 @@
 
                 int accessFlags = dexFile.getBuffer().readInt(out.getCursor());
                 out.annotate(4, "access_flags = 0x%x: %s", accessFlags,
-                        Joiner.on('|').join(AccessFlags.getAccessFlagsForClass(accessFlags)));
+                        StringUtils.join(Arrays.asList(AccessFlags.getAccessFlagsForClass(accessFlags)), "|"));
 
                 int superclassIndex = dexFile.getBuffer().readOptionalUint(out.getCursor());
                 out.annotate(4, "superclass_idx = %s",
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CodeItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CodeItem.java
index 904a9fc..be3868e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CodeItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/CodeItem.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.ReferenceType;
 import com.android.tools.smali.dexlib2.VerificationError;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.instruction.DexBackedInstruction;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.iface.instruction.FieldOffsetInstruction;
@@ -55,8 +56,7 @@
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
 import com.android.tools.smali.util.ExceptionWithContext;
 import com.android.tools.smali.util.NumberUtils;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
+import com.android.tools.smali.util.StringUtils;
 import com.android.tools.smali.dexlib2.dexbacked.CDexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
@@ -134,7 +134,7 @@
 
             @Override
             protected PreInstructionInfo annotatePreInstructionFields(
-                    @Nonnull AnnotatedBytes out, @Nonnull DexReader reader, @Nullable String itemIdentity) {
+                    @Nonnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, @Nullable String itemIdentity) {
                 int sizeFields = reader.readUshort();
 
                 int triesCount = (sizeFields >> CDEX_TRIES_SIZE_SHIFT) & 0xf;
@@ -267,7 +267,7 @@
         }
 
         protected PreInstructionInfo annotatePreInstructionFields(
-                @Nonnull AnnotatedBytes out, @Nonnull DexReader reader, @Nullable String itemIdentity) {
+                @Nonnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, @Nullable String itemIdentity) {
 
             int registers = reader.readUshort();
             out.annotate(2, "registers_size = %d", registers);
@@ -296,7 +296,7 @@
 
         protected void annotateInstructions(
                 @Nonnull AnnotatedBytes out,
-                @Nonnull DexReader reader,
+                @Nonnull DexReader<? extends DexBuffer> reader,
                 int instructionSize) {
 
             out.annotate(0, "instructions:");
@@ -353,7 +353,7 @@
         }
 
         protected void annotatePostInstructionFields(@Nonnull AnnotatedBytes out,
-                                                     @Nonnull DexReader reader,
+                                                     @Nonnull DexReader<? extends DexBuffer> reader,
                                                      int triesCount) {
             if (triesCount > 0) {
                 if ((reader.getOffset() % 4) != 0) {
@@ -435,7 +435,7 @@
         @Override
         public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
             try {
-                DexReader reader = dexFile.getBuffer().readerAt(out.getCursor());
+                DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor());
 
                 PreInstructionInfo info = annotatePreInstructionFields(out, reader, itemIdentity);
                 annotateInstructions(out, reader, info.instructionSize);
@@ -454,7 +454,7 @@
         }
 
         private void annotateInstruction35c(@Nonnull AnnotatedBytes out, @Nonnull Instruction35c instruction) {
-            List<String> args = Lists.newArrayList();
+            List<String> args = new ArrayList<>();
 
             int registerCount = instruction.getRegisterCount();
             if (registerCount == 1) {
@@ -480,7 +480,7 @@
             }
 
             out.annotate(6, String.format("%s {%s}, %s",
-                    instruction.getOpcode().name, Joiner.on(", ").join(args), instruction.getReference()));
+                    instruction.getOpcode().name, StringUtils.join(args, ", "), instruction.getReference()));
         }
 
         private void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) {
@@ -492,7 +492,7 @@
         }
 
         private void annotateDefaultInstruction(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) {
-            List<String> args = Lists.newArrayList();
+            List<String> args = new ArrayList<>();
 
             if (instruction instanceof OneRegisterInstruction) {
                 args.add(formatRegister(((OneRegisterInstruction)instruction).getRegisterA()));
@@ -554,7 +554,7 @@
             }
 
             out.annotate(instruction.getCodeUnits()*2, "%s %s",
-                    instruction.getOpcode().name, Joiner.on(", ").join(args));
+                    instruction.getOpcode().name, StringUtils.join(args, ", "));
         }
 
         private void annotateArrayPayload(@Nonnull AnnotatedBytes out, @Nonnull ArrayPayload instruction) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/DebugInfoItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/DebugInfoItem.java
index 9b435ac..ea506bc 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/DebugInfoItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/DebugInfoItem.java
@@ -31,6 +31,7 @@
 package com.android.tools.smali.dexlib2.dexbacked.raw;
 
 import com.android.tools.smali.dexlib2.DebugItemType;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
@@ -49,7 +50,7 @@
 
             @Override
             public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
-                DexReader reader = dexFile.getBuffer().readerAt(out.getCursor());
+                DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor());
 
                 int lineStart = reader.readBigUleb128();
                 out.annotateTo(reader.getOffset(), "line_start = %d", lineStart & 0xFFFFFFFFL);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedArrayItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedArrayItem.java
index 8ea8182..a367941 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedArrayItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedArrayItem.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.raw;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
@@ -47,7 +48,7 @@
 
             @Override
             protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
-                DexReader reader = dexFile.getBuffer().readerAt(out.getCursor());
+                DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor());
                 EncodedValue.annotateEncodedArray(dexFile, out, reader);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedValue.java
index 0280153..6b7f339 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/EncodedValue.java
@@ -31,6 +31,7 @@
 package com.android.tools.smali.dexlib2.dexbacked.raw;
 
 import com.android.tools.smali.dexlib2.ValueType;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.value.DexBackedEncodedValue;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -42,7 +43,7 @@
     public static void annotateEncodedValue(
             @Nonnull DexBackedDexFile dexFile,
             @Nonnull AnnotatedBytes out,
-            @Nonnull DexReader reader) {
+            @Nonnull DexReader<? extends DexBuffer> reader) {
         int valueArgType = reader.readUbyte();
 
         int valueArg = valueArgType >>> 5;
@@ -91,7 +92,7 @@
     public static void annotateEncodedAnnotation(
             @Nonnull DexBackedDexFile dexFile,
             @Nonnull AnnotatedBytes out,
-            @Nonnull DexReader reader) {
+            @Nonnull DexReader<? extends DexBuffer> reader) {
         assert out.getCursor() == reader.getOffset();
 
         int typeIndex = reader.readSmallUleb128();
@@ -117,7 +118,7 @@
     public static void annotateEncodedArray(
             @Nonnull DexBackedDexFile dexFile,
             @Nonnull AnnotatedBytes out,
-            @Nonnull DexReader reader) {
+            @Nonnull DexReader<? extends DexBuffer> reader) {
         assert out.getCursor() == reader.getOffset();
 
         int size = reader.readSmallUleb128();
@@ -133,15 +134,16 @@
         }
     }
 
-    public static String asString(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public static String asString(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         int valueArgType = reader.readUbyte();
 
         int valueArg = valueArgType >>> 5;
         int valueType = valueArgType & 0x1f;
+        int intValue;
 
         switch (valueType) {
             case ValueType.BYTE:
-                int intValue = reader.readByte();
+                intValue = reader.readByte();
                 return String.format("0x%x", intValue);
             case ValueType.SHORT:
                 intValue = reader.readSizedInt(valueArg+1);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/SectionAnnotator.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/SectionAnnotator.java
index 7d52559..720f4b6 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/SectionAnnotator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/SectionAnnotator.java
@@ -33,11 +33,12 @@
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AlignmentUtils;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.HashMap;
 import java.util.Map;
 
 public abstract class SectionAnnotator {
@@ -47,7 +48,7 @@
     public final int sectionOffset;
     public final int itemCount;
 
-    protected Map<Integer, String> itemIdentities = Maps.newHashMap();
+    protected Map<Integer, String> itemIdentities = new HashMap<>();
 
     public SectionAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) {
         this.annotator = annotator;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/StringDataItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/StringDataItem.java
index 9e30f75..144b998 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/StringDataItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/StringDataItem.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.raw;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
 import com.android.tools.smali.util.StringUtils;
@@ -48,7 +49,7 @@
 
             @Override
             protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
-                DexReader reader = dexFile.getBuffer().readerAt(out.getCursor());
+                DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor());
                 int utf16Length = reader.readSmallUleb128();
                 out.annotateTo(reader.getOffset(), "utf16_size = %d", utf16Length);
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/util/DexAnnotator.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/util/DexAnnotator.java
index 55a68fa..5f219f6 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/util/DexAnnotator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/util/DexAnnotator.java
@@ -55,9 +55,7 @@
 import com.android.tools.smali.dexlib2.dexbacked.raw.TypeIdItem;
 import com.android.tools.smali.dexlib2.dexbacked.raw.TypeListItem;
 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
-import com.google.common.primitives.Ints;
+
 import com.android.tools.smali.dexlib2.dexbacked.CDexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 
@@ -65,15 +63,17 @@
 import javax.annotation.Nullable;
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Arrays;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 public class DexAnnotator extends AnnotatedBytes {
     @Nonnull public final DexBackedDexFile dexFile;
 
-    private final Map<Integer, SectionAnnotator> annotators = Maps.newHashMap();
-    private static final Map<Integer, Integer> sectionAnnotationOrder = Maps.newHashMap();
+    private final Map<Integer, SectionAnnotator> annotators = new HashMap<>();
+    private static final Map<Integer, Integer> sectionAnnotationOrder = new HashMap<>();
 
     static {
         int[] sectionOrder = new int[] {
@@ -189,13 +189,14 @@
     public void writeAnnotations(Writer out) throws IOException {
         List<MapItem> mapItems = dexFile.getMapItems();
         // sort the map items based on the order defined by sectionAnnotationOrder
-        Ordering<MapItem> ordering = Ordering.from(new Comparator<MapItem>() {
+        Comparator<MapItem> comparator = new Comparator<MapItem>() {
             @Override public int compare(MapItem o1, MapItem o2) {
-                return Ints.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType()));
+                return Integer.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType()));
             }
-        });
+        };
 
-        mapItems = ordering.immutableSortedCopy(mapItems);
+        MapItem[] mapItemsArray = mapItems.toArray(new MapItem[mapItems.size()]);
+        Arrays.sort(mapItemsArray, comparator);
 
         try {
             // Need to annotate the debug info offset table first, to propagate the debug info identities
@@ -204,7 +205,7 @@
                 CdexDebugOffsetTable.annotate(this, dexFile.getBuffer());
             }
 
-            for (MapItem mapItem: mapItems) {
+            for (MapItem mapItem: mapItemsArray) {
                 try {
                     SectionAnnotator annotator = annotators.get(mapItem.getType());
                     annotator.annotateSection(this);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedCallSiteReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedCallSiteReference.java
index 23224a1..a7a6925 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedCallSiteReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedCallSiteReference.java
@@ -32,7 +32,6 @@
 
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.collect.Lists;
 import com.android.tools.smali.dexlib2.base.reference.BaseCallSiteReference;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.util.EncodedArrayItemIterator;
@@ -44,6 +43,8 @@
 import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue;
 
 import javax.annotation.Nonnull;
+
+import java.util.ArrayList;
 import java.util.List;
 
 public class DexBackedCallSiteReference extends BaseCallSiteReference {
@@ -124,7 +125,7 @@
     @Nonnull
     @Override
     public List<? extends EncodedValue> getExtraArguments() {
-        List<EncodedValue> values = Lists.newArrayList();
+        List<EncodedValue> values = new ArrayList<>();
 
         EncodedArrayItemIterator iter = getCallSiteIterator();
         if (iter.getItemCount() < 3) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java
index 1855aeb..ac7593b 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodProtoReference.java
@@ -30,7 +30,6 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.reference;
 
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodProtoReference;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.raw.ProtoIdItem;
@@ -38,6 +37,8 @@
 import com.android.tools.smali.dexlib2.dexbacked.util.FixedSizeList;
 
 import javax.annotation.Nonnull;
+
+import java.util.Collections;
 import java.util.List;
 
 public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
@@ -67,7 +68,7 @@
                 @Override public int size() { return parameterCount; }
             };
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     @Nonnull
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodReference.java
index a9ae9dc..1910e8d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedMethodReference.java
@@ -30,7 +30,6 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.reference;
 
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.raw.MethodIdItem;
@@ -39,6 +38,8 @@
 import com.android.tools.smali.dexlib2.dexbacked.util.FixedSizeList;
 
 import javax.annotation.Nonnull;
+
+import java.util.Collections;
 import java.util.List;
 
 public class DexBackedMethodReference extends BaseMethodReference {
@@ -84,7 +85,7 @@
                 @Override public int size() { return parameterCount; }
             };
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     @Nonnull
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedStringReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedStringReference.java
index a7ac23b..8594cfb 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedStringReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/reference/DexBackedStringReference.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.base.reference.BaseStringReference;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 import com.android.tools.smali.dexlib2.dexbacked.raw.StringIdItem;
 
@@ -64,7 +65,7 @@
         //add the string data length:
         int stringOffset = dexFile.getStringSection().getOffset(stringIndex);
         int stringDataOffset = dexFile.getBuffer().readSmallUint(stringOffset);
-        DexReader reader = dexFile.getDataBuffer().readerAt(stringDataOffset);
+        DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(stringDataOffset);
         size += reader.peekSmallUleb128Size();
         int utf16Length = reader.readSmallUleb128();
         //and string data itself:
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/AnnotationsDirectory.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/AnnotationsDirectory.java
index 987b92c..1a25253 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/AnnotationsDirectory.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/AnnotationsDirectory.java
@@ -30,19 +30,19 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.util;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedAnnotation;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 
 import javax.annotation.Nonnull;
+
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
 public abstract class AnnotationsDirectory {
     public static final AnnotationsDirectory EMPTY = new AnnotationsDirectory() {
         @Override public int getFieldAnnotationCount() { return 0; }
-        @Nonnull @Override public Set<? extends DexBackedAnnotation> getClassAnnotations() { return ImmutableSet.of(); }
+        @Nonnull @Override public Set<? extends DexBackedAnnotation> getClassAnnotations() { return Collections.emptySet(); }
         @Nonnull @Override public AnnotationIterator getFieldAnnotationIterator() { return AnnotationIterator.EMPTY; }
         @Nonnull @Override public AnnotationIterator getMethodAnnotationIterator() { return AnnotationIterator.EMPTY; }
         @Nonnull @Override public AnnotationIterator getParameterAnnotationIterator() {return AnnotationIterator.EMPTY;}
@@ -111,7 +111,7 @@
             };
         }
 
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 
     @Nonnull
@@ -132,7 +132,7 @@
                 @Override public int size() { return size; }
             };
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     private static class AnnotationsDirectoryImpl extends AnnotationsDirectory {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/DebugInfo.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/DebugInfo.java
index 2868446..303c377 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/DebugInfo.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/DebugInfo.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.AccessFlags;
 import com.android.tools.smali.dexlib2.DebugItemType;
+import com.android.tools.smali.dexlib2.dexbacked.*;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
 import com.android.tools.smali.dexlib2.immutable.debug.ImmutableEndLocal;
 import com.android.tools.smali.dexlib2.immutable.debug.ImmutableEpilogueBegin;
@@ -40,12 +41,7 @@
 import com.android.tools.smali.dexlib2.immutable.debug.ImmutableRestartLocal;
 import com.android.tools.smali.dexlib2.immutable.debug.ImmutableSetSourceFile;
 import com.android.tools.smali.dexlib2.immutable.debug.ImmutableStartLocal;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterators;
-import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
-import com.android.tools.smali.dexlib2.dexbacked.DexBackedMethod;
-import com.android.tools.smali.dexlib2.dexbacked.DexBackedMethodImplementation;
-import com.android.tools.smali.dexlib2.dexbacked.DexReader;
+import com.android.tools.smali.util.IteratorUtils;
 import com.android.tools.smali.dexlib2.iface.debug.DebugItem;
 import com.android.tools.smali.dexlib2.iface.debug.EndLocal;
 import com.android.tools.smali.dexlib2.iface.debug.LocalInfo;
@@ -53,6 +49,7 @@
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 
 public abstract class DebugInfo implements Iterable<DebugItem> {
@@ -63,7 +60,7 @@
      *               field, and will
      * @return An iterator that yields the parameter names as strings
      */
-    @Nonnull public abstract Iterator<String> getParameterNames(@Nullable DexReader reader);
+    @Nonnull public abstract Iterator<String> getParameterNames(@Nullable DexReader<? extends DexBuffer> reader);
 
     /**
      * Calculate and return the private size of debuginfo.
@@ -85,11 +82,11 @@
         private EmptyDebugInfo() {}
 
         @Nonnull @Override public Iterator<DebugItem> iterator() {
-            return ImmutableSet.<DebugItem>of().iterator();
+            return Collections.emptyIterator();
         }
 
-        @Nonnull @Override public Iterator<String> getParameterNames(@Nullable DexReader reader) {
-            return ImmutableSet.<String>of().iterator();
+        @Nonnull @Override public Iterator<String> getParameterNames(@Nullable DexReader<? extends DexBuffer> reader) {
+            return Collections.emptyIterator();
         }
 
         @Override
@@ -120,14 +117,14 @@
         @Nonnull
         @Override
         public Iterator<DebugItem> iterator() {
-            DexReader reader = dexFile.getDataBuffer().readerAt(debugInfoOffset);
+            DexReader<? extends DexBuffer> reader = dexFile.getDataBuffer().readerAt(debugInfoOffset);
             final int lineNumberStart = reader.readBigUleb128();
             int registerCount = methodImpl.getRegisterCount();
             // Debug information can have events for addresses past the instructions.
             // They have no relevance for the method in question and are excluded from the iterator.
             final int lastInstructionAddress =
                 methodImpl.getInstructionsSize()
-                    - Iterators.getLast(methodImpl.getInstructions().iterator()).getCodeUnits();
+                    - IteratorUtils.getLast(methodImpl.getInstructions().iterator()).getCodeUnits();
 
             //TODO: does dalvik allow references to invalid registers?
             final LocalInfo[] locals = new LocalInfo[registerCount];
@@ -182,7 +179,7 @@
                 private int lineNumber = lineNumberStart;
 
                 @Nullable
-                protected DebugItem readNextItem(@Nonnull DexReader reader) {
+                protected DebugItem readNextItem(@Nonnull DexReader<? extends DexBuffer> reader) {
                     while (codeAddress <= lastInstructionAddress) {
                         int next = reader.readUbyte();
                         switch (next) {
@@ -295,7 +292,7 @@
 
         @Nonnull
         @Override
-        public VariableSizeIterator<String> getParameterNames(@Nullable DexReader reader) {
+        public VariableSizeIterator<String> getParameterNames(@Nullable DexReader<? extends DexBuffer> reader) {
             if (reader == null) {
                 reader = dexFile.getDataBuffer().readerAt(debugInfoOffset);
                 reader.skipUleb128();
@@ -303,7 +300,7 @@
             //TODO: make sure dalvik doesn't allow more parameter names than we have parameters
             final int parameterNameCount = reader.readSmallUleb128();
             return new VariableSizeIterator<String>(reader, parameterNameCount) {
-                @Override protected String readNextItem(@Nonnull DexReader reader, int index) {
+                @Override protected String readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                     return dexFile.getStringSection().getOptional(reader.readSmallUleb128() - 1);
                 }
             };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/EncodedArrayItemIterator.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/EncodedArrayItemIterator.java
index 9313943..b6f9fd2 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/EncodedArrayItemIterator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/EncodedArrayItemIterator.java
@@ -31,6 +31,7 @@
 package com.android.tools.smali.dexlib2.dexbacked.util;
 
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 import com.android.tools.smali.dexlib2.dexbacked.value.DexBackedEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
@@ -60,7 +61,7 @@
     }
 
     private static class EncodedArrayItemIteratorImpl extends EncodedArrayItemIterator {
-        @Nonnull private final DexReader reader;
+        @Nonnull private final DexReader<? extends DexBuffer> reader;
         @Nonnull private final DexBackedDexFile dexFile;
         private final int size;
         private int index = 0;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/ParameterIterator.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/ParameterIterator.java
index bd4d9e7..349495b 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/ParameterIterator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/ParameterIterator.java
@@ -33,10 +33,11 @@
 import com.android.tools.smali.dexlib2.base.BaseMethodParameter;
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -66,7 +67,7 @@
         if (parameterAnnotations.hasNext()) {
             annotations = parameterAnnotations.next();
         } else {
-            annotations = ImmutableSet.of();
+            annotations = Collections.emptySet();
         }
 
         if (parameterNames.hasNext()) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeCollection.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeCollection.java
index c4b5af5..4870a8d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeCollection.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeCollection.java
@@ -47,14 +47,14 @@
         this.size = size;
     }
 
-    protected abstract T readNextItem(@Nonnull DexReader reader, int index);
+    protected abstract T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index);
 
     @Override
     @Nonnull
     public VariableSizeIterator<T> iterator() {
         return new VariableSizeIterator<T>(buffer, offset, size) {
             @Override
-            protected T readNextItem(@Nonnull DexReader reader, int index) {
+            protected T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                 return VariableSizeCollection.this.readNextItem(reader, index);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeIterator.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeIterator.java
index c5c5989..708a545 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeIterator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeIterator.java
@@ -38,7 +38,7 @@
 import java.util.NoSuchElementException;
 
 public abstract class VariableSizeIterator<T> implements Iterator<T> {
-    @Nonnull private final DexReader reader;
+    @Nonnull private final DexReader<? extends DexBuffer> reader;
     protected final int size;
 
     private int index;
@@ -48,7 +48,7 @@
         this.size = size;
     }
 
-    protected VariableSizeIterator(@Nonnull DexReader reader, int size) {
+    protected VariableSizeIterator(@Nonnull DexReader<? extends DexBuffer> reader, int size) {
         this.reader = reader;
         this.size = size;
     }
@@ -60,7 +60,7 @@
      * @param index The index of the item being read. This is guaranteed to be less than {@code size}
      * @return The item that was read
      */
-    protected abstract T readNextItem(@Nonnull DexReader reader, int index);
+    protected abstract T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index);
 
     public int getReaderOffset() {
         return reader.getOffset();
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeList.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeList.java
index b1b467a..3973e57 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeList.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeList.java
@@ -47,7 +47,7 @@
         this.size = size;
     }
 
-    protected abstract T readNextItem(@Nonnull DexReader reader, int index);
+    protected abstract T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index);
 
     @Override
     @Nonnull
@@ -62,7 +62,7 @@
     public VariableSizeListIterator<T> listIterator(int index) {
         VariableSizeListIterator<T> iterator = new VariableSizeListIterator<T>(buffer, offset, size) {
             @Override
-            protected T readNextItem(@Nonnull DexReader reader, int index) {
+            protected T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                 return VariableSizeList.this.readNextItem(reader, index);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java
index 36e4b42..7dfc1f9 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeLookaheadIterator.java
@@ -30,31 +30,83 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.util;
 
-import com.google.common.collect.AbstractIterator;
 import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Iterator;
+import java.util.NoSuchElementException;
 
-public abstract class VariableSizeLookaheadIterator<T> extends AbstractIterator<T> implements Iterator<T> {
-    @Nonnull private final DexReader reader;
+public abstract class VariableSizeLookaheadIterator<T> implements Iterator<T> {
+    /** We have computed the next element and haven't returned it yet. */
+    private static final int STATE_READY = 1;
+
+    /** We haven't yet computed or have already returned the element. */
+    private static final int STATE_NOT_READY = 2;
+
+    /** We have reached the end of the data and are finished. */
+    private static final int STATE_DONE = 3;
+
+    /** We've suffered an exception and are kaputt. */
+    private static final int STATE_FAILED = 4;
+
+    private int state = STATE_NOT_READY;
+    private T next;
+    @Nonnull
+    private final DexReader<? extends DexBuffer> reader;
 
     protected VariableSizeLookaheadIterator(@Nonnull DexBuffer buffer, int offset) {
         this.reader = buffer.readerAt(offset);
     }
 
+    protected final T endOfData() {
+        state = STATE_DONE;
+        return null;
+    }
+
+    @Override
+    public final boolean hasNext() {
+        switch (state) {
+            case STATE_DONE:
+                return false;
+            case STATE_READY:
+                return true;
+            default:
+        }
+        return tryToComputeNext();
+    }
+
+    private boolean tryToComputeNext() {
+        state = STATE_FAILED; // temporary pessimism
+        next = computeNext();
+        if (state != STATE_DONE) {
+            state = STATE_READY;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public final T next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        state = STATE_NOT_READY;
+        T result = next;
+        next = null;
+        return result;
+    }
+
     /**
-     * Reads the next item from reader. If the end of the list has been reached, it should call endOfData.
-     *
-     * endOfData has a return value of T, so you can simply {@code return endOfData()}
+     * Reads the next item from reader. If the end of the list has been reached, it should call
+     * endOfData. endOfData has a return value of T, so you can simply {@code return endOfData()}
      *
      * @return The item that was read. If endOfData was called, the return value is ignored.
      */
-    @Nullable protected abstract T readNextItem(@Nonnull DexReader reader);
+    @Nullable
+    protected abstract T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader);
 
-    @Override
     protected T computeNext() {
         return readNextItem(reader);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeSet.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeSet.java
index 36af102..85a8227 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeSet.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/util/VariableSizeSet.java
@@ -47,14 +47,14 @@
         this.size = size;
     }
 
-    protected abstract T readNextItem(@Nonnull DexReader reader, int index);
+    protected abstract T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index);
 
     @Override
     @Nonnull
     public VariableSizeIterator<T> iterator() {
         return new VariableSizeIterator<T>(buffer, offset, size) {
             @Override
-            protected T readNextItem(@Nonnull DexReader reader, int index) {
+            protected T readNextItem(@Nonnull DexReader<? extends DexBuffer> reader, int index) {
                 return VariableSizeSet.this.readNextItem(reader, index);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedAnnotationEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedAnnotationEncodedValue.java
index 5660128..341d73d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedAnnotationEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedAnnotationEncodedValue.java
@@ -33,6 +33,7 @@
 import com.android.tools.smali.dexlib2.base.value.BaseAnnotationEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedAnnotationElement;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 import com.android.tools.smali.dexlib2.dexbacked.util.VariableSizeSet;
 import com.android.tools.smali.dexlib2.iface.value.AnnotationEncodedValue;
@@ -46,7 +47,7 @@
     private final int elementCount;
     private final int elementsOffset;
 
-    public DexBackedAnnotationEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public DexBackedAnnotationEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         this.dexFile = dexFile;
         this.type = dexFile.getTypeSection().get(reader.readSmallUleb128());
         this.elementCount = reader.readSmallUleb128();
@@ -54,13 +55,13 @@
         skipElements(reader, elementCount);
     }
 
-    public static void skipFrom(@Nonnull DexReader reader) {
+    public static void skipFrom(@Nonnull DexReader<? extends DexBuffer> reader) {
         reader.skipUleb128(); // type
         int elementCount = reader.readSmallUleb128();
         skipElements(reader, elementCount);
     }
 
-    private static void skipElements(@Nonnull DexReader reader, int elementCount) {
+    private static void skipElements(@Nonnull DexReader<? extends DexBuffer> reader, int elementCount) {
         for (int i=0; i<elementCount; i++) {
             reader.skipUleb128();
             DexBackedEncodedValue.skipFrom(reader);
@@ -75,7 +76,7 @@
         return new VariableSizeSet<DexBackedAnnotationElement>(dexFile.getDataBuffer(), elementsOffset, elementCount) {
             @Nonnull
             @Override
-            protected DexBackedAnnotationElement readNextItem(@Nonnull DexReader dexReader, int index) {
+            protected DexBackedAnnotationElement readNextItem(@Nonnull DexReader<? extends DexBuffer> dexReader, int index) {
                 return new DexBackedAnnotationElement(dexFile, dexReader);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedArrayEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedArrayEncodedValue.java
index bd1d851..4df35e7 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedArrayEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedArrayEncodedValue.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.base.value.BaseArrayEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 import com.android.tools.smali.dexlib2.dexbacked.util.VariableSizeList;
 import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue;
@@ -45,19 +46,19 @@
     private final int elementCount;
     private final int encodedArrayOffset;
 
-    public DexBackedArrayEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public DexBackedArrayEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         this.dexFile = dexFile;
         this.elementCount = reader.readSmallUleb128();
         this.encodedArrayOffset = reader.getOffset();
         skipElementsFrom(reader, elementCount);
     }
 
-    public static void skipFrom(@Nonnull DexReader reader) {
+    public static void skipFrom(@Nonnull DexReader<? extends DexBuffer> reader) {
         int elementCount = reader.readSmallUleb128();
         skipElementsFrom(reader, elementCount);
     }
 
-    private static void skipElementsFrom(@Nonnull DexReader reader, int elementCount) {
+    private static void skipElementsFrom(@Nonnull DexReader<? extends DexBuffer> reader, int elementCount) {
         for (int i=0; i<elementCount; i++) {
             DexBackedEncodedValue.skipFrom(reader);
         }
@@ -69,7 +70,7 @@
         return new VariableSizeList<EncodedValue>(dexFile.getDataBuffer(), encodedArrayOffset, elementCount) {
             @Nonnull
             @Override
-            protected EncodedValue readNextItem(@Nonnull DexReader dexReader, int index) {
+            protected EncodedValue readNextItem(@Nonnull DexReader<? extends DexBuffer> dexReader, int index) {
                 return DexBackedEncodedValue.readFrom(dexFile, dexReader);
             }
         };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEncodedValue.java
index 39fbea3..a21e9ca 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEncodedValue.java
@@ -31,6 +31,7 @@
 package com.android.tools.smali.dexlib2.dexbacked.value;
 
 import com.android.tools.smali.dexlib2.ValueType;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue;
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableByteEncodedValue;
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableCharEncodedValue;
@@ -50,7 +51,7 @@
 
 public abstract class DexBackedEncodedValue {
     @Nonnull
-    public static EncodedValue readFrom(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader) {
+    public static EncodedValue readFrom(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader) {
         int startOffset = reader.getOffset();
 
         try {
@@ -123,7 +124,7 @@
         }
     }
 
-    public static void skipFrom(@Nonnull DexReader reader) {
+    public static void skipFrom(@Nonnull DexReader<? extends DexBuffer> reader) {
         int startOffset = reader.getOffset();
 
         try {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEnumEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEnumEncodedValue.java
index 91da14c..b5e2a76 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEnumEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedEnumEncodedValue.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.value;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedFieldReference;
 import com.android.tools.smali.dexlib2.base.value.BaseEnumEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -42,7 +43,7 @@
     @Nonnull public final DexBackedDexFile dexFile;
     private final int fieldIndex;
 
-    public DexBackedEnumEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+    public DexBackedEnumEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         fieldIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedFieldEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedFieldEncodedValue.java
index 6836265..2e6a2f8 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedFieldEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedFieldEncodedValue.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.value;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedFieldReference;
 import com.android.tools.smali.dexlib2.base.value.BaseFieldEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -42,7 +43,8 @@
     @Nonnull public final DexBackedDexFile dexFile;
     private final int fieldIndex;
 
-    public DexBackedFieldEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+    public DexBackedFieldEncodedValue(@Nonnull DexBackedDexFile dexFile,
+                                      @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         fieldIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodEncodedValue.java
index 6e94191..3207f0e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodEncodedValue.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.value;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodReference;
 import com.android.tools.smali.dexlib2.base.value.BaseMethodEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -42,7 +43,8 @@
     @Nonnull public final DexBackedDexFile dexFile;
     private final int methodIndex;
 
-    public DexBackedMethodEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+    public DexBackedMethodEncodedValue(@Nonnull DexBackedDexFile dexFile,
+                                       @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         methodIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodHandleEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodHandleEncodedValue.java
index 5708f8e..78c7451 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodHandleEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodHandleEncodedValue.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.value;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodHandleReference;
 import com.android.tools.smali.dexlib2.base.value.BaseMethodHandleEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -43,7 +44,7 @@
     private final int methodHandleIndex;
 
     public DexBackedMethodHandleEncodedValue(
-            @Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+            @Nonnull DexBackedDexFile dexFile, @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         this.methodHandleIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodTypeEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodTypeEncodedValue.java
index 4f8b1a6..f0d28d6 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodTypeEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedMethodTypeEncodedValue.java
@@ -30,6 +30,7 @@
 
 package com.android.tools.smali.dexlib2.dexbacked.value;
 
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodProtoReference;
 import com.android.tools.smali.dexlib2.base.value.BaseMethodTypeEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -42,7 +43,8 @@
     @Nonnull public final DexBackedDexFile dexFile;
     private final int methodProtoIndex;
 
-    public DexBackedMethodTypeEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+    public DexBackedMethodTypeEncodedValue(@Nonnull DexBackedDexFile dexFile,
+                                           @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         this.methodProtoIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedStringEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedStringEncodedValue.java
index de46765..755de8a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedStringEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedStringEncodedValue.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.base.value.BaseStringEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 
 import javax.annotation.Nonnull;
@@ -40,7 +41,8 @@
     @Nonnull public final DexBackedDexFile dexFile;
     private final int stringIndex;
 
-    public DexBackedStringEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+    public DexBackedStringEncodedValue(@Nonnull DexBackedDexFile dexFile,
+                                       @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         stringIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedTypeEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedTypeEncodedValue.java
index 3c582b6..16506cb 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedTypeEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/value/DexBackedTypeEncodedValue.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.base.value.BaseTypeEncodedValue;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
+import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
 import com.android.tools.smali.dexlib2.dexbacked.DexReader;
 
 import javax.annotation.Nonnull;
@@ -40,7 +41,8 @@
     @Nonnull public final DexBackedDexFile dexFile;
     private final int typeIndex;
 
-    public DexBackedTypeEncodedValue(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, int valueArg) {
+    public DexBackedTypeEncodedValue(@Nonnull DexBackedDexFile dexFile,
+                                     @Nonnull DexReader<? extends DexBuffer> reader, int valueArg) {
         this.dexFile = dexFile;
         typeIndex = reader.readSizedSmallUint(valueArg + 1);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/DexUtil.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/DexUtil.java
index 6c70a3e..9bbfc11 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/DexUtil.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/DexUtil.java
@@ -30,12 +30,12 @@
 
 package com.android.tools.smali.dexlib2.util;
 
-import com.google.common.io.ByteStreams;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile.NotADexFile;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedOdexFile.NotAnOdexFile;
 import com.android.tools.smali.dexlib2.dexbacked.raw.CdexHeaderItem;
 import com.android.tools.smali.dexlib2.dexbacked.raw.HeaderItem;
 import com.android.tools.smali.dexlib2.dexbacked.raw.OdexHeaderItem;
+import com.android.tools.smali.util.InputStreamUtil;
 
 import javax.annotation.Nonnull;
 import java.io.EOFException;
@@ -62,7 +62,7 @@
         inputStream.mark(44);
         byte[] partialHeader = new byte[44];
         try {
-            ByteStreams.readFully(inputStream, partialHeader);
+            InputStreamUtil.readFully(inputStream, partialHeader);
         } catch (EOFException ex) {
             throw new NotADexFile("File is too short");
         } finally {
@@ -160,7 +160,7 @@
         inputStream.mark(8);
         byte[] partialHeader = new byte[8];
         try {
-            ByteStreams.readFully(inputStream, partialHeader);
+            InputStreamUtil.readFully(inputStream, partialHeader);
         } catch (EOFException ex) {
             throw new NotAnOdexFile("File is too short");
         } finally {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java
index 757955b..205ca2f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java
@@ -374,11 +374,10 @@
                         @Nonnull DeferredOutputStreamFactory tempFactory) throws IOException {
         try {
             int dataSectionOffset = getDataSectionOffset();
-            DexDataWriter headerWriter = outputAt(dest, 0);
-            DexDataWriter indexWriter = outputAt(dest, HeaderItem.ITEM_SIZE);
-            DexDataWriter offsetWriter = outputAt(dest, dataSectionOffset);
 
-            try {
+            try (DexDataWriter headerWriter = outputAt(dest, 0);
+                 DexDataWriter indexWriter = outputAt(dest, HeaderItem.ITEM_SIZE);
+                 DexDataWriter offsetWriter = outputAt(dest, dataSectionOffset)) {
                 writeStrings(indexWriter, offsetWriter);
                 writeTypes(indexWriter);
                 writeTypeLists(offsetWriter);
@@ -387,25 +386,19 @@
                 writeMethods(indexWriter);
 
                 // encoded arrays depend on method handles..
-                DexDataWriter methodHandleWriter = outputAt(dest, indexWriter.getPosition() +
+                try (DexDataWriter methodHandleWriter = outputAt(dest, indexWriter.getPosition() +
                         classSection.getItemCount() * ClassDefItem.ITEM_SIZE +
-                        callSiteSection.getItemCount() * CallSiteIdItem.ITEM_SIZE);
-                try {
+                        callSiteSection.getItemCount() * CallSiteIdItem.ITEM_SIZE)) {
                     writeMethodHandles(methodHandleWriter);
-                } finally {
-                    methodHandleWriter.close();
                 }
 
                 // call sites depend on encoded arrays..
                 writeEncodedArrays(offsetWriter);
 
                 // class defs depend on method handles and call sites..
-                DexDataWriter callSiteWriter = outputAt(dest, indexWriter.getPosition() +
-                        classSection.getItemCount() * ClassDefItem.ITEM_SIZE);
-                try {
+                try (DexDataWriter callSiteWriter = outputAt(dest, indexWriter.getPosition() +
+                        classSection.getItemCount() * ClassDefItem.ITEM_SIZE)) {
                     writeCallSites(callSiteWriter);
-                } finally {
-                    callSiteWriter.close();
                 }
 
                 writeAnnotations(offsetWriter);
@@ -417,10 +410,6 @@
 
                 writeMapItem(offsetWriter);
                 writeHeader(headerWriter, dataSectionOffset, offsetWriter.getPosition());
-            } finally {
-                headerWriter.close();
-                indexWriter.close();
-                offsetWriter.close();
             }
             updateSignature(dest);
             updateChecksum(dest);
@@ -576,7 +565,7 @@
         hiddenApiRestrictionsOffset = offsetWriter.getPosition();
 
         List<Map.Entry<? extends ClassKey, Integer>> classEntriesValueSorted = Lists.newArrayList(classSection.getItems());
-        Collections.sort(classEntriesValueSorted, DexWriter.comparableValueComparator());
+        classEntriesValueSorted.sort(DexWriter.comparableValueComparator());
         RestrictionsWriter restrictionsWriter = new RestrictionsWriter(dataStore, offsetWriter, classEntriesValueSorted.size());
 
         try {
@@ -677,15 +666,9 @@
         }
 
         public void close() throws IOException {
-            DexDataWriter writer = null;
             offsetsWriter.close();
-            try {
-                writer = outputAt(dataStore, startOffset);
+            try (DexDataWriter writer = outputAt(dataStore, startOffset)) {
                 writer.writeInt(restrictionsWriter.getPosition() - startOffset);
-            } finally {
-                if (writer != null) {
-                    writer.close();
-                }
             }
         }
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java b/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java
new file mode 100644
index 0000000..ed8eab1
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import java.lang.Iterable;
+import java.util.Iterator;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/**
+ * Combines two iterators into a single iterator. The returned iterator iterates across the elements
+ * in {@code a}, followed by the elements in {@code b}. The source iterators are not polled until
+ * necessary.
+ * <p>
+ * The returned iterator does not support {@code remove()}.
+ */
+public class ChainedIterator<T extends @Nullable Object> implements Iterator<T>, Iterable<T> {
+    Iterator<T> iteratorA;
+    Iterator<T> iteratorB;
+
+    public ChainedIterator(Iterable<T> iterableA, Iterable<T> iterableB) {
+        this.iteratorA = iterableA.iterator();
+        this.iteratorB = iterableB.iterator();
+    }
+
+    @Override
+    public final boolean hasNext() {
+        return iteratorA.hasNext() || iteratorB.hasNext();
+    }
+
+    @Override
+    public final T next() {
+        if (iteratorA.hasNext()) {
+            return iteratorA.next();
+        }
+        return iteratorB.next();
+    }
+
+    @Override
+    public final void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Iterator<T> iterator() {
+        return this;
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java
index 75bf7f9..2fe222a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java
@@ -32,13 +32,13 @@
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Ordering;
-import com.google.common.primitives.Ints;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.SortedSet;
+
 import javax.annotation.Nonnull;
 
 public class CollectionUtils {
@@ -64,7 +64,7 @@
 
     public static <T extends Comparable<? super T>> int compareAsList(@Nonnull Collection<? extends T> list1,
                                                                       @Nonnull Collection<? extends T> list2) {
-        int res = Ints.compare(list1.size(), list2.size());
+        int res = Integer.compare(list1.size(), list2.size());
         if (res != 0) return res;
         Iterator<? extends T> elements2 = list2.iterator();
         for (T element1: list1) {
@@ -114,7 +114,7 @@
     public static <T> int compareAsList(@Nonnull Comparator<? super T> elementComparator,
                                         @Nonnull Collection<? extends T> list1,
                                         @Nonnull Collection<? extends T> list2) {
-        int res = Ints.compare(list1.size(), list2.size());
+        int res = Integer.compare(list1.size(), list2.size());
         if (res != 0) return res;
         Iterator<? extends T> elements2 = list2.iterator();
         for (T element1: list1) {
@@ -139,7 +139,7 @@
         if (it instanceof SortedSet) {
             SortedSet<? extends T> sortedSet = (SortedSet<? extends T>)it;
             Comparator<?> comparator = sortedSet.comparator();
-            return (comparator == null) || comparator.equals(Ordering.natural());
+            return (comparator == null) || comparator.equals(NaturalOrdering.INSTANCE);
         }
         return false;
     }
@@ -150,7 +150,7 @@
             SortedSet<? extends T> sortedSet = (SortedSet<? extends T>)it;
             Comparator<?> comparator = sortedSet.comparator();
             if (comparator == null) {
-                return elementComparator.equals(Ordering.natural());
+                return elementComparator.equals(NaturalOrdering.INSTANCE);
             }
             return elementComparator.equals(comparator);
         }
@@ -162,7 +162,8 @@
         if (isNaturalSortedSet(collection)) {
             return (SortedSet<? extends T>)collection;
         }
-        return ImmutableSortedSet.copyOf(collection);
+        SortedSet<? extends T> sortedSet = ArraySortedSet.of(NaturalOrdering.INSTANCE, collection.toArray());
+        return Collections.unmodifiableSortedSet(sortedSet);
     }
 
     @Nonnull
@@ -175,6 +176,7 @@
                 return sortedSet;
             }
         }
+
         return ImmutableSortedSet.copyOf(elementComparator, collection);
     }
 
@@ -191,7 +193,7 @@
 
     public static <T extends Comparable<T>> int compareAsSet(@Nonnull Collection<? extends T> set1,
                                                              @Nonnull Collection<? extends T> set2) {
-        int res = Ints.compare(set1.size(), set2.size());
+        int res = Integer.compare(set1.size(), set2.size());
         if (res != 0) return res;
 
         SortedSet<? extends T> sortedSet1 = toNaturalSortedSet(set1);
@@ -208,7 +210,7 @@
     public static <T> int compareAsSet(@Nonnull Comparator<? super T> elementComparator,
                                        @Nonnull Collection<? extends T> list1,
                                        @Nonnull Collection<? extends T> list2) {
-        int res = Ints.compare(list1.size(), list2.size());
+        int res = Integer.compare(list1.size(), list2.size());
         if (res != 0) return res;
 
         SortedSet<? extends T> set1 = toSortedSet(elementComparator, list1);
@@ -221,4 +223,34 @@
         }
         return 0;
     }
+
+    public static <T> Comparator<? super T> usingToStringOrdering() {
+        return UsingToStringOrdering.INSTANCE;
+    }
+
+    public static <T> Comparator<? super T> naturalOrdering() {
+        return NaturalOrdering.INSTANCE;
+    }
+
+    public final static class UsingToStringOrdering<T extends Object> implements Comparator<T> {
+        static final UsingToStringOrdering INSTANCE = new UsingToStringOrdering();
+
+        @Override
+        public int compare(Object left, Object right) {
+            return left.toString().compareTo(right.toString());
+        }
+
+        private UsingToStringOrdering() {}
+    }
+
+    public final static class NaturalOrdering<T extends Comparable<? super T>> implements Comparator<T> {
+        static final NaturalOrdering INSTANCE = new NaturalOrdering();
+
+        @Override
+        public int compare(T left, T right) {
+            return left.compareTo(right);
+        }
+
+        private NaturalOrdering() {}
+    }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java b/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java
new file mode 100644
index 0000000..46f696a
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java
@@ -0,0 +1,262 @@
+
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import java.io.DataInput;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Queue;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Utility methods for working with {@link InputStream}. Based on guava ByteStreams.
+ */
+public final class InputStreamUtil {
+
+    private static final int BUFFER_SIZE = 8192;
+
+    /** Max array length on JVM. */
+    private static final int MAX_ARRAY_LEN = Integer.MAX_VALUE - 8;
+
+    /** Large enough to never need to expand, given the geometric progression of buffer sizes. */
+    private static final int TO_BYTE_ARRAY_DEQUE_SIZE = 20;
+
+    /**
+     * Reads all bytes from an input stream into a byte array. Does not close the stream.
+     *
+     * @param in the input stream to read from
+     * @return a byte array containing all the bytes from the stream
+     * @throws IOException if an I/O error occurs
+     */
+    public static byte[] toByteArray(InputStream in) throws IOException {
+        int totalLen = 0;
+        ArrayDeque<byte[]> bufs = new ArrayDeque<byte[]>(TO_BYTE_ARRAY_DEQUE_SIZE);
+
+        // Roughly size to match what has been read already. Some file systems, such as procfs,
+        // return 0
+        // as their length. These files are very small, so it's wasteful to allocate an 8KB buffer.
+        int initialBufferSize = min(BUFFER_SIZE, max(128, Integer.highestOneBit(totalLen) * 2));
+        // Starting with an 8k buffer, double the size of each successive buffer. Smaller buffers
+        // quadruple in size until they reach 8k, to minimize the number of small reads for longer
+        // streams. Buffers are retained in a deque so that there's no copying between buffers while
+        // reading and so all of the bytes in each new allocated buffer are available for reading
+        // from
+        // the stream.
+        for (int bufSize = initialBufferSize; totalLen < MAX_ARRAY_LEN; bufSize = 
+                saturatedMultiply(bufSize, bufSize < 4096 ? 4 : 2)) {
+            byte[] buf = new byte[min(bufSize, MAX_ARRAY_LEN - totalLen)];
+            bufs.add(buf);
+            int off = 0;
+            while (off < buf.length) {
+                // always OK to fill buf; its size plus the rest of bufs is never more than
+                // MAX_ARRAY_LEN
+                int r = in.read(buf, off, buf.length - off);
+                if (r == -1) {
+                    return combineBuffers(bufs, totalLen);
+                }
+                off += r;
+                totalLen += r;
+            }
+        }
+
+        // read MAX_ARRAY_LEN bytes without seeing end of stream
+        if (in.read() == -1) {
+            // oh, there's the end of the stream
+            return combineBuffers(bufs, MAX_ARRAY_LEN);
+        } else {
+            throw new OutOfMemoryError("input is too large to fit in a byte array");
+        }
+    }
+
+    private static int saturatedMultiply(int a, int b) {
+        long value = (long) a * b;
+        if (value > Integer.MAX_VALUE) {
+            return Integer.MAX_VALUE;
+          }
+          if (value < Integer.MIN_VALUE) {
+            return Integer.MIN_VALUE;
+          }
+          return (int) value;
+    }
+
+    private static byte[] combineBuffers(Queue<byte[]> bufs, int totalLen) {
+        if (bufs.isEmpty()) {
+            return new byte[0];
+        }
+        byte[] result = bufs.remove();
+        if (result.length == totalLen) {
+            return result;
+        }
+        int remaining = totalLen - result.length;
+        result = Arrays.copyOf(result, totalLen);
+        while (remaining > 0) {
+            byte[] buf = bufs.remove();
+            int bytesToCopy = min(remaining, buf.length);
+            int resultOffset = totalLen - remaining;
+            System.arraycopy(buf, 0, result, resultOffset, bytesToCopy);
+            remaining -= bytesToCopy;
+        }
+        return result;
+    }
+
+    /**
+     * Discards {@code n} bytes of data from the input stream. This method will block until the full
+     * amount has been skipped. Does not close the stream.
+     *
+     * @param in the input stream to read from
+     * @param n the number of bytes to skip
+     * @throws EOFException if this stream reaches the end before skipping all the bytes
+     * @throws IOException if an I/O error occurs, or the stream does not support skipping
+     */
+    public static void skipFully(InputStream in, long n) throws IOException {
+        long skipped = skipUpTo(in, n);
+        if (skipped < n) {
+            throw new EOFException(
+                    "reached end of stream after skipping " + skipped + " bytes; " + n
+                            + " bytes expected");
+        }
+    }
+
+    /**
+     * Discards up to {@code n} bytes of data from the input stream. This method will block until
+     * either the full amount has been skipped or until the end of the stream is reached, whichever
+     * happens first. Returns the total number of bytes skipped.
+     */
+    static long skipUpTo(InputStream in, long n) throws IOException {
+        long totalSkipped = 0;
+        // A buffer is allocated if skipSafely does not skip any bytes.
+        byte[] buf = null;
+
+        while (totalSkipped < n) {
+            long remaining = n - totalSkipped;
+            long skipped = skipSafely(in, remaining);
+
+            if (skipped == 0) {
+                // Do a buffered read since skipSafely could return 0 repeatedly, for example if
+                // in.available() always returns 0 (the default).
+                int skip = (int) Math.min(remaining, BUFFER_SIZE);
+                if (buf == null) {
+                    // Allocate a buffer bounded by the maximum size that can be requested, for
+                    // example an array of BUFFER_SIZE is unnecessary when the value of remaining
+                    // is smaller.
+                    buf = new byte[skip];
+                }
+                if ((skipped = in.read(buf, 0, skip)) == -1) {
+                    // Reached EOF
+                    break;
+                }
+            }
+
+            totalSkipped += skipped;
+        }
+
+        return totalSkipped;
+    }
+
+    /**
+     * Attempts to skip up to {@code n} bytes from the given input stream, but not more than {@code
+     * in.available()} bytes. This prevents {@code FileInputStream} from skipping more bytes than
+     * actually remain in the file, something that it {@linkplain java.io.FileInputStream#skip(long)
+     * specifies} it can do in its Javadoc despite the fact that it is violating the contract of
+     * {@code InputStream.skip()}.
+     */
+    private static long skipSafely(InputStream in, long n) throws IOException {
+        int available = in.available();
+        return available == 0 ? 0 : in.skip(Math.min(available, n));
+    }
+
+    /**
+     * Attempts to read enough bytes from the stream to fill the given byte array, with the same
+     * behavior as {@link DataInput#readFully(byte[])}. Does not close the stream.
+     *
+     * @param in the input stream to read from.
+     * @param b the buffer into which the data is read.
+     * @throws EOFException if this stream reaches the end before reading all the bytes.
+     * @throws IOException if an I/O error occurs.
+     */
+    public static void readFully(@Nonnull InputStream in, @Nonnull byte[] b) throws IOException {
+        int read = read(in, b, 0, b.length);
+        if (read != b.length) {
+            throw new EOFException(
+                    "reached end of stream after reading " + read + " bytes; " + b.length
+                            + " bytes expected");
+        }
+    }
+
+    /**
+     * Reads some bytes from an input stream and stores them into the buffer array {@code b}. This
+     * method blocks until {@code len} bytes of input data have been read into the array, or end of
+     * file is detected. The number of bytes read is returned, possibly zero. Does not close the
+     * stream.
+     * <p>
+     * A caller can detect EOF if the number of bytes read is less than {@code len}. All subsequent
+     * calls on the same stream will return zero.
+     * <p>
+     * If {@code b} is null, a {@code NullPointerException} is thrown. If {@code off} is negative,
+     * or {@code len} is negative, or {@code off+len} is greater than the length of the array {@code
+     * b}, then an {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then no
+     * bytes are read. Otherwise, the first byte read is stored into element {@code b[off]}, the
+     * next one into {@code b[off+1]}, and so on. The number of bytes read is, at most, equal to
+     * {@code len}.
+     *
+     * @param in the input stream to read from
+     * @param b the buffer into which the data is read
+     * @param off an int specifying the offset into the data
+     * @param len an int specifying the number of bytes to read
+     * @return the number of bytes read
+     * @throws IOException if an I/O error occurs
+     * @throws IndexOutOfBoundsException if {@code off} is negative, if {@code len} is negative, or
+     *             if {@code off + len} is greater than {@code b.length}
+     */
+    public static int read(@Nonnull InputStream in, @Nonnull byte[] b, int off, int len) throws IOException {
+        if (off < 0 || len < 0 || off + len > b.length) {
+            throw new IndexOutOfBoundsException("trying to read invalid offset/length range");
+        }
+
+        int total = 0;
+        while (total < len) {
+            int result = in.read(b, off + total, len - total);
+            if (result == -1) {
+                break;
+            }
+            total += result;
+        }
+        return total;
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java
new file mode 100644
index 0000000..6f6c857
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import java.util.Iterator;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+public final class IteratorUtils {
+
+    public static <T extends @Nullable Object> T getLast(Iterator<T> iterator) {
+        while (true) {
+            T current = iterator.next();
+            if (!iterator.hasNext()) {
+                return current;
+            }
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java
index 4c567d1..730caa8 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java
@@ -33,6 +33,8 @@
 import com.android.tools.smali.dexlib2.formatter.DexFormattedWriter;
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Iterator;
+import java.util.List;
 
 public class StringUtils {
 
@@ -122,4 +124,17 @@
 
         return sb.toString();
     }
+
+    public static String join(List<? extends Object> parts, String separator) {
+        StringBuilder builder = new StringBuilder();
+        Iterator<? extends Object> it = parts.iterator();
+        if (it.hasNext()) {
+            builder.append(it.hasNext());
+        }
+        while (it.hasNext()) {
+            builder.append(separator);
+            builder.append(it.next());
+        }
+        return builder.toString();
+    }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java b/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java
new file mode 100644
index 0000000..bf89ea9
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import java.util.Iterator;
+import java.util.function.Function;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/**
+ * An iterator that will return the results of applying {@code transformFunction} to each element of
+ * {@code backingIterator}.
+ * <p>
+ * The returned iterator supports {@code remove()} if {@code backingIterator} does.
+ */
+public class TransformedIterator<F extends @Nullable Object, T extends @Nullable Object>
+        implements Iterator<T> {
+    final Iterator<? extends F> backingIterator;
+    final Function<F, T> transformFunction;
+
+    public TransformedIterator(Iterator<? extends F> backingIterator,
+            Function<F, T> transformFunction) {
+        this.backingIterator = backingIterator;
+        this.transformFunction = transformFunction;
+    }
+
+    @Override
+    public final boolean hasNext() {
+        return backingIterator.hasNext();
+    }
+
+    @Override
+    public final T next() {
+        return transformFunction.apply(backingIterator.next());
+    }
+
+    @Override
+    public final void remove() {
+        backingIterator.remove();
+    }
+}
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/AccessorTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/AccessorTest.java
index a53cf83..ac63ac1 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/AccessorTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/AccessorTest.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2;
 
 import com.google.common.collect.ImmutableMap;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.DexFile;
 import com.android.tools.smali.dexlib2.iface.Method;
@@ -41,6 +40,7 @@
 import com.android.tools.smali.dexlib2.iface.reference.FieldReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 import com.android.tools.smali.dexlib2.util.SyntheticAccessorResolver;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/CommonSuperclassTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/CommonSuperclassTest.java
index 6d4c015..95d4309 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/CommonSuperclassTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/CommonSuperclassTest.java
@@ -32,10 +32,10 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.Opcodes;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.immutable.ImmutableDexFile;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/util/SuperclassChainTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/util/SuperclassChainTest.java
index df8502d..f228fd4 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/util/SuperclassChainTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/analysis/util/SuperclassChainTest.java
@@ -33,13 +33,13 @@
 import com.android.tools.smali.dexlib2.analysis.TestUtils;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.Opcodes;
 import com.android.tools.smali.dexlib2.analysis.ClassPath;
 import com.android.tools.smali.dexlib2.analysis.DexClassProvider;
 import com.android.tools.smali.dexlib2.analysis.TypeProto;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.immutable.ImmutableDexFile;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixGotoTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixGotoTest.java
index f98abd2..9436289 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixGotoTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixGotoTest.java
@@ -30,10 +30,7 @@
 
 package com.android.tools.smali.dexlib2.builder;
 
-import com.android.tools.smali.dexlib2.builder.Label;
-import com.android.tools.smali.dexlib2.builder.MethodImplementationBuilder;
 import com.google.common.collect.Lists;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10t;
 import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10x;
@@ -41,6 +38,7 @@
 import com.android.tools.smali.dexlib2.iface.MethodImplementation;
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
 import com.android.tools.smali.dexlib2.iface.instruction.OffsetInstruction;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.List;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixOffsetsTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixOffsetsTest.java
index 07a4b5d..7e4579a 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixOffsetsTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/builder/FixOffsetsTest.java
@@ -30,10 +30,7 @@
 
 package com.android.tools.smali.dexlib2.builder;
 
-import com.android.tools.smali.dexlib2.builder.Label;
-import com.android.tools.smali.dexlib2.builder.MethodImplementationBuilder;
 import com.google.common.collect.Lists;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10t;
 import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10x;
@@ -44,6 +41,7 @@
 import com.android.tools.smali.dexlib2.iface.debug.LineNumber;
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
 import com.android.tools.smali.dexlib2.iface.instruction.OffsetInstruction;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.List;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexBufferTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexBufferTest.java
index b05333e..0211523 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexBufferTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexBufferTest.java
@@ -30,9 +30,8 @@
 
 package com.android.tools.smali.dexlib2.dexbacked;
 
-import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
-import junit.framework.Assert;
 import com.android.tools.smali.util.ExceptionWithContext;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.nio.ByteBuffer;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderLeb128Test.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderLeb128Test.java
index 3541df8..55c2d2f 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderLeb128Test.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderLeb128Test.java
@@ -30,10 +30,8 @@
 
 package com.android.tools.smali.dexlib2.dexbacked;
 
-import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
-import com.android.tools.smali.dexlib2.dexbacked.DexReader;
-import junit.framework.Assert;
 import com.android.tools.smali.util.ExceptionWithContext;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class BaseDexReaderLeb128Test {
@@ -248,7 +246,7 @@
 
     private void performTest(int expectedValue, byte[] buf, int expectedLength) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSmallUleb128());
         Assert.assertEquals(expectedLength, reader.getOffset());
 
@@ -262,7 +260,7 @@
 
     private void performFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.peekSmallUleb128Size();
             Assert.fail();
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderSleb128Test.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderSleb128Test.java
index 38de921..7c49687 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderSleb128Test.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderSleb128Test.java
@@ -30,10 +30,8 @@
 
 package com.android.tools.smali.dexlib2.dexbacked;
 
-import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
-import com.android.tools.smali.dexlib2.dexbacked.DexReader;
-import junit.framework.Assert;
 import com.android.tools.smali.util.ExceptionWithContext;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class BaseDexReaderSleb128Test {
@@ -255,7 +253,7 @@
 
     private void performTest(int expectedValue, byte[] buf, int expectedLength) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSleb128());
         Assert.assertEquals(expectedLength, reader.getOffset());
 
@@ -265,7 +263,7 @@
 
     private void performFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.peekSleb128Size();
             Assert.fail();
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderTest.java
index dcf70de..8eeb693 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/dexbacked/BaseDexReaderTest.java
@@ -30,10 +30,8 @@
 
 package com.android.tools.smali.dexlib2.dexbacked;
 
-import com.android.tools.smali.dexlib2.dexbacked.DexBuffer;
-import com.android.tools.smali.dexlib2.dexbacked.DexReader;
-import junit.framework.Assert;
 import com.android.tools.smali.util.ExceptionWithContext;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class BaseDexReaderTest {
@@ -69,7 +67,7 @@
 
     private void performSizedIntTest(int expectedValue, byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSizedInt(buf.length));
     }
 
@@ -84,7 +82,7 @@
 
     private void performSizedIntFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.readSizedInt(buf.length);
             Assert.fail();
@@ -124,7 +122,7 @@
 
     private void performSizedSmallUintTest(int expectedValue, byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSizedSmallUint(buf.length));
     }
 
@@ -143,7 +141,7 @@
 
     private void performSizedSmallUintFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.readSizedSmallUint(buf.length);
             Assert.fail();
@@ -194,7 +192,7 @@
 
     private void performSizedRightExtendedIntTest(int expectedValue, byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSizedRightExtendedInt(buf.length));
     }
 
@@ -209,7 +207,7 @@
 
     private void performSizedRightExtendedIntFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.readSizedRightExtendedInt(buf.length);
             Assert.fail();
@@ -303,7 +301,7 @@
 
     private void performSizedRightExtendedLongTest(long expectedValue, byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSizedRightExtendedLong(buf.length));
     }
 
@@ -318,7 +316,7 @@
 
     private void performSizedRightExtendedLongFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.readSizedRightExtendedLong(buf.length);
             Assert.fail();
@@ -412,7 +410,7 @@
 
     private void performSizedLongTest(long expectedValue, byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         Assert.assertEquals(expectedValue, reader.readSizedLong(buf.length));
     }
 
@@ -427,7 +425,7 @@
 
     private void performSizedLongFailureTest(byte[] buf) {
         DexBuffer dexBuf = new DexBuffer(buf);
-        DexReader reader = dexBuf.readerAt(0);
+        DexReader<? extends DexBuffer> reader = dexBuf.readerAt(0);
         try {
             reader.readSizedLong(buf.length);
             Assert.fail();
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/InstructionOffsetMapTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/InstructionOffsetMapTest.java
index 555239a..882fce2 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/InstructionOffsetMapTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/InstructionOffsetMapTest.java
@@ -56,14 +56,13 @@
 import com.android.tools.smali.dexlib2.immutable.instruction.ImmutableInstruction35c;
 import com.android.tools.smali.dexlib2.immutable.instruction.ImmutableInstruction3rc;
 import com.android.tools.smali.dexlib2.immutable.instruction.ImmutableInstruction51l;
-import com.android.tools.smali.dexlib2.util.InstructionOffsetMap;
 import com.google.common.collect.ImmutableList;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation;
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference;
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableTypeReference;
 import com.android.tools.smali.util.ExceptionWithContext;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class InstructionOffsetMapTest {
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexDataWriterTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexDataWriterTest.java
index edc4400..6c869c6 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexDataWriterTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexDataWriterTest.java
@@ -30,9 +30,9 @@
 
 package com.android.tools.smali.dexlib2.writer;
 
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.util.ExceptionWithContext;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterSleb128Test.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterSleb128Test.java
index 1703b38..e2ea6b7 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterSleb128Test.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterSleb128Test.java
@@ -30,7 +30,7 @@
 
 package com.android.tools.smali.dexlib2.writer;
 
-import junit.framework.Assert;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterTest.java
index b4c94e5..b301a33 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterTest.java
@@ -33,7 +33,6 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.AnnotationVisibility;
 import com.android.tools.smali.dexlib2.Opcodes;
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
@@ -49,6 +48,7 @@
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableNullEncodedValue;
 import com.android.tools.smali.dexlib2.writer.io.MemoryDataStore;
 import com.android.tools.smali.dexlib2.writer.pool.DexPool;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterUleb128Test.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterUleb128Test.java
index a66879c..a26e738 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterUleb128Test.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/DexWriterUleb128Test.java
@@ -30,7 +30,7 @@
 
 package com.android.tools.smali.dexlib2.writer;
 
-import junit.framework.Assert;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilderTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilderTest.java
index 64c1da3..f64b26c 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilderTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilderTest.java
@@ -31,11 +31,11 @@
 package com.android.tools.smali.dexlib2.writer.util;
 
 import com.google.common.collect.ImmutableList;
-import junit.framework.Assert;
 import com.android.tools.smali.dexlib2.iface.ExceptionHandler;
 import com.android.tools.smali.dexlib2.iface.TryBlock;
 import com.android.tools.smali.dexlib2.immutable.ImmutableExceptionHandler;
 import com.android.tools.smali.dexlib2.immutable.ImmutableTryBlock;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.List;
diff --git a/dexlib2/src/test/java/com/android/tools/smali/util/AbstractForwardSequentialListTest.java b/dexlib2/src/test/java/com/android/tools/smali/util/AbstractForwardSequentialListTest.java
index 5ea49c5..1b6a8fc 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/util/AbstractForwardSequentialListTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/util/AbstractForwardSequentialListTest.java
@@ -30,8 +30,7 @@
 
 package com.android.tools.smali.util;
 
-import com.android.tools.smali.util.AbstractForwardSequentialList;
-import junit.framework.Assert;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
diff --git a/dexlib2/src/test/java/com/android/tools/smali/util/NumberUtilsTest.java b/dexlib2/src/test/java/com/android/tools/smali/util/NumberUtilsTest.java
index ee401bb..9d8b172 100644
--- a/dexlib2/src/test/java/com/android/tools/smali/util/NumberUtilsTest.java
+++ b/dexlib2/src/test/java/com/android/tools/smali/util/NumberUtilsTest.java
@@ -30,8 +30,7 @@
 
 package com.android.tools.smali.util;
 
-import com.android.tools.smali.util.NumberUtils;
-import junit.framework.Assert;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class NumberUtilsTest {
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 25d3265..d0d403e 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/smali/build.gradle b/smali/build.gradle
index cbc2e7e..fbb6394 100644
--- a/smali/build.gradle
+++ b/smali/build.gradle
@@ -94,13 +94,17 @@
 
 processResources.inputs.property('version', version)
 processResources.expand('version': version)
+processResources.dependsOn('generateGrammarSource')
 
 // Build a separate jar that contains all dependencies
 task fatJar(type: Jar, dependsOn: jar) {
+    dependsOn ':dexlib2:jar'
+    dependsOn ':util:jar'
     from sourceSets.main.output
     from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
 
-    classifier = 'fat'
+    duplicatesStrategy = 'exclude'
+    archiveClassifier = 'fat'
 
     manifest {
         attributes('Main-Class': 'com.android.tools.smali.smali.Main')
@@ -168,5 +172,7 @@
 sourcesJar {
     duplicatesStrategy = DuplicatesStrategy.INCLUDE
 }
+sourcesJar.dependsOn('generateGrammarSource')
+sourcesJar.dependsOn('jflex')
 
 tasks.getByPath(':release').dependsOn(proguard)
diff --git a/smali/src/main/java/com/android/tools/smali/smali/Smali.java b/smali/src/main/java/com/android/tools/smali/smali/Smali.java
index 8094fa9..86c6eb2 100644
--- a/smali/src/main/java/com/android/tools/smali/smali/Smali.java
+++ b/smali/src/main/java/com/android/tools/smali/smali/Smali.java
@@ -31,6 +31,8 @@
 package com.android.tools.smali.smali;
 
 import com.google.common.collect.Lists;
+
+import java.nio.charset.StandardCharsets;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -192,19 +194,17 @@
 
     private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, SmaliOptions options)
             throws Exception {
-        FileInputStream fis = null;
-        try {
-            fis = new FileInputStream(smaliFile);
-            InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
+        try (FileInputStream fis = new FileInputStream(smaliFile)) {
+            InputStreamReader reader = new InputStreamReader(fis, StandardCharsets.UTF_8);
 
             LexerErrorInterface lexer = new smaliFlexLexer(reader, options.apiLevel);
-            ((smaliFlexLexer)lexer).setSourceFile(smaliFile);
-            CommonTokenStream tokens = new CommonTokenStream((TokenSource)lexer);
+            ((smaliFlexLexer) lexer).setSourceFile(smaliFile);
+            CommonTokenStream tokens = new CommonTokenStream((TokenSource) lexer);
 
             if (options.printTokens) {
                 tokens.getTokens();
 
-                for (int i=0; i<tokens.size(); i++) {
+                for (int i = 0; i < tokens.size(); i++) {
                     Token token = tokens.get(i);
                     if (token.getChannel() == smaliParser.HIDDEN) {
                         continue;
@@ -250,26 +250,20 @@
             dexGen.smali_file();
 
             return dexGen.getNumberOfSyntaxErrors() == 0;
-        } finally {
-            if (fis != null) {
-                fis.close();
-            }
         }
     }
 
     private static boolean printTokensForSingleFile(File smaliFile, SmaliOptions options)
             throws Exception {
-        FileInputStream fis = null;
-        try {
-            fis = new FileInputStream(smaliFile);
-            InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
+        try (FileInputStream fis = new FileInputStream(smaliFile)) {
+            InputStreamReader reader = new InputStreamReader(fis, StandardCharsets.UTF_8);
 
             LexerErrorInterface lexer = new smaliFlexLexer(reader, options.apiLevel);
-            ((smaliFlexLexer)lexer).setSourceFile(smaliFile);
-            CommonTokenStream tokens = new CommonTokenStream((TokenSource)lexer);
+            ((smaliFlexLexer) lexer).setSourceFile(smaliFile);
+            CommonTokenStream tokens = new CommonTokenStream((TokenSource) lexer);
             tokens.fill();
 
-            for (int i=0; i<tokens.size(); i++) {
+            for (int i = 0; i < tokens.size(); i++) {
                 Token token = tokens.get(i);
                 if (token.getChannel() == smaliParser.HIDDEN) {
                     continue;
@@ -286,10 +280,6 @@
             System.out.flush();
 
             return lexer.getNumberOfSyntaxErrors() == 0;
-        } finally {
-            if (fis != null) {
-                fis.close();
-            }
         }
     }
 }
diff --git a/smali/src/test/java/com/android/tools/smali/smali/ImplicitReferenceTest.java b/smali/src/test/java/com/android/tools/smali/smali/ImplicitReferenceTest.java
index 68ec59b..d4574b5 100644
--- a/smali/src/test/java/com/android/tools/smali/smali/ImplicitReferenceTest.java
+++ b/smali/src/test/java/com/android/tools/smali/smali/ImplicitReferenceTest.java
@@ -30,10 +30,8 @@
 
 package com.android.tools.smali.smali;
 
-import com.android.tools.smali.smali.SmaliTestUtils;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import junit.framework.Assert;
 import org.antlr.runtime.RecognitionException;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.ValueType;
@@ -49,6 +47,7 @@
 import com.android.tools.smali.dexlib2.iface.value.FieldEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.MethodEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.IOException;
diff --git a/third_party/NOTICE b/third_party/NOTICE
index ef17360..a4068b9 100644
--- a/third_party/NOTICE
+++ b/third_party/NOTICE
@@ -83,6 +83,8 @@
 limitations under the License.
 *******************************************************************************
 
+Various portions of the code are taken from https://github.com/google/guava,
+and are used in accordance with the following license:
 
 Content of http://www.apache.org/licenses/LICENSE-2.0:
 
diff --git a/third_party/baksmali/src/main/java/com/android/tools/smali/baksmali/Baksmali.java b/third_party/baksmali/src/main/java/com/android/tools/smali/baksmali/Baksmali.java
index 7f9d1fe..06299ab 100644
--- a/third_party/baksmali/src/main/java/com/android/tools/smali/baksmali/Baksmali.java
+++ b/third_party/baksmali/src/main/java/com/android/tools/smali/baksmali/Baksmali.java
@@ -40,6 +40,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -160,7 +161,7 @@
             }
 
             BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter(
-                    new FileOutputStream(smaliFile), "UTF8"));
+                    new FileOutputStream(smaliFile), StandardCharsets.UTF_8));
 
             writer = new BaksmaliWriter(
                     bufWriter,
diff --git a/util/src/test/java/com/android/tools/smali/util/ClassFileNameHandlerTest.java b/util/src/test/java/com/android/tools/smali/util/ClassFileNameHandlerTest.java
index de5e3c0..cdc9874 100644
--- a/util/src/test/java/com/android/tools/smali/util/ClassFileNameHandlerTest.java
+++ b/util/src/test/java/com/android/tools/smali/util/ClassFileNameHandlerTest.java
@@ -32,15 +32,16 @@
 
 import com.google.common.base.Strings;
 import com.google.common.io.Files;
-import junit.framework.Assert;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 public class ClassFileNameHandlerTest {
-    private final Charset UTF8 = Charset.forName("UTF-8");
+    private final Charset UTF8 = StandardCharsets.UTF_8;
 
     @Test
     public void test1ByteEncodings() {
diff --git a/util/src/test/java/com/android/tools/smali/util/LinearSearchTest.java b/util/src/test/java/com/android/tools/smali/util/LinearSearchTest.java
index f4519e5..92063a6 100644
--- a/util/src/test/java/com/android/tools/smali/util/LinearSearchTest.java
+++ b/util/src/test/java/com/android/tools/smali/util/LinearSearchTest.java
@@ -30,10 +30,9 @@
 
 package com.android.tools.smali.util;
 
-import com.android.tools.smali.util.LinearSearch;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
-import junit.framework.Assert;
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.List;