aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoel Spilker <r.spilker@gmail.com>2010-08-03 01:04:01 +0200
committerRoel Spilker <r.spilker@gmail.com>2010-08-03 01:04:01 +0200
commit11fcdbee725a3b900ed7d6b7d09ea18f6af6b961 (patch)
tree4913fc2ad0c2412db5ff45d8f878f2c5d86307c3
parentfd8e08cb784db38d527c684681a88fc59931f713 (diff)
downloadlombok-11fcdbee725a3b900ed7d6b7d09ea18f6af6b961.tar.gz
lombok-11fcdbee725a3b900ed7d6b7d09ea18f6af6b961.tar.bz2
lombok-11fcdbee725a3b900ed7d6b7d09ea18f6af6b961.zip
Added initial support for post-compilation byte code transformations
-rw-r--r--src/core/lombok/core/DiagnosticsReceiver.java30
-rw-r--r--src/core/lombok/core/LombokNode.java8
-rw-r--r--src/core/lombok/core/PostCompiler.java30
-rw-r--r--src/core/lombok/javac/apt/InterceptingJavaFileManager.java104
-rw-r--r--src/core/lombok/javac/apt/InterceptingJavaFileObject.java129
-rw-r--r--src/core/lombok/javac/apt/MessagerDiagnosticsReceiver.java43
-rw-r--r--src/core/lombok/javac/apt/Processor.java38
7 files changed, 373 insertions, 9 deletions
diff --git a/src/core/lombok/core/DiagnosticsReceiver.java b/src/core/lombok/core/DiagnosticsReceiver.java
new file mode 100644
index 00000000..cdd16bc0
--- /dev/null
+++ b/src/core/lombok/core/DiagnosticsReceiver.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2009-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 DiagnosticsReceiver {
+ /** Generate a compiler error on this node. */
+ void addError(String message);
+
+ /** Generate a compiler warning on this node. */
+ void addWarning(String message);
+}
diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java
index 6fe37a6b..6d0f3147 100644
--- a/src/core/lombok/core/LombokNode.java
+++ b/src/core/lombok/core/LombokNode.java
@@ -38,7 +38,7 @@ import lombok.core.AST.Kind;
* @param N The common type of all AST nodes in the internal representation of the target platform.
* For example, JCTree for javac, and ASTNode for Eclipse.
*/
-public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> {
+public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> implements DiagnosticsReceiver {
protected final A ast;
protected final Kind kind;
protected final N node;
@@ -316,12 +316,6 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
return (L) this;
}
- /** Generate a compiler error on this node. */
- public abstract void addError(String message);
-
- /** Generate a compiler warning on this node. */
- public abstract void addWarning(String message);
-
/**
* Structurally significant means: LocalDeclaration, TypeDeclaration, MethodDeclaration, ConstructorDeclaration,
* FieldDeclaration, Initializer, and CompilationUnitDeclaration.
diff --git a/src/core/lombok/core/PostCompiler.java b/src/core/lombok/core/PostCompiler.java
new file mode 100644
index 00000000..882430fc
--- /dev/null
+++ b/src/core/lombok/core/PostCompiler.java
@@ -0,0 +1,30 @@
+/*
+ * 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 final class PostCompiler {
+ private PostCompiler() {/* prevent instantiation*/};
+
+ public static byte[] applyTransformations(byte[] original, String className, DiagnosticsReceiver diagnostics) {
+ return original;
+ }
+}
diff --git a/src/core/lombok/javac/apt/InterceptingJavaFileManager.java b/src/core/lombok/javac/apt/InterceptingJavaFileManager.java
new file mode 100644
index 00000000..2b570eb0
--- /dev/null
+++ b/src/core/lombok/javac/apt/InterceptingJavaFileManager.java
@@ -0,0 +1,104 @@
+/*
+ * 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.javac.apt;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+
+import lombok.core.DiagnosticsReceiver;
+
+final class InterceptingJavaFileManager implements JavaFileManager {
+ private final JavaFileManager delegate;
+ private final DiagnosticsReceiver diagnostics;
+
+ InterceptingJavaFileManager(JavaFileManager original, DiagnosticsReceiver diagnostics) {
+ this.delegate = original;
+ this.diagnostics = diagnostics;
+ }
+
+ @Override public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+ JavaFileObject fileObject = delegate.getJavaFileForOutput(location, className, kind, sibling);
+ if (kind != Kind.CLASS) {
+ return fileObject;
+ }
+ return new InterceptingJavaFileObject(fileObject, className, diagnostics);
+ }
+
+
+
+
+/////////////////////// NOTHING CHANGED BELOW //////////////////////////////////////
+
+ @Override public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override public void flush() throws IOException {
+ delegate.flush();
+ }
+
+ @Override public ClassLoader getClassLoader(Location location) {
+ return delegate.getClassLoader(location);
+ }
+
+ @Override public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ return delegate.getFileForInput(location, packageName, relativeName);
+ }
+
+ @Override public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
+ return delegate.getFileForOutput(location, packageName, relativeName, sibling);
+ }
+
+ @Override public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
+ return delegate.getJavaFileForInput(location, className, kind);
+ }
+
+ @Override public boolean handleOption(String current, Iterator<String> remaining) {
+ return delegate.handleOption(current, remaining);
+ }
+
+ @Override public boolean hasLocation(Location location) {
+ return delegate.hasLocation(location);
+ }
+
+ @Override public String inferBinaryName(Location location, JavaFileObject file) {
+ return delegate.inferBinaryName(location, file);
+ }
+
+ @Override public boolean isSameFile(FileObject a, FileObject b) {
+ return delegate.isSameFile(a, b);
+ }
+
+ @Override public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException {
+ return delegate.list(location, packageName, kinds, recurse);
+ }
+
+ @Override public int isSupportedOption(String option) {
+ return delegate.isSupportedOption(option);
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/javac/apt/InterceptingJavaFileObject.java b/src/core/lombok/javac/apt/InterceptingJavaFileObject.java
new file mode 100644
index 00000000..1e07440a
--- /dev/null
+++ b/src/core/lombok/javac/apt/InterceptingJavaFileObject.java
@@ -0,0 +1,129 @@
+/*
+ * 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.javac.apt;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import lombok.core.DiagnosticsReceiver;
+import lombok.core.PostCompiler;
+
+final class InterceptingJavaFileObject implements JavaFileObject {
+ private final JavaFileObject delegate;
+ private final String className;
+ private final DiagnosticsReceiver diagnostics;
+
+ public InterceptingJavaFileObject(JavaFileObject original, String className, DiagnosticsReceiver diagnostics) {
+ this.delegate = original;
+ this.className = className;
+ this.diagnostics = diagnostics;
+ }
+
+ public OutputStream openOutputStream() throws IOException {
+ // Open it first to make sure we throw an exception if that fails.
+ final OutputStream originalStream = delegate.openOutputStream();
+
+ return new ByteArrayOutputStream() {
+ @Override public void close() throws IOException {
+ // no need to call super
+ byte[] original = toByteArray();
+ byte[] copy = null;
+ try {
+ copy = PostCompiler.applyTransformations(original, className, diagnostics);
+ } catch (Exception e) {
+ diagnostics.addWarning(String.format("Error during the transformation of '%s'; no post-compilation has been applied", className));
+ }
+
+ if (copy == null) {
+ copy = original;
+ }
+
+ // Exceptions below should bubble
+ originalStream.write(copy);
+ originalStream.close();
+ }
+ };
+ }
+
+ public Writer openWriter() throws IOException {
+ throw new UnsupportedOperationException("Can't use a write for class files");
+// return original.openWriter();
+ }
+
+
+
+
+/////////////////////// NOTHING CHANGED BELOW //////////////////////////////////////
+
+ public boolean delete() {
+ return delegate.delete();
+ }
+
+ public Modifier getAccessLevel() {
+ return delegate.getAccessLevel();
+ }
+
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return delegate.getCharContent(ignoreEncodingErrors);
+ }
+
+ public Kind getKind() {
+ return delegate.getKind();
+ }
+
+ public long getLastModified() {
+ return delegate.getLastModified();
+ }
+
+ public String getName() {
+ return delegate.getName();
+ }
+
+ public NestingKind getNestingKind() {
+ return delegate.getNestingKind();
+ }
+
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ return delegate.isNameCompatible(simpleName, kind);
+ }
+
+ public InputStream openInputStream() throws IOException {
+ return delegate.openInputStream();
+ }
+
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ return delegate.openReader(ignoreEncodingErrors);
+ }
+
+ public URI toUri() {
+ return delegate.toUri();
+ }
+}
diff --git a/src/core/lombok/javac/apt/MessagerDiagnosticsReceiver.java b/src/core/lombok/javac/apt/MessagerDiagnosticsReceiver.java
new file mode 100644
index 00000000..5b75b3c5
--- /dev/null
+++ b/src/core/lombok/javac/apt/MessagerDiagnosticsReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2009-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.javac.apt;
+
+import javax.annotation.processing.Messager;
+import javax.tools.Diagnostic.Kind;
+
+import lombok.core.DiagnosticsReceiver;
+
+public class MessagerDiagnosticsReceiver implements DiagnosticsReceiver {
+ private final Messager messager;
+
+ public MessagerDiagnosticsReceiver(Messager messager) {
+ this.messager = messager;
+ }
+
+ @Override public void addWarning(String message) {
+ messager.printMessage(Kind.WARNING, message);
+ }
+
+ @Override public void addError(String message) {
+ messager.printMessage(Kind.ERROR, message);
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java
index 31cedf03..ab445309 100644
--- a/src/core/lombok/javac/apt/Processor.java
+++ b/src/core/lombok/javac/apt/Processor.java
@@ -1,5 +1,5 @@
/*
- * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ * Copyright © 2009-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
@@ -21,10 +21,14 @@
*/
package lombok.javac.apt;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.util.IdentityHashMap;
+import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
@@ -32,14 +36,17 @@ import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileManager;
+import lombok.Lombok;
+import lombok.core.DiagnosticsReceiver;
import lombok.javac.JavacTransformer;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
-
+import com.sun.tools.javac.util.Context;
/**
* This Annotation Processor is the standard injection mechanism for lombok-enabling the javac compiler.
@@ -54,6 +61,7 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class Processor extends AbstractProcessor {
+
private JavacProcessingEnvironment processingEnv;
private JavacTransformer transformer;
private Trees trees;
@@ -62,9 +70,35 @@ public class Processor extends AbstractProcessor {
@Override public void init(ProcessingEnvironment procEnv) {
super.init(procEnv);
this.processingEnv = (JavacProcessingEnvironment) procEnv;
+ placePostCompileHook();
transformer = new JavacTransformer(procEnv.getMessager());
trees = Trees.instance(procEnv);
}
+
+ private void placePostCompileHook() {
+ Context context = processingEnv.getContext();
+
+ try {
+ Method keyMethod = Context.class.getDeclaredMethod("key", Class.class);
+ keyMethod.setAccessible(true);
+ Object key = keyMethod.invoke(context, JavaFileManager.class);
+ Field htField = Context.class.getDeclaredField("ht");
+ htField.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ Map<Object,Object> ht = (Map<Object,Object>) htField.get(context);
+ final JavaFileManager originalFiler = (JavaFileManager) ht.get(key);
+
+ if (!(originalFiler instanceof InterceptingJavaFileManager)) {
+ final Messager messager = processingEnv.getMessager();
+ DiagnosticsReceiver receiver = new MessagerDiagnosticsReceiver(messager);
+
+ JavaFileManager newFiler = new InterceptingJavaFileManager(originalFiler, receiver);
+ ht.put(key, newFiler);
+ }
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ }
/** {@inheritDoc} */
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {