// Copyright 2017 The Bazel Authors. All rights reserved. // // 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.google.devtools.build.android.desugar; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.collect.Iterators; import com.google.common.collect.UnmodifiableIterator; import com.google.common.io.ByteStreams; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * Test data generator for b/62456849. This class converts methods satisfying the following * conditions to synthetic methods. *
  • The name starts with "lambda$" *
  • Not synthetic */ public class Bug62456849TestDataGenerator { public static void main(String[] args) throws IOException { checkArgument( args.length == 2, "Usage: %s ", Bug62456849TestDataGenerator.class.getName()); Path inputJar = Paths.get(args[0]); checkArgument(Files.isRegularFile(inputJar), "The input jar %s is not a file", inputJar); Path outputJar = Paths.get(args[1]); try (ZipFile inputZip = new ZipFile(inputJar.toFile()); ZipOutputStream outZip = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(outputJar)))) { for (UnmodifiableIterator it = Iterators.forEnumeration(inputZip.entries()); it.hasNext(); ) { ZipEntry entry = it.next(); String entryName = entry.getName(); byte[] content = entryName.endsWith(".class") ? convertClass(inputZip, entry) : readEntry(inputZip, entry); writeToZipFile(outZip, entryName, content); } } } private static void writeToZipFile(ZipOutputStream outZip, String entryName, byte[] content) throws IOException { ZipEntry result = new ZipEntry(entryName); result.setTime(0L); outZip.putNextEntry(result); outZip.write(content); outZip.closeEntry(); } private static byte[] readEntry(ZipFile file, ZipEntry entry) throws IOException { try (InputStream is = file.getInputStream(entry)) { return ByteStreams.toByteArray(is); } } private static byte[] convertClass(ZipFile file, ZipEntry entry) throws IOException { try (InputStream content = file.getInputStream(entry)) { ClassReader reader = new ClassReader(content); ClassWriter writer = new ClassWriter(0); ClassVisitor converter = new ClassVisitor(Opcodes.ASM5, writer) { @Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if (name.startsWith("lambda$") && (access & Opcodes.ACC_SYNTHETIC) == 0) { access |= Opcodes.ACC_SYNTHETIC; } return super.visitMethod(access, name, desc, signature, exceptions); } }; reader.accept(converter, 0); return writer.toByteArray(); } } }