Add new experimental dex rewriter functionality
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/AnnotationElementRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/AnnotationElementRewriter.java
new file mode 100644
index 0000000..945f022
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/AnnotationElementRewriter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.BaseAnnotationElement;
+import org.jf.dexlib2.iface.AnnotationElement;
+import org.jf.dexlib2.iface.value.EncodedValue;
+
+import javax.annotation.Nonnull;
+
+public class AnnotationElementRewriter implements Rewriter<AnnotationElement> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public AnnotationElementRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public AnnotationElement rewrite(@Nonnull AnnotationElement annotationElement) {
+        return new RewrittenAnnotationElement(annotationElement);
+    }
+
+    protected class RewrittenAnnotationElement extends BaseAnnotationElement {
+        @Nonnull protected AnnotationElement annotationElement;
+
+        public RewrittenAnnotationElement(@Nonnull AnnotationElement annotationElement) {
+            this.annotationElement = annotationElement;
+        }
+
+        @Nonnull @Override public String getName() {
+            return annotationElement.getName();
+        }
+
+        @Nonnull @Override public EncodedValue getValue() {
+            return rewriters.getEncodedValueRewriter().rewrite(annotationElement.getValue());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/AnnotationRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/AnnotationRewriter.java
new file mode 100644
index 0000000..725d2f2
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/AnnotationRewriter.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.BaseAnnotation;
+import org.jf.dexlib2.iface.Annotation;
+import org.jf.dexlib2.iface.AnnotationElement;
+
+import javax.annotation.Nonnull;
+import java.util.Set;
+
+public class AnnotationRewriter implements Rewriter<Annotation> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public AnnotationRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public Annotation rewrite(@Nonnull Annotation value) {
+        return new RewrittenAnnotation(value);
+    }
+
+    protected class RewrittenAnnotation extends BaseAnnotation {
+        @Nonnull protected Annotation annotation;
+
+        public RewrittenAnnotation(@Nonnull Annotation annotation) {
+            this.annotation = annotation;
+        }
+
+        @Override public int getVisibility() {
+            return annotation.getVisibility();
+        }
+
+        @Override @Nonnull public String getType() {
+            return rewriters.getTypeRewriter().rewrite(annotation.getType());
+        }
+
+        @Override @Nonnull public Set<? extends AnnotationElement> getElements() {
+            return RewriterUtils.rewriteSet(rewriters.getAnnotationElementRewriter(), annotation.getElements());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java
new file mode 100644
index 0000000..ad246e5
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ClassDefRewriter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import com.google.common.collect.Iterators;
+import org.jf.dexlib2.base.reference.BaseTypeReference;
+import org.jf.dexlib2.iface.Annotation;
+import org.jf.dexlib2.iface.ClassDef;
+import org.jf.dexlib2.iface.Field;
+import org.jf.dexlib2.iface.Method;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Iterator;
+import java.util.Set;
+
+public class ClassDefRewriter implements Rewriter<ClassDef> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public ClassDefRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public ClassDef rewrite(@Nonnull ClassDef classDef) {
+        return new RewrittenClassDef(classDef);
+    }
+
+    protected class RewrittenClassDef extends BaseTypeReference implements ClassDef {
+        @Nonnull protected ClassDef classDef;
+
+        public RewrittenClassDef(@Nonnull ClassDef classdef) {
+            this.classDef = classdef;
+        }
+
+        @Override @Nonnull public String getType() {
+            return rewriters.getTypeRewriter().rewrite(classDef.getType());
+        }
+
+        @Override public int getAccessFlags() {
+            return classDef.getAccessFlags();
+        }
+
+        @Override @Nullable public String getSuperclass() {
+            return RewriterUtils.rewriteNullable(rewriters.getTypeRewriter(), classDef.getSuperclass());
+        }
+
+        @Override @Nonnull public Set<String> getInterfaces() {
+            return RewriterUtils.rewriteSet(rewriters.getTypeRewriter(), classDef.getInterfaces());
+        }
+
+        @Override @Nullable public String getSourceFile() {
+            return classDef.getSourceFile();
+        }
+
+        @Override @Nonnull public Set<? extends Annotation> getAnnotations() {
+            return RewriterUtils.rewriteSet(rewriters.getAnnotationRewriter(), classDef.getAnnotations());
+        }
+
+        @Override @Nonnull public Iterable<? extends Field> getStaticFields() {
+            return RewriterUtils.rewriteIterable(rewriters.getFieldRewriter(), classDef.getStaticFields());
+        }
+
+        @Override @Nonnull public Iterable<? extends Field> getInstanceFields() {
+            return RewriterUtils.rewriteIterable(rewriters.getFieldRewriter(), classDef.getInstanceFields());
+        }
+
+        @Nonnull
+        @Override
+        public Iterable<? extends Field> getFields() {
+            return new Iterable<Field>() {
+                @Nonnull
+                @Override
+                public Iterator<Field> iterator() {
+                    return Iterators.concat(getStaticFields().iterator(), getInstanceFields().iterator());
+                }
+            };
+        }
+
+        @Override @Nonnull public Iterable<? extends Method> getDirectMethods() {
+            return RewriterUtils.rewriteIterable(rewriters.getMethodRewriter(), classDef.getDirectMethods());
+        }
+
+        @Override @Nonnull public Iterable<? extends Method> getVirtualMethods() {
+            return RewriterUtils.rewriteIterable(rewriters.getMethodRewriter(), classDef.getVirtualMethods());
+        }
+
+        @Nonnull
+        @Override
+        public Iterable<? extends Method> getMethods() {
+            return new Iterable<Method>() {
+                @Nonnull
+                @Override
+                public Iterator<Method> iterator() {
+                    return Iterators.concat(getDirectMethods().iterator(), getVirtualMethods().iterator());
+                }
+            };
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DebugItemRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DebugItemRewriter.java
new file mode 100644
index 0000000..4fc753a
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DebugItemRewriter.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.DebugItemType;
+import org.jf.dexlib2.iface.debug.*;
+import org.jf.dexlib2.iface.reference.StringReference;
+import org.jf.dexlib2.iface.reference.TypeReference;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class DebugItemRewriter implements Rewriter<DebugItem> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public DebugItemRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public DebugItem rewrite(@Nonnull DebugItem value) {
+        switch (value.getDebugItemType()) {
+            case DebugItemType.START_LOCAL:
+                return new RewrittenStartLocal((StartLocal)value);
+            case DebugItemType.END_LOCAL:
+                return new RewrittenEndLocal((EndLocal)value);
+            case DebugItemType.RESTART_LOCAL:
+                return new RewrittenRestartLocal((RestartLocal)value);
+            default:
+                return value;
+        }
+    }
+
+    protected class BaseRewrittenLocalInfoDebugItem<T extends DebugItem & LocalInfo> implements DebugItem, LocalInfo {
+        @Nonnull protected T debugItem;
+
+        public BaseRewrittenLocalInfoDebugItem (@Nonnull T debugItem) {
+            this.debugItem = debugItem;
+        }
+
+        @Override public int getDebugItemType() {
+            return debugItem.getDebugItemType();
+        }
+
+        @Override public int getCodeAddress() {
+            return debugItem.getCodeAddress();
+        }
+
+        @Override @Nullable public String getName() {
+            return debugItem.getName();
+        }
+
+        @Override @Nullable public String getType() {
+            return RewriterUtils.rewriteNullable(rewriters.getTypeRewriter(), debugItem.getType());
+        }
+
+        @Override @Nullable public String getSignature() {
+            return debugItem.getSignature();
+        }
+    }
+
+    protected class RewrittenStartLocal extends BaseRewrittenLocalInfoDebugItem<StartLocal> implements StartLocal {
+        public RewrittenStartLocal(@Nonnull StartLocal debugItem) {
+            super(debugItem);
+        }
+
+        @Override public int getRegister() {
+            return debugItem.getRegister();
+        }
+
+        @Override @Nullable public StringReference getNameReference() {
+            return debugItem.getNameReference();
+        }
+
+        @Override @Nullable public TypeReference getTypeReference() {
+            TypeReference typeReference = debugItem.getTypeReference();
+            if (typeReference == null) {
+                return null;
+            }
+
+            return RewriterUtils.rewriteTypeReference(rewriters.getTypeRewriter(), typeReference);
+        }
+
+        @Override @Nullable public StringReference getSignatureReference() {
+            return debugItem.getSignatureReference();
+        }
+    }
+
+    protected class RewrittenEndLocal extends BaseRewrittenLocalInfoDebugItem<EndLocal> implements EndLocal {
+        public RewrittenEndLocal(@Nonnull EndLocal instruction) {
+            super(instruction);
+        }
+
+        public int getRegister() {
+            return debugItem.getRegister();
+        }
+    }
+
+    protected class RewrittenRestartLocal extends BaseRewrittenLocalInfoDebugItem<RestartLocal>
+            implements RestartLocal {
+        public RewrittenRestartLocal(@Nonnull RestartLocal instruction) {
+            super(instruction);
+        }
+
+        public int getRegister() {
+            return debugItem.getRegister();
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java
new file mode 100644
index 0000000..e482cd0
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.iface.*;
+import org.jf.dexlib2.iface.debug.DebugItem;
+import org.jf.dexlib2.iface.instruction.Instruction;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.dexlib2.iface.value.EncodedValue;
+
+import javax.annotation.Nonnull;
+import java.util.Set;
+
+/**
+ * Out-of-the box, this class does nothing except make a picture-perfect copy of a dex file.
+ *
+ * However, it provides many points where you can hook into this process and selectively modify
+ * the dex file. For example, If you want to rename all instances (including definitions and references)
+ * of the class Lorg/blah/MyBlah; to Lorg/blah/YourBlah;
+ *
+ * <pre>
+ * {@code
+ * DexRewriter rewriter = new DexRewriter(new RewriterModule() {
+ *     public Rewriter<String> getTypeRewriter(Rewriters rewriters) {
+ *         return new Rewriter<String>() {
+ *             public String rewrite(String value) {
+ *                 if (value.equals("Lorg/blah/MyBlah;")) {
+ *                     return "Lorg/blah/YourBlah;";
+ *                 }
+ *                 return value;
+ *             }
+ *         };
+ *     }
+ * });
+ * DexFile rewrittenDexFile = rewriter.rewriteDexFile(dexFile);
+ * }
+ * </pre>
+ */
+public class DexRewriter implements Rewriters {
+    private final Rewriter<ClassDef> classDefRewriter;
+    private final Rewriter<Field> fieldRewriter;
+    private final Rewriter<Method> methodRewriter;
+    private final Rewriter<MethodParameter> methodParameterRewriter;
+    private final Rewriter<MethodImplementation> methodImplementationRewriter;
+    private final Rewriter<Instruction> instructionRewriter;
+    private final Rewriter<TryBlock<? extends ExceptionHandler>> tryBlockRewriter;
+    private final Rewriter<ExceptionHandler> exceptionHandlerRewriter;
+    private final Rewriter<DebugItem> debugItemRewriter;
+    private final Rewriter<String> typeRewriter;
+    private final Rewriter<FieldReference> fieldReferenceRewriter;
+    private final Rewriter<MethodReference> methodReferenceRewriter;
+    private final Rewriter<Annotation> annotationRewriter;
+    private final Rewriter<AnnotationElement> annotationElementRewriter;
+    private final Rewriter<EncodedValue> encodedValueRewriter;
+
+    public DexRewriter(RewriterModule module) {
+        this.classDefRewriter = module.getClassDefRewriter(this);
+        this.fieldRewriter = module.getFieldRewriter(this);
+        this.methodRewriter = module.getMethodRewriter(this);
+        this.methodParameterRewriter = module.getMethodParameterRewriter(this);
+        this.methodImplementationRewriter = module.getMethodImplementationRewriter(this);
+        this.instructionRewriter = module.getInstructionRewriter(this);
+        this.tryBlockRewriter = module.getTryBlockRewriter(this);
+        this.exceptionHandlerRewriter = module.getExceptionHandlerRewriter(this);
+        this.debugItemRewriter = module.getDebugItemRewriter(this);
+        this.typeRewriter = module.getTypeRewriter(this);
+        this.fieldReferenceRewriter = module.getFieldReferenceRewriter(this);
+        this.methodReferenceRewriter = module.getMethodReferenceRewriter(this);
+        this.annotationRewriter = module.getAnnotationRewriter(this);
+        this.annotationElementRewriter = module.getAnnotationElementRewriter(this);
+        this.encodedValueRewriter = module.getEncodedValueRewriter(this);
+    }
+
+    @Nonnull
+    public DexFile rewriteDexFile(@Nonnull DexFile dexFile) {
+        return new RewrittenDexFile(dexFile);
+    }
+
+    protected class RewrittenDexFile implements DexFile {
+        @Nonnull protected final DexFile dexFile;
+
+        public RewrittenDexFile(@Nonnull DexFile dexFile) {
+            this.dexFile = dexFile;
+        }
+
+        @Override @Nonnull public Set<? extends ClassDef> getClasses() {
+            return RewriterUtils.rewriteSet(getClassDefRewriter(), dexFile.getClasses());
+        }
+    }
+
+    @Nonnull @Override public Rewriter<ClassDef> getClassDefRewriter() { return classDefRewriter; }
+    @Nonnull @Override public Rewriter<Field> getFieldRewriter() { return fieldRewriter; }
+    @Nonnull @Override public Rewriter<Method> getMethodRewriter() { return methodRewriter; }
+    @Nonnull @Override public Rewriter<MethodParameter> getMethodParameterRewriter() { return methodParameterRewriter; }
+    @Nonnull @Override public Rewriter<MethodImplementation> getMethodImplementationRewriter() { return methodImplementationRewriter; }
+    @Nonnull @Override public Rewriter<Instruction> getInstructionRewriter() { return instructionRewriter; }
+    @Nonnull @Override public Rewriter<TryBlock<? extends ExceptionHandler>> getTryBlockRewriter() { return tryBlockRewriter; }
+    @Nonnull @Override public Rewriter<ExceptionHandler> getExceptionHandlerRewriter() { return exceptionHandlerRewriter; }
+    @Nonnull @Override public Rewriter<DebugItem> getDebugItemRewriter() { return debugItemRewriter; }
+    @Nonnull @Override public Rewriter<String> getTypeRewriter() { return typeRewriter; }
+    @Nonnull @Override public Rewriter<FieldReference> getFieldReferenceRewriter() { return fieldReferenceRewriter; }
+    @Nonnull @Override public Rewriter<MethodReference> getMethodReferenceRewriter() { return methodReferenceRewriter; }
+    @Nonnull @Override public Rewriter<Annotation> getAnnotationRewriter() { return annotationRewriter; }
+    @Nonnull @Override public Rewriter<AnnotationElement> getAnnotationElementRewriter() { return annotationElementRewriter; }
+    @Nonnull @Override public Rewriter<EncodedValue> getEncodedValueRewriter() { return encodedValueRewriter; }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/EncodedValueRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/EncodedValueRewriter.java
new file mode 100644
index 0000000..9719dcd
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/EncodedValueRewriter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.ValueType;
+import org.jf.dexlib2.base.value.*;
+import org.jf.dexlib2.iface.AnnotationElement;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.dexlib2.iface.value.*;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Set;
+
+public class EncodedValueRewriter implements Rewriter<EncodedValue> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public EncodedValueRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public EncodedValue rewrite(@Nonnull EncodedValue encodedValue) {
+        switch (encodedValue.getValueType()) {
+            case ValueType.TYPE:
+                return new RewrittenTypeEncodedValue((TypeEncodedValue)encodedValue);
+            case ValueType.FIELD:
+                return new RewrittenFieldEncodedValue((FieldEncodedValue)encodedValue);
+            case ValueType.METHOD:
+                return new RewrittenMethodEncodedValue((MethodEncodedValue)encodedValue);
+            case ValueType.ENUM:
+                return new RewrittenEnumEncodedValue((EnumEncodedValue)encodedValue);
+            case ValueType.ARRAY:
+                return new RewrittenArrayEncodedValue((ArrayEncodedValue)encodedValue);
+            case ValueType.ANNOTATION:
+                return new RewrittenAnnotationEncodedValue((AnnotationEncodedValue)encodedValue);
+            default:
+                return encodedValue;
+        }
+    }
+
+    protected class RewrittenTypeEncodedValue extends BaseTypeEncodedValue {
+        @Nonnull protected TypeEncodedValue typeEncodedValue;
+
+        public RewrittenTypeEncodedValue(@Nonnull TypeEncodedValue typeEncodedValue) {
+            this.typeEncodedValue = typeEncodedValue;
+        }
+
+        @Override @Nonnull public String getValue() {
+            return rewriters.getTypeRewriter().rewrite(typeEncodedValue.getValue());
+        }
+    }
+
+    protected class RewrittenFieldEncodedValue extends BaseFieldEncodedValue {
+        @Nonnull protected FieldEncodedValue fieldEncodedValue;
+
+        public RewrittenFieldEncodedValue(@Nonnull FieldEncodedValue fieldEncodedValue) {
+            this.fieldEncodedValue = fieldEncodedValue;
+        }
+
+        @Override @Nonnull public FieldReference getValue() {
+            return rewriters.getFieldReferenceRewriter().rewrite(fieldEncodedValue.getValue());
+        }
+    }
+
+    protected class RewrittenEnumEncodedValue extends BaseEnumEncodedValue {
+        @Nonnull protected EnumEncodedValue enumEncodedValue;
+
+        public RewrittenEnumEncodedValue(@Nonnull EnumEncodedValue enumEncodedValue) {
+            this.enumEncodedValue = enumEncodedValue;
+        }
+
+        @Override @Nonnull public FieldReference getValue() {
+            return rewriters.getFieldReferenceRewriter().rewrite(enumEncodedValue.getValue());
+        }
+    }
+
+    protected class RewrittenMethodEncodedValue extends BaseMethodEncodedValue {
+        @Nonnull protected MethodEncodedValue methodEncodedValue;
+
+        public RewrittenMethodEncodedValue(@Nonnull MethodEncodedValue methodEncodedValue) {
+            this.methodEncodedValue = methodEncodedValue;
+        }
+
+        @Override @Nonnull public MethodReference getValue() {
+            return rewriters.getMethodReferenceRewriter().rewrite(methodEncodedValue.getValue());
+        }
+    }
+
+    protected class RewrittenArrayEncodedValue extends BaseArrayEncodedValue {
+        @Nonnull protected ArrayEncodedValue arrayEncodedValue;
+
+        public RewrittenArrayEncodedValue(@Nonnull ArrayEncodedValue arrayEncodedValue) {
+            this.arrayEncodedValue = arrayEncodedValue;
+        }
+
+        @Override @Nonnull public List<? extends EncodedValue> getValue() {
+            return RewriterUtils.rewriteList(EncodedValueRewriter.this, arrayEncodedValue.getValue());
+        }
+    }
+
+    protected class RewrittenAnnotationEncodedValue extends BaseAnnotationEncodedValue {
+        @Nonnull protected AnnotationEncodedValue annotationEncodedValue;
+
+        public RewrittenAnnotationEncodedValue(@Nonnull AnnotationEncodedValue annotationEncodedValue) {
+            this.annotationEncodedValue = annotationEncodedValue;
+        }
+
+        @Nonnull @Override public String getType() {
+            return rewriters.getTypeRewriter().rewrite(annotationEncodedValue.getType());
+        }
+
+        @Nonnull @Override public Set<? extends AnnotationElement> getElements() {
+            return RewriterUtils.rewriteSet(rewriters.getAnnotationElementRewriter(),
+                    annotationEncodedValue.getElements());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ExceptionHandlerRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ExceptionHandlerRewriter.java
new file mode 100644
index 0000000..51df68c
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/ExceptionHandlerRewriter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.BaseExceptionHandler;
+import org.jf.dexlib2.iface.ExceptionHandler;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class ExceptionHandlerRewriter implements Rewriter<ExceptionHandler> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public ExceptionHandlerRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public ExceptionHandler rewrite(@Nonnull ExceptionHandler value) {
+        return new RewrittenExceptionHandler(value);
+    }
+
+    protected class RewrittenExceptionHandler extends BaseExceptionHandler {
+        @Nonnull protected ExceptionHandler exceptionHandler;
+
+        public RewrittenExceptionHandler(@Nonnull ExceptionHandler exceptionHandler) {
+            this.exceptionHandler = exceptionHandler;
+        }
+
+        @Override @Nullable public String getExceptionType() {
+            return RewriterUtils.rewriteNullable(rewriters.getTypeRewriter(), exceptionHandler.getExceptionType());
+        }
+
+        @Override public int getHandlerCodeAddress() {
+            return exceptionHandler.getHandlerCodeAddress();
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldReferenceRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldReferenceRewriter.java
new file mode 100644
index 0000000..41b5093
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldReferenceRewriter.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.reference.BaseFieldReference;
+import org.jf.dexlib2.iface.reference.FieldReference;
+
+import javax.annotation.Nonnull;
+
+public class FieldReferenceRewriter implements Rewriter<FieldReference> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public FieldReferenceRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public FieldReference rewrite(@Nonnull FieldReference fieldReference) {
+        return new RewrittenFieldReference(fieldReference);
+    }
+
+    protected class RewrittenFieldReference extends BaseFieldReference {
+        @Nonnull protected FieldReference fieldReference;
+
+        public RewrittenFieldReference(@Nonnull FieldReference fieldReference) {
+            this.fieldReference = fieldReference;
+        }
+
+        @Override @Nonnull public String getDefiningClass() {
+            return rewriters.getTypeRewriter().rewrite(fieldReference.getDefiningClass());
+        }
+
+        @Override @Nonnull public String getName() {
+            return fieldReference.getName();
+        }
+
+        @Override @Nonnull public String getType() {
+            return rewriters.getTypeRewriter().rewrite(fieldReference.getType());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java
new file mode 100644
index 0000000..1e5eb6d
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.reference.BaseFieldReference;
+import org.jf.dexlib2.iface.Annotation;
+import org.jf.dexlib2.iface.Field;
+import org.jf.dexlib2.iface.value.EncodedValue;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Set;
+
+public class FieldRewriter implements Rewriter<Field> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public FieldRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public Field rewrite(@Nonnull Field field) {
+        return new RewrittenField(field);
+    }
+
+    protected class RewrittenField extends BaseFieldReference implements Field {
+        @Nonnull protected Field field;
+
+        public RewrittenField(@Nonnull Field field) {
+            this.field = field;
+        }
+
+        @Override @Nonnull public String getDefiningClass() {
+            return rewriters.getFieldReferenceRewriter().rewrite(field).getDefiningClass();
+        }
+
+        @Override @Nonnull public String getName() {
+            return rewriters.getFieldReferenceRewriter().rewrite(field).getName();
+        }
+
+        @Override @Nonnull public String getType() {
+            return rewriters.getFieldReferenceRewriter().rewrite(field).getType();
+        }
+
+        public int getAccessFlags() {
+            return field.getAccessFlags();
+        }
+
+        @Nullable public EncodedValue getInitialValue() {
+            return RewriterUtils.rewriteNullable(rewriters.getEncodedValueRewriter(), field.getInitialValue());
+        }
+
+        @Nonnull public Set<? extends Annotation> getAnnotations() {
+            return RewriterUtils.rewriteSet(rewriters.getAnnotationRewriter(), field.getAnnotations());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java
new file mode 100644
index 0000000..c7da8ca
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.ReferenceType;
+import org.jf.dexlib2.iface.instruction.Instruction;
+import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
+import org.jf.dexlib2.iface.instruction.formats.*;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.dexlib2.iface.reference.Reference;
+import org.jf.dexlib2.iface.reference.TypeReference;
+
+import javax.annotation.Nonnull;
+
+public class InstructionRewriter implements Rewriter<Instruction> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public InstructionRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public Instruction rewrite(@Nonnull Instruction instruction) {
+        if (instruction instanceof ReferenceInstruction) {
+            switch (instruction.getOpcode().format) {
+                case Format20bc:
+                    return new RewrittenInstruction20bc((Instruction20bc)instruction);
+                case Format21c:
+                    return new RewrittenInstruction21c((Instruction21c)instruction);
+                case Format22c:
+                    return new RewrittenInstruction22c((Instruction22c)instruction);
+                case Format31c:
+                    return new RewrittenInstruction31c((Instruction31c)instruction);
+                case Format35c:
+                    return new RewrittenInstruction35c((Instruction35c)instruction);
+                case Format3rc:
+                    return new RewrittenInstruction3rc((Instruction3rc)instruction);
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+        return instruction;
+    }
+
+    protected class BaseRewrittenReferenceInstruction<T extends ReferenceInstruction>
+            implements ReferenceInstruction {
+        @Nonnull protected T instruction;
+
+        protected BaseRewrittenReferenceInstruction(@Nonnull T instruction) {
+            this.instruction = instruction;
+        }
+
+        @Override @Nonnull public Reference getReference() {
+            switch (getReferenceType()) {
+                case ReferenceType.TYPE:
+                    return RewriterUtils.rewriteTypeReference(rewriters.getTypeRewriter(),
+                            (TypeReference)instruction.getReference());
+                case ReferenceType.FIELD:
+                    return rewriters.getFieldReferenceRewriter().rewrite((FieldReference)instruction.getReference());
+                case ReferenceType.METHOD:
+                    return rewriters.getMethodReferenceRewriter().rewrite((MethodReference)instruction.getReference());
+                case ReferenceType.STRING:
+                    return instruction.getReference();
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        @Override public int getReferenceType() {
+            return instruction.getReferenceType();
+        }
+
+        @Override public Opcode getOpcode() {
+            return instruction.getOpcode();
+        }
+
+        @Override public int getCodeUnits() {
+            return instruction.getCodeUnits();
+        }
+    }
+
+    protected class RewrittenInstruction20bc extends BaseRewrittenReferenceInstruction<Instruction20bc>
+            implements Instruction20bc {
+        public RewrittenInstruction20bc(@Nonnull Instruction20bc instruction) {
+            super(instruction);
+        }
+
+        @Override public int getVerificationError() {
+            return instruction.getVerificationError();
+        }
+    }
+
+    protected class RewrittenInstruction21c extends BaseRewrittenReferenceInstruction<Instruction21c>
+            implements Instruction21c {
+        public RewrittenInstruction21c(@Nonnull Instruction21c instruction) {
+            super(instruction);
+        }
+
+        public int getRegisterA() {
+            return instruction.getRegisterA();
+        }
+    }
+
+    protected class RewrittenInstruction22c extends BaseRewrittenReferenceInstruction<Instruction22c>
+            implements Instruction22c {
+        public RewrittenInstruction22c(@Nonnull Instruction22c instruction) {
+            super(instruction);
+        }
+
+        public int getRegisterA() {
+            return instruction.getRegisterA();
+        }
+
+        public int getRegisterB() {
+            return instruction.getRegisterB();
+        }
+    }
+
+    protected class RewrittenInstruction31c extends BaseRewrittenReferenceInstruction<Instruction31c>
+            implements Instruction31c {
+        public RewrittenInstruction31c(@Nonnull Instruction31c instruction) {
+            super(instruction);
+        }
+
+        public int getRegisterA() {
+            return instruction.getRegisterA();
+        }
+    }
+
+    protected class RewrittenInstruction35c extends BaseRewrittenReferenceInstruction<Instruction35c>
+            implements Instruction35c {
+        public RewrittenInstruction35c(@Nonnull Instruction35c instruction) {
+            super(instruction);
+        }
+
+        public int getRegisterC() {
+            return instruction.getRegisterC();
+        }
+
+        public int getRegisterE() {
+            return instruction.getRegisterE();
+        }
+
+        public int getRegisterG() {
+            return instruction.getRegisterG();
+        }
+
+        public int getRegisterCount() {
+            return instruction.getRegisterCount();
+        }
+
+        public int getRegisterD() {
+            return instruction.getRegisterD();
+        }
+
+        public int getRegisterF() {
+            return instruction.getRegisterF();
+        }
+    }
+
+    protected class RewrittenInstruction3rc extends BaseRewrittenReferenceInstruction<Instruction3rc>
+            implements Instruction3rc {
+        public RewrittenInstruction3rc(@Nonnull Instruction3rc instruction) {
+            super(instruction);
+        }
+
+        public int getStartRegister() {
+            return instruction.getStartRegister();
+        }
+
+        public int getRegisterCount() {
+            return instruction.getRegisterCount();
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodImplementationRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodImplementationRewriter.java
new file mode 100644
index 0000000..4c90e5a
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodImplementationRewriter.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.iface.ExceptionHandler;
+import org.jf.dexlib2.iface.MethodImplementation;
+import org.jf.dexlib2.iface.TryBlock;
+import org.jf.dexlib2.iface.debug.DebugItem;
+import org.jf.dexlib2.iface.instruction.Instruction;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+public class MethodImplementationRewriter implements Rewriter<MethodImplementation> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public MethodImplementationRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public MethodImplementation rewrite(@Nonnull MethodImplementation methodImplementation) {
+        return new RewrittenMethodImplementation(methodImplementation);
+    }
+
+    protected class RewrittenMethodImplementation implements MethodImplementation {
+        @Nonnull protected MethodImplementation methodImplementation;
+
+        public RewrittenMethodImplementation(@Nonnull MethodImplementation methodImplementation) {
+            this.methodImplementation = methodImplementation;
+        }
+
+        @Override public int getRegisterCount() {
+            return methodImplementation.getRegisterCount();
+        }
+
+        @Override @Nonnull public Iterable<? extends Instruction> getInstructions() {
+            return RewriterUtils.rewriteIterable(rewriters.getInstructionRewriter(),
+                    methodImplementation.getInstructions());
+        }
+
+        @Override @Nonnull public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
+            return RewriterUtils.rewriteList(rewriters.getTryBlockRewriter(),
+                    methodImplementation.getTryBlocks());
+        }
+
+        @Override @Nonnull public Iterable<? extends DebugItem> getDebugItems() {
+            return RewriterUtils.rewriteIterable(rewriters.getDebugItemRewriter(),
+                    methodImplementation.getDebugItems());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodParameterRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodParameterRewriter.java
new file mode 100644
index 0000000..1ddc380
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodParameterRewriter.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.BaseMethodParameter;
+import org.jf.dexlib2.iface.Annotation;
+import org.jf.dexlib2.iface.MethodParameter;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Set;
+
+public class MethodParameterRewriter implements Rewriter<MethodParameter> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public MethodParameterRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public MethodParameter rewrite(@Nonnull MethodParameter methodParameter) {
+        return new RewrittenMethodParameter(methodParameter);
+    }
+
+    protected class RewrittenMethodParameter extends BaseMethodParameter {
+        @Nonnull protected MethodParameter methodParameter;
+
+        public RewrittenMethodParameter(@Nonnull MethodParameter methodParameter) {
+            this.methodParameter = methodParameter;
+        }
+
+        @Override @Nonnull public String getType() {
+            return rewriters.getTypeRewriter().rewrite(methodParameter.getType());
+        }
+
+        @Override @Nonnull public Set<? extends Annotation> getAnnotations() {
+            return RewriterUtils.rewriteSet(rewriters.getAnnotationRewriter(), methodParameter.getAnnotations());
+        }
+
+        @Override @Nullable public String getName() {
+            return methodParameter.getName();
+        }
+
+        @Override @Nullable public String getSignature() {
+            return methodParameter.getSignature();
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodReferenceRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodReferenceRewriter.java
new file mode 100644
index 0000000..83a9f9a
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodReferenceRewriter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import org.jf.dexlib2.base.reference.BaseMethodReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+public class MethodReferenceRewriter implements Rewriter<MethodReference> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public MethodReferenceRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public MethodReference rewrite(@Nonnull MethodReference methodReference) {
+        return new RewrittenMethodReference(methodReference);
+    }
+
+    protected class RewrittenMethodReference extends BaseMethodReference {
+        @Nonnull protected MethodReference methodReference;
+
+        public RewrittenMethodReference(@Nonnull MethodReference methodReference) {
+            this.methodReference = methodReference;
+        }
+
+        @Override @Nonnull public String getDefiningClass() {
+            return rewriters.getTypeRewriter().rewrite(methodReference.getDefiningClass());
+        }
+
+        @Override @Nonnull public String getName() {
+            return methodReference.getName();
+        }
+
+        @Override @Nonnull public List<? extends CharSequence> getParameterTypes() {
+            return RewriterUtils.rewriteList(rewriters.getTypeRewriter(),
+                    Lists.transform(methodReference.getParameterTypes(),
+                    new Function<CharSequence, String>() {
+                        @Nonnull @Override public String apply(CharSequence input) {
+                            return input.toString();
+                        }
+                    }));
+        }
+
+        @Override @Nonnull public String getReturnType() {
+            return rewriters.getTypeRewriter().rewrite(methodReference.getReturnType());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java
new file mode 100644
index 0000000..01af6e2
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.reference.BaseMethodReference;
+import org.jf.dexlib2.iface.Annotation;
+import org.jf.dexlib2.iface.Method;
+import org.jf.dexlib2.iface.MethodImplementation;
+import org.jf.dexlib2.iface.MethodParameter;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Set;
+
+public class MethodRewriter implements Rewriter<Method> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public MethodRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public Method rewrite(@Nonnull Method value) {
+        return new RewrittenMethod(value);
+    }
+
+    protected class RewrittenMethod extends BaseMethodReference implements Method {
+        @Nonnull protected Method method;
+
+        public RewrittenMethod(@Nonnull Method method) {
+            this.method = method;
+        }
+
+        @Override @Nonnull public String getDefiningClass() {
+            return rewriters.getMethodReferenceRewriter().rewrite(method).getDefiningClass();
+        }
+
+        @Override @Nonnull public String getName() {
+            return rewriters.getMethodReferenceRewriter().rewrite(method).getName();
+        }
+
+        @Override @Nonnull public List<? extends CharSequence> getParameterTypes() {
+            return rewriters.getMethodReferenceRewriter().rewrite(method).getParameterTypes();
+        }
+
+        @Override @Nonnull public List<? extends MethodParameter> getParameters() {
+            // We can't use the MethodReferenceRewriter to rewrite the parameters, because we would lose
+            // parameter names and annotations. If a method rewrite involves changing parameters, it needs
+            // to be handled here as well as in the MethodReferenceRewriter
+
+            return RewriterUtils.rewriteList(rewriters.getMethodParameterRewriter(), method.getParameters());
+        }
+
+        @Override @Nonnull public String getReturnType() {
+            return rewriters.getMethodReferenceRewriter().rewrite(method).getReturnType();
+        }
+
+        @Override public int getAccessFlags() {
+            return method.getAccessFlags();
+        }
+
+        @Override @Nonnull public Set<? extends Annotation> getAnnotations() {
+            return RewriterUtils.rewriteSet(rewriters.getAnnotationRewriter(), method.getAnnotations());
+        }
+
+        @Override @Nullable public MethodImplementation getImplementation() {
+            return RewriterUtils.rewriteNullable(rewriters.getMethodImplementationRewriter(),
+                    method.getImplementation());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriter.java
new file mode 100644
index 0000000..6fc5334
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import javax.annotation.Nonnull;
+
+public interface Rewriter<T> {
+    @Nonnull
+    T rewrite(@Nonnull T value);
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java
new file mode 100644
index 0000000..2913a67
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.iface.*;
+import org.jf.dexlib2.iface.debug.DebugItem;
+import org.jf.dexlib2.iface.instruction.Instruction;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.dexlib2.iface.value.EncodedValue;
+
+import javax.annotation.Nonnull;
+
+public class RewriterModule {
+    @Nonnull public Rewriter<ClassDef> getClassDefRewriter(@Nonnull Rewriters rewriters) {
+        return new ClassDefRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<Field> getFieldRewriter(@Nonnull Rewriters rewriters) {
+        return new FieldRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<Method> getMethodRewriter(@Nonnull Rewriters rewriters) {
+        return new MethodRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<MethodParameter> getMethodParameterRewriter(@Nonnull Rewriters rewriters) {
+        return new MethodParameterRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<MethodImplementation> getMethodImplementationRewriter(@Nonnull Rewriters rewriters) {
+        return new MethodImplementationRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<Instruction> getInstructionRewriter(@Nonnull Rewriters rewriters) {
+        return new InstructionRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<TryBlock<? extends ExceptionHandler>> getTryBlockRewriter(@Nonnull Rewriters rewriters) {
+        return new TryBlockRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<ExceptionHandler> getExceptionHandlerRewriter(@Nonnull Rewriters rewriters) {
+        return new ExceptionHandlerRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<DebugItem> getDebugItemRewriter(@Nonnull Rewriters rewriters) {
+        return new DebugItemRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<String> getTypeRewriter(@Nonnull Rewriters rewriters) {
+        return new TypeRewriter();
+    }
+
+    @Nonnull public Rewriter<FieldReference> getFieldReferenceRewriter(@Nonnull Rewriters rewriters) {
+        return new FieldReferenceRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<MethodReference> getMethodReferenceRewriter(@Nonnull Rewriters rewriters) {
+        return new MethodReferenceRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<Annotation> getAnnotationRewriter(@Nonnull Rewriters rewriters) {
+        return new AnnotationRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<AnnotationElement> getAnnotationElementRewriter(@Nonnull Rewriters rewriters) {
+        return new AnnotationElementRewriter(rewriters);
+    }
+
+    @Nonnull public Rewriter<EncodedValue> getEncodedValueRewriter(@Nonnull Rewriters rewriters) {
+        return new EncodedValueRewriter(rewriters);
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java
new file mode 100644
index 0000000..d08467a
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.reference.BaseTypeReference;
+import org.jf.dexlib2.iface.reference.TypeReference;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.*;
+
+public class RewriterUtils {
+    @Nullable
+    public static <T> T rewriteNullable(@Nonnull Rewriter<T> rewriter, @Nullable T value) {
+        return value==null?null:rewriter.rewrite(value);
+    }
+
+    public static <T> Set<T> rewriteSet(@Nonnull final Rewriter<T> rewriter,
+                                        @Nonnull final Set<? extends T> set) {
+        return new AbstractSet<T>() {
+            @Nonnull @Override public Iterator<T> iterator() {
+                final Iterator<? extends T> iterator = set.iterator();
+                return new Iterator<T>() {
+                    @Override public boolean hasNext() {
+                        return iterator.hasNext();
+                    }
+
+                    @Override public T next() {
+                        return rewriteNullable(rewriter, iterator.next());
+                    }
+
+                    @Override public void remove() {
+                        iterator.remove();
+                    }
+                };
+            }
+
+            @Override public int size() {
+                return set.size();
+            }
+        };
+    }
+
+    public static <T> List<T> rewriteList(@Nonnull final Rewriter<T> rewriter,
+                                        @Nonnull final List<? extends T> list) {
+        return new AbstractList<T>() {
+            @Override public T get(int i) {
+                return rewriteNullable(rewriter, list.get(i));
+            }
+
+            @Override public int size() {
+                return list.size();
+            }
+        };
+    }
+
+    public static <T> Iterable<T> rewriteIterable(@Nonnull final Rewriter<T> rewriter,
+                                                  @Nonnull final Iterable<? extends T> iterable) {
+        return new Iterable<T>() {
+            @Override public Iterator<T> iterator() {
+                final Iterator<? extends T> iterator = iterable.iterator();
+                return new Iterator<T>() {
+                    @Override public boolean hasNext() {
+                        return iterator.hasNext();
+                    }
+
+                    @Override public T next() {
+                        return rewriteNullable(rewriter, iterator.next());
+                    }
+
+                    @Override public void remove() {
+                        iterator.remove();
+                    }
+                };
+            }
+        };
+    }
+
+    public static TypeReference rewriteTypeReference(@Nonnull final Rewriter<String> typeRewriter,
+                                                     @Nonnull final TypeReference typeReference) {
+        return new BaseTypeReference() {
+            @Nonnull @Override public String getType() {
+                return typeRewriter.rewrite(typeReference.getType());
+            }
+        };
+    }
+}
+
+
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java
new file mode 100644
index 0000000..97fd879
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.iface.*;
+import org.jf.dexlib2.iface.debug.DebugItem;
+import org.jf.dexlib2.iface.instruction.Instruction;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.dexlib2.iface.value.EncodedValue;
+
+import javax.annotation.Nonnull;
+
+public interface Rewriters {
+    @Nonnull Rewriter<ClassDef> getClassDefRewriter();
+    @Nonnull Rewriter<Field> getFieldRewriter();
+
+    @Nonnull Rewriter<Method> getMethodRewriter();
+    @Nonnull Rewriter<MethodParameter> getMethodParameterRewriter();
+    @Nonnull Rewriter<MethodImplementation> getMethodImplementationRewriter();
+    @Nonnull Rewriter<Instruction> getInstructionRewriter();
+    @Nonnull Rewriter<TryBlock<? extends ExceptionHandler>> getTryBlockRewriter();
+    @Nonnull Rewriter<ExceptionHandler> getExceptionHandlerRewriter();
+    @Nonnull Rewriter<DebugItem> getDebugItemRewriter();
+
+    @Nonnull Rewriter<String> getTypeRewriter();
+    @Nonnull Rewriter<FieldReference> getFieldReferenceRewriter();
+    @Nonnull Rewriter<MethodReference> getMethodReferenceRewriter();
+
+    @Nonnull Rewriter<Annotation> getAnnotationRewriter();
+    @Nonnull Rewriter<AnnotationElement> getAnnotationElementRewriter();
+
+    @Nonnull Rewriter<EncodedValue> getEncodedValueRewriter();
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/TryBlockRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/TryBlockRewriter.java
new file mode 100644
index 0000000..43fed10
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/TryBlockRewriter.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import org.jf.dexlib2.base.BaseTryBlock;
+import org.jf.dexlib2.iface.ExceptionHandler;
+import org.jf.dexlib2.iface.TryBlock;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+public class TryBlockRewriter implements Rewriter<TryBlock<? extends ExceptionHandler>> {
+    @Nonnull protected final Rewriters rewriters;
+
+    public TryBlockRewriter(@Nonnull Rewriters rewriters) {
+        this.rewriters = rewriters;
+    }
+
+    @Nonnull @Override public TryBlock<? extends ExceptionHandler> rewrite(
+            @Nonnull TryBlock<? extends ExceptionHandler> tryBlock) {
+        return new RewrittenTryBlock(tryBlock);
+    }
+
+    protected class RewrittenTryBlock extends BaseTryBlock<ExceptionHandler> {
+        @Nonnull protected TryBlock<? extends ExceptionHandler> tryBlock;
+
+        public RewrittenTryBlock(@Nonnull TryBlock<? extends ExceptionHandler> tryBlock) {
+            this.tryBlock = tryBlock;
+        }
+
+        @Override public int getStartCodeAddress() {
+            return tryBlock.getStartCodeAddress();
+        }
+
+        @Override public int getCodeUnitCount() {
+            return tryBlock.getCodeUnitCount();
+        }
+
+        @Override @Nonnull public List<? extends ExceptionHandler> getExceptionHandlers() {
+            return RewriterUtils.rewriteList(rewriters.getExceptionHandlerRewriter(), tryBlock.getExceptionHandlers());
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/TypeRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/TypeRewriter.java
new file mode 100644
index 0000000..9731154
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/TypeRewriter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * 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 Inc. 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 org.jf.dexlib2.rewriter;
+
+import javax.annotation.Nonnull;
+
+public class TypeRewriter implements Rewriter<String> {
+    @Nonnull @Override public String rewrite(@Nonnull String value) {
+        return value;
+    }
+}