OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.javaassertionenabler; | 5 package org.chromium.javaassertionenabler; |
6 | 6 |
| 7 import com.google.common.io.ByteStreams; |
| 8 |
7 import org.objectweb.asm.ClassReader; | 9 import org.objectweb.asm.ClassReader; |
8 import org.objectweb.asm.ClassVisitor; | 10 import org.objectweb.asm.ClassVisitor; |
9 import org.objectweb.asm.ClassWriter; | 11 import org.objectweb.asm.ClassWriter; |
10 import org.objectweb.asm.MethodVisitor; | 12 import org.objectweb.asm.MethodVisitor; |
11 import org.objectweb.asm.Opcodes; | 13 import org.objectweb.asm.Opcodes; |
12 | 14 |
13 import java.io.BufferedInputStream; | 15 import java.io.BufferedInputStream; |
14 import java.io.BufferedOutputStream; | 16 import java.io.BufferedOutputStream; |
15 import java.io.ByteArrayOutputStream; | |
16 import java.io.FileInputStream; | |
17 import java.io.FileOutputStream; | 17 import java.io.FileOutputStream; |
18 import java.io.IOException; | 18 import java.io.IOException; |
19 import java.io.InputStream; | 19 import java.util.Collections; |
20 import java.nio.file.Files; | 20 import java.util.jar.JarEntry; |
21 import java.nio.file.Path; | 21 import java.util.jar.JarFile; |
22 import java.nio.file.Paths; | 22 import java.util.jar.JarOutputStream; |
23 import java.nio.file.StandardCopyOption; | |
24 import java.util.zip.ZipEntry; | |
25 import java.util.zip.ZipInputStream; | |
26 import java.util.zip.ZipOutputStream; | |
27 | 23 |
28 /** | 24 /** |
29 * An application that enables Java ASSERT statements by modifying Java bytecode
. It takes in a JAR | 25 * An application that enables Java ASSERT statements by modifying Java bytecode
. It takes in a JAR |
30 * file, modifies bytecode of classes that use ASSERT, and outputs the bytecode
to a new JAR file. | 26 * file, modifies bytecode of classes that use ASSERT, and outputs the bytecode
to a new JAR file. |
31 */ | 27 */ |
32 class AssertionEnabler { | 28 class AssertionEnabler { |
33 static final String ASSERTION_DISABLED_NAME = "$assertionsDisabled"; | |
34 static final String CLASS_FILE_SUFFIX = ".class"; | 29 static final String CLASS_FILE_SUFFIX = ".class"; |
35 static final String STATIC_INITIALIZER_NAME = "<clinit>"; | 30 static final String STATIC_INITIALIZER_NAME = "<clinit>"; |
36 static final String TEMPORARY_FILE_SUFFIX = ".temp"; | 31 static final String ASSERTION_DISABLED_NAME = "$assertionsDisabled"; |
37 | |
38 static final int BUFFER_SIZE = 16384; | |
39 | 32 |
40 static class AssertionEnablerVisitor extends ClassVisitor { | 33 static class AssertionEnablerVisitor extends ClassVisitor { |
41 AssertionEnablerVisitor(ClassWriter writer) { | 34 AssertionEnablerVisitor(ClassWriter writer) { |
42 super(Opcodes.ASM5, writer); | 35 super(Opcodes.ASM5, writer); |
43 } | 36 } |
44 | 37 |
45 @Override | 38 @Override |
46 public MethodVisitor visitMethod(final int access, final String name, St
ring desc, | 39 public MethodVisitor visitMethod(final int access, final String name, St
ring desc, |
47 String signature, String[] exceptions) { | 40 String signature, String[] exceptions) { |
48 // Patch static initializer. | 41 // Patch static initializer. |
(...skipping 19 matching lines...) Expand all Loading... |
68 } else { | 61 } else { |
69 super.visitFieldInsn(opcode, owner, name, desc); | 62 super.visitFieldInsn(opcode, owner, name, desc); |
70 } | 63 } |
71 } | 64 } |
72 }; | 65 }; |
73 } | 66 } |
74 return super.visitMethod(access, name, desc, signature, exceptions); | 67 return super.visitMethod(access, name, desc, signature, exceptions); |
75 } | 68 } |
76 } | 69 } |
77 | 70 |
78 static byte[] readAllBytes(InputStream inputStream) throws IOException { | 71 static void enableAssertionInJar(String inputJarPath, String outputJarPath)
{ |
79 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | 72 try (JarOutputStream outputStream = new JarOutputStream( |
80 int numRead = 0; | 73 new BufferedOutputStream(new FileOutputStream(outputJarPath))))
{ |
81 byte[] data = new byte[BUFFER_SIZE]; | 74 JarFile jarFile = new JarFile(inputJarPath); |
82 while ((numRead = inputStream.read(data, 0, data.length)) != -1) { | 75 for (JarEntry entry : Collections.list(jarFile.entries())) { |
83 buffer.write(data, 0, numRead); | 76 try (BufferedInputStream inputStream = new BufferedInputStream( |
84 } | 77 jarFile.getInputStream(entry))) { |
| 78 byte[] byteCode = ByteStreams.toByteArray(inputStream); |
85 | 79 |
86 return buffer.toByteArray(); | 80 if (entry.isDirectory() || !entry.getName().endsWith(CLASS_F
ILE_SUFFIX)) { |
87 } | 81 outputStream.putNextEntry(entry); |
88 | 82 outputStream.write(byteCode); |
89 static void enableAssertionInJar(String inputJarPath, String outputJarPath)
{ | 83 outputStream.closeEntry(); |
90 String tempJarPath = outputJarPath + TEMPORARY_FILE_SUFFIX; | 84 continue; |
91 try (ZipInputStream inputStream = new ZipInputStream( | 85 } |
92 new BufferedInputStream(new FileInputStream(inputJarPath))); | 86 ClassReader reader = new ClassReader(byteCode); |
93 ZipOutputStream tempStream = new ZipOutputStream( | 87 ClassWriter writer = new ClassWriter(reader, 0); |
94 new BufferedOutputStream(new FileOutputStream(tempJarPath)))
) { | 88 reader.accept(new AssertionEnablerVisitor(writer), 0); |
95 ZipEntry entry = null; | 89 byte[] patchedByteCode = writer.toByteArray(); |
96 | 90 outputStream.putNextEntry(new JarEntry(entry.getName())); |
97 while ((entry = inputStream.getNextEntry()) != null) { | 91 outputStream.write(patchedByteCode); |
98 byte[] byteCode = readAllBytes(inputStream); | 92 outputStream.closeEntry(); |
99 | |
100 if (entry.isDirectory() || !entry.getName().endsWith(CLASS_FILE_
SUFFIX)) { | |
101 tempStream.putNextEntry(entry); | |
102 tempStream.write(byteCode); | |
103 tempStream.closeEntry(); | |
104 continue; | |
105 } | 93 } |
106 ClassReader reader = new ClassReader(byteCode); | |
107 ClassWriter writer = new ClassWriter(reader, 0); | |
108 reader.accept(new AssertionEnablerVisitor(writer), 0); | |
109 byte[] patchedByteCode = writer.toByteArray(); | |
110 tempStream.putNextEntry(new ZipEntry(entry.getName())); | |
111 tempStream.write(patchedByteCode); | |
112 tempStream.closeEntry(); | |
113 } | 94 } |
114 } catch (IOException e) { | 95 } catch (IOException e) { |
115 throw new RuntimeException(e); | 96 throw new RuntimeException(e); |
116 } | 97 } |
117 | |
118 try { | |
119 Path src = Paths.get(tempJarPath); | |
120 Path dest = Paths.get(outputJarPath); | |
121 Files.move(src, dest, StandardCopyOption.REPLACE_EXISTING); | |
122 } catch (IOException ioException) { | |
123 throw new RuntimeException(ioException); | |
124 } | |
125 } | 98 } |
126 | 99 |
127 public static void main(String[] args) { | 100 public static void main(String[] args) { |
128 if (args.length != 2) { | 101 if (args.length != 2) { |
129 System.out.println("Incorrect number of arguments."); | 102 System.out.println("Incorrect number of arguments."); |
130 System.out.println("Example usage: java_assertion_enabler input.jar
output.jar"); | 103 System.out.println("Example usage: java_assertion_enabler input.jar
output.jar"); |
131 System.exit(-1); | 104 System.exit(-1); |
132 } | 105 } |
133 enableAssertionInJar(args[0], args[1]); | 106 enableAssertionInJar(args[0], args[1]); |
134 } | 107 } |
135 } | 108 } |
OLD | NEW |