diff options
author | Roel Spilker <r.spilker@gmail.com> | 2010-08-03 03:41:07 +0200 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2010-08-03 03:41:07 +0200 |
commit | 57bb88a7691dd89029517a79393a62e6cdedc3ce (patch) | |
tree | 37fb6bf42eae92064eeca6d8736b1cd91215f72f | |
parent | 40466c3e2d7d26a43b58f008986fd0b84c986b27 (diff) | |
download | lombok-57bb88a7691dd89029517a79393a62e6cdedc3ce.tar.gz lombok-57bb88a7691dd89029517a79393a62e6cdedc3ce.tar.bz2 lombok-57bb88a7691dd89029517a79393a62e6cdedc3ce.zip |
Post Compiler now works, including the sneaky throws remover. Also added a lombok app for it. Not yet in eclipse, though
-rw-r--r-- | src/core/lombok/bytecode/PostCompilerApp.java | 152 | ||||
-rw-r--r-- | src/core/lombok/bytecode/SneakyThrowsRemover.java | 66 | ||||
-rw-r--r-- | src/core/lombok/core/PostCompiler.java | 14 | ||||
-rw-r--r-- | src/core/lombok/core/PostCompilerTransformation.java | 21 |
4 files changed, 222 insertions, 31 deletions
diff --git a/src/core/lombok/bytecode/PostCompilerApp.java b/src/core/lombok/bytecode/PostCompilerApp.java new file mode 100644 index 00000000..3a413d67 --- /dev/null +++ b/src/core/lombok/bytecode/PostCompilerApp.java @@ -0,0 +1,152 @@ +/* + * Copyright © 2010 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.bytecode; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import lombok.core.DiagnosticsReceiver; +import lombok.core.LombokApp; +import lombok.core.PostCompiler; + +import org.mangosdk.spi.ProviderFor; + +import com.zwitserloot.cmdreader.CmdReader; +import com.zwitserloot.cmdreader.Description; +import com.zwitserloot.cmdreader.InvalidCommandLineException; +import com.zwitserloot.cmdreader.Mandatory; +import com.zwitserloot.cmdreader.Sequential; +import com.zwitserloot.cmdreader.Shorthand; + +@ProviderFor(LombokApp.class) +public class PostCompilerApp implements LombokApp { + @Override public List<String> getAppAliases() { + return Arrays.asList("post", "postcompile"); + } + + @Override public String getAppDescription() { + return "Runs registered post compiler handlers to against existing class files, modifying them in the process."; + } + + @Override public String getAppName() { + return "post-compile"; + } + + public static class CmdArgs { + @Sequential + @Mandatory + @Description("paths to class files to be converted. If a directory is named, all files (recursively) in that directory will be converted.") + private List<String> classFiles = new ArrayList<String>(); + + @Shorthand("v") + @Description("Prints lots of status information as the post compiler runs") + boolean verbose = false; + + @Shorthand({"h", "?"}) + @Description("Shows this help text") + boolean help = false; + } + + @Override public int runApp(List<String> raw) throws Exception { + CmdReader<CmdArgs> reader = CmdReader.of(CmdArgs.class); + CmdArgs args; + try { + args = reader.make(raw.toArray(new String[0])); + if (args.help) { + System.out.println(reader.generateCommandLineHelp("java -jar lombok.jar post-compile")); + return 0; + } + } catch (InvalidCommandLineException e) { + System.err.println(e.getMessage()); + System.err.println(reader.generateCommandLineHelp("java -jar lombok.jar post-compile")); + return 1; + } + + List<File> filesToProcess = new ArrayList<File>(); + for (String f : args.classFiles) addFiles(filesToProcess, f); + + int filesVisited = 0, filesTouched = 0; + for (File file : filesToProcess) { + if (!file.exists() || !file.isFile()) { + System.out.printf("Cannot find file '%s'\n", file); + continue; + } + filesVisited++; + if (args.verbose) System.out.println("Processing " + file.getAbsolutePath()); + byte[] original = readFile(file); + byte[] clone = original.clone(); + byte[] transformed = PostCompiler.applyTransformations(clone, file.toString(), DiagnosticsReceiver.CONSOLE); + if (clone != transformed && !Arrays.equals(clone, transformed)) { + filesTouched++; + if (args.verbose) System.out.println("Rewriting " + file.getAbsolutePath()); + writeFile(file, transformed); + } + } + + if (args.verbose) { + System.out.printf("Total files visited: %d total files changed: %d\n", filesVisited, filesTouched); + } + + return filesVisited == 0 ? 1 : 0; + } + + private void addFiles(List<File> filesToProcess, String f) { + File file = new File(f); + if (file.isDirectory()) { + addRecursively(filesToProcess, file); + } else { + filesToProcess.add(file); + } + } + + private void addRecursively(List<File> filesToProcess, File file) { + for (File f : file.listFiles()) { + if (f.isDirectory()) addRecursively(filesToProcess, f); + else if (f.getName().endsWith(".class")) filesToProcess.add(f); + } + } + + private static byte[] readFile(File file) throws IOException { + byte[] buffer = new byte[1024]; + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + FileInputStream fileInputStream = new FileInputStream(file); + while (true) { + int read = fileInputStream.read(buffer); + if (read == -1) break; + bytes.write(buffer, 0, read); + } + fileInputStream.close(); + return bytes.toByteArray(); + } + + private static void writeFile(File file, byte[] transformed) throws IOException { + FileOutputStream out = new FileOutputStream(file); + out.write(transformed); + out.close(); + } +} diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java index b816cd54..02a220c3 100644 --- a/src/core/lombok/bytecode/SneakyThrowsRemover.java +++ b/src/core/lombok/bytecode/SneakyThrowsRemover.java @@ -1,5 +1,28 @@ +/* + * Copyright © 2010 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.bytecode; +import java.util.concurrent.atomic.AtomicBoolean; + import lombok.core.DiagnosticsReceiver; import lombok.core.PostCompilerTransformation; @@ -51,30 +74,33 @@ public class SneakyThrowsRemover implements PostCompilerTransformation { ClassReader reader = new ClassReader(fixedByteCode); ClassWriter writer = new FixedClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + final AtomicBoolean changesMade = new AtomicBoolean(); + + class SneakyThrowsRemoverVisitor extends MethodAdapter { + SneakyThrowsRemoverVisitor(MethodVisitor mv) { + super(mv); + } + + @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { + boolean hit = true; + if (hit && opcode != Opcodes.INVOKESTATIC) hit = false; + if (hit && !"sneakyThrow".equals(name)) hit = false; + if (hit && !"lombok/Lombok".equals(owner)) hit = false; + if (hit && !"(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;".equals(desc)) hit = false; + if (hit) { + changesMade.set(true); + super.visitInsn(Opcodes.ATHROW); + } else { + super.visitMethodInsn(opcode, owner, name, desc); + } + } + } + reader.accept(new ClassAdapter(writer) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return new SneakyThrowsRemoverVisitor(super.visitMethod(access, name, desc, signature, exceptions)); } }, 0); - return writer.toByteArray(); - } - - private class SneakyThrowsRemoverVisitor extends MethodAdapter { - SneakyThrowsRemoverVisitor(MethodVisitor mv) { - super(mv); - } - - @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { - boolean hit = true; - if (hit && opcode != Opcodes.INVOKESTATIC) hit = false; - if (hit && !"sneakyThrow".equals(name)) hit = false; - if (hit && !"lombok/Lombok".equals(owner)) hit = false; - if (hit && !"(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;".equals(desc)) hit = false; - if (hit) { - super.visitInsn(Opcodes.ATHROW); - } else { - super.visitMethodInsn(opcode, owner, name, desc); - } - } + return changesMade.get() ? writer.toByteArray() : null; } } diff --git a/src/core/lombok/core/PostCompiler.java b/src/core/lombok/core/PostCompiler.java index a473b45f..07cfc04d 100644 --- a/src/core/lombok/core/PostCompiler.java +++ b/src/core/lombok/core/PostCompiler.java @@ -22,8 +22,7 @@ package lombok.core; import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; +import java.util.Collections; import java.util.List; public final class PostCompiler { @@ -49,17 +48,10 @@ public final class PostCompiler { private static synchronized void init(DiagnosticsReceiver diagnostics) { if (transformations != null) return; - transformations = new ArrayList<PostCompilerTransformation>(); try { - Iterator<PostCompilerTransformation> discovered = SpiLoadUtil.findServices(PostCompilerTransformation.class).iterator(); - while (discovered.hasNext()) { - try { - transformations.add(discovered.next()); - } catch (Exception e) { - diagnostics.addWarning("Error during loading post-compile transformers: " + e.getMessage()); - } - } + transformations = SpiLoadUtil.readAllFromIterator(SpiLoadUtil.findServices(PostCompilerTransformation.class, PostCompilerTransformation.class.getClassLoader())); } catch (IOException e) { + transformations = Collections.emptyList(); diagnostics.addWarning("Could not load post-compile transformers: " + e.getMessage()); } } diff --git a/src/core/lombok/core/PostCompilerTransformation.java b/src/core/lombok/core/PostCompilerTransformation.java index c174b97f..e0770f53 100644 --- a/src/core/lombok/core/PostCompilerTransformation.java +++ b/src/core/lombok/core/PostCompilerTransformation.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2010 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.core; public interface PostCompilerTransformation { |