| 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 |