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