aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lombok/apt/AnnotationTransponder.java111
-rw-r--r--src/lombok/apt/HandleANY_ecj.java17
-rw-r--r--src/lombok/apt/HandleGetter_javac.java77
-rw-r--r--src/lombok/apt/HandlerForCompiler.java16
-rw-r--r--src/lombok/apt/Processor.java35
-rw-r--r--src/lombok/core/SpiLoadUtil.java37
-rw-r--r--src/lombok/eclipse/HandlerLibrary.java66
-rw-r--r--src/lombok/javac/HandlerLibrary.java222
-rw-r--r--src/lombok/javac/JavacAnnotationHandler.java7
-rw-r--r--src/lombok/javac/JavacNode.java63
-rw-r--r--src/lombok/javac/apt/PKG.java (renamed from src/lombok/apt/PKG.java)16
-rw-r--r--src/lombok/javac/apt/Processor.java62
-rw-r--r--src/lombok/javac/handlers/HandleGetter_javac.java60
-rw-r--r--src/lombok/javac/handlers/PKG.java34
14 files changed, 505 insertions, 318 deletions
diff --git a/src/lombok/apt/AnnotationTransponder.java b/src/lombok/apt/AnnotationTransponder.java
deleted file mode 100644
index 01a79c12..00000000
--- a/src/lombok/apt/AnnotationTransponder.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package lombok.apt;
-
-import static lombok.apt.PKG.CURRENT_SUPPORT;
-import static lombok.apt.PKG.isInstanceOf;
-import static lombok.apt.PKG.readResource;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.Element;
-import javax.tools.Diagnostic;
-
-/**
- * Responsible for redirecting the need to handle an annotation to a class that knows how to handle a given annotation type in a given compiler environment.
- * Will dynamically locate a class in this package using the naming pattern: "HandleFoo_compilerType", e.g. "HandleGetter_ecj".
- * Responsible for injecting the proper class into the right classloader so that it has open access to the classes required to inspect the live AST and
- * modify it so that annotations can cause changes to the live AST.
- *
- * @author rzwitserloot
- *
- * @param <T> The annotation class that this transponder should handle (example: Getter.class).
- */
-public class AnnotationTransponder<T extends Annotation> {
- private HandlerForCompiler<T> impl;
- private final ProcessingEnvironment processEnv;
- private final RoundEnvironment roundEnv;
- private String error;
-
- @SuppressWarnings("unchecked")
- private void createInstance(Class<T> annotation, ClassLoader loader, String compilerType) {
- try {
- if ( loader == null ) loader = AnnotationTransponder.class.getClassLoader();
- Class<?> implClass;
- try {
- implClass = loader.loadClass(String.format(
- "org.javanext.apt.Handle%s_%s", annotation.getSimpleName(), compilerType));
- } catch ( ClassNotFoundException e ) {
- implClass = loader.loadClass(String.format("lombok.apt.HandleANY_%s", compilerType));
- }
-
- Constructor<?> constructor;
-
- constructor = implClass.getDeclaredConstructor();
- constructor.setAccessible(true);
- impl = (HandlerForCompiler<T>)constructor.newInstance();
- impl.processEnv = processEnv;
- impl.roundEnv = roundEnv;
- try {
- impl.init();
- } catch ( Exception e ) {
- error = "Exception initializing handler: " + e;
- impl = null;
- }
- } catch ( Exception e ) {
- e.printStackTrace();
- error = "You are using " + compilerType + " but a version that's changed the compiler internals. I can't work with it.";
- }
- }
-
- public AnnotationTransponder(Class<T> annotation, RoundEnvironment roundEnv, ProcessingEnvironment processEnv) {
- this.processEnv = processEnv;
- this.roundEnv = roundEnv;
- if ( isInstanceOf(processEnv, "com.sun.tools.javac.processing.JavacProcessingEnvironment") ) {
- createInstance(annotation, null, "javac");
- } else if ( isInstanceOf(processEnv, "org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeBuildProcessingEnvImpl") ) {
- final ClassLoader[] parentLoaders =
- new ClassLoader[] { processEnv.getClass().getClassLoader(), AnnotationTransponder.class.getClassLoader() };
-
- ClassLoader loader = new ClassLoader() {
- @Override public Class<?> findClass(String name) throws ClassNotFoundException {
- if ( name.equals(HandlerForCompiler.class.getName()) ) return HandlerForCompiler.class;
- if ( name.startsWith(AnnotationTransponder.class.getPackage().getName()) ) {
- byte[] data = readResource(name.replace(".", "/") + ".class");
- return defineClass(name, data, 0, data.length);
- }
- for ( int i = 0 ; i < parentLoaders.length ; i++ ) {
- try {
- return parentLoaders[i].loadClass(name);
- } catch ( ClassNotFoundException e ) {
- if ( i == parentLoaders.length -1 ) throw e;
- }
- }
-
- return null;
- }
- };
-
- createInstance(annotation, loader, "ecj");
- } else {
- impl = null;
- this.error = "I cannot work with your compiler. I currently only support " + CURRENT_SUPPORT + ".\n" +
- "This is a: " + processEnv.getClass();
- }
- }
-
-
- public void handle(Element element, T annotation) {
- if ( impl == null ) {
- processEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, error, element);
- } else {
- try {
- impl.handle(element, annotation);
- } catch ( Exception e ) {
- e.printStackTrace();
- processEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Exception in JavaNext: " + e, element);
- }
- }
- }
-}
diff --git a/src/lombok/apt/HandleANY_ecj.java b/src/lombok/apt/HandleANY_ecj.java
deleted file mode 100644
index 587444d9..00000000
--- a/src/lombok/apt/HandleANY_ecj.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package lombok.apt;
-
-import java.lang.annotation.Annotation;
-
-import javax.lang.model.element.Element;
-import javax.tools.Diagnostic;
-
-public class HandleANY_ecj extends HandlerForCompiler<Annotation> {
- @Override public void handle(Element element, Annotation annotation) throws Exception {
- //TODO: We should find eclipse's eclipse.ini file and patch us in as a javaagent and bootclasspath/a.
- //Though, we should probably use reflection to find eclipse's SWT system and generate a popup dialog for
- //confirmation.
-
- String msg = "You'll need to install the eclipse patch. See http://lombok.github.org/ for more info.";
- processEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg, element);
- }
-}
diff --git a/src/lombok/apt/HandleGetter_javac.java b/src/lombok/apt/HandleGetter_javac.java
deleted file mode 100644
index bfa2746d..00000000
--- a/src/lombok/apt/HandleGetter_javac.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package lombok.apt;
-
-import java.lang.reflect.Modifier;
-
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
-
-import lombok.Getter;
-
-import com.sun.source.tree.MethodTree;
-import com.sun.source.util.Trees;
-import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.tree.TreeMaker;
-import com.sun.tools.javac.tree.JCTree.JCAnnotation;
-import com.sun.tools.javac.tree.JCTree.JCBlock;
-import com.sun.tools.javac.tree.JCTree.JCClassDecl;
-import com.sun.tools.javac.tree.JCTree.JCExpression;
-import com.sun.tools.javac.tree.JCTree.JCStatement;
-import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
-import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.Name;
-
-class HandleGetter_javac extends HandlerForCompiler<Getter> {
- private final Trees trees;
- private final Messager messager;
- private JavacProcessingEnvironment env;
-
- HandleGetter_javac() {
- this.messager = processEnv.getMessager();
- this.trees = Trees.instance(processEnv);
- }
-
- @Override public void init() {
- this.env = (JavacProcessingEnvironment)processEnv;
- }
-
- @Override public void handle(Element element, Getter getter) {
- if ( !element.getKind().isField() ) {
- messager.printMessage(Diagnostic.Kind.ERROR, "@Getter is only supported on a field.");
- return;
- }
-
- TypeElement classElement = (TypeElement)element.getEnclosingElement();
- JCClassDecl javacClassTree = (JCClassDecl)trees.getTree(classElement);
-
- Name.Table nameTable = Name.Table.instance(env.getContext());
- TreeMaker treeMaker = TreeMaker.instance(env.getContext());
-
- MethodTree getterMethod = createGetter(element, treeMaker, nameTable);
- javacClassTree.defs = javacClassTree.defs.append((JCTree)getterMethod);
- }
-
- private MethodTree createGetter(Element field, TreeMaker treeMaker, Name.Table nameTable) {
- JCStatement returnStatement = treeMaker.Return(treeMaker.Ident((Symbol)field));
-
- //TODO Trab the position in the source file of the field by looking it up in the JCClassDecl,
- //and copy it into the 'position' info for the Ident and Return AST Nodes.
-
- JCBlock methodBody = treeMaker.Block(0, List.of(returnStatement));
- Name methodName = Name.fromString(nameTable, PKG.toGetterName(field));
- JCExpression methodType = treeMaker.Type((Type)field.asType());
-
- List<JCTypeParameter> methodGenericParams = List.nil();
- List<JCVariableDecl> parameters = List.nil();
- List<JCExpression> throwsClauses = List.nil();
- JCExpression annotationMethodDefaultValue = null;
-
- return treeMaker.MethodDef(treeMaker.Modifiers(Modifier.PUBLIC, List.<JCAnnotation>nil()), methodName, methodType,
- methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue);
- }
-}
diff --git a/src/lombok/apt/HandlerForCompiler.java b/src/lombok/apt/HandlerForCompiler.java
deleted file mode 100644
index 7eb29385..00000000
--- a/src/lombok/apt/HandlerForCompiler.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package lombok.apt;
-
-import java.lang.annotation.Annotation;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.Element;
-
-public abstract class HandlerForCompiler<T extends Annotation> {
- protected ProcessingEnvironment processEnv;
- protected RoundEnvironment roundEnv;
-
- public void init() throws Exception {}
-
- public abstract void handle(Element element, T annotation) throws Exception;
-}
diff --git a/src/lombok/apt/Processor.java b/src/lombok/apt/Processor.java
deleted file mode 100644
index d63ec006..00000000
--- a/src/lombok/apt/Processor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package lombok.apt;
-
-import java.lang.annotation.Annotation;
-import java.util.Set;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.annotation.processing.SupportedSourceVersion;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-import lombok.Getter;
-
-
-@SupportedAnnotationTypes("lombok.*")
-@SupportedSourceVersion(SourceVersion.RELEASE_6)
-public class Processor extends AbstractProcessor {
- @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- for ( TypeElement typeElement : annotations ) {
- if ( typeElement.getQualifiedName().contentEquals(Getter.class.getName()) )
- return handle(roundEnv, Getter.class, typeElement);
- }
-
- return false;
- }
-
- private <T extends Annotation> boolean handle(RoundEnvironment roundEnv, Class<T> annotation, TypeElement typeElement) {
- for ( Element element : roundEnv.getElementsAnnotatedWith(typeElement) ) {
- new AnnotationTransponder<T>(annotation, roundEnv, processingEnv).handle(element, element.getAnnotation(annotation));
- }
- return true;
- }
-}
diff --git a/src/lombok/core/SpiLoadUtil.java b/src/lombok/core/SpiLoadUtil.java
new file mode 100644
index 00000000..bf4bddf4
--- /dev/null
+++ b/src/lombok/core/SpiLoadUtil.java
@@ -0,0 +1,37 @@
+package lombok.core;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+public class SpiLoadUtil {
+ private SpiLoadUtil() {}
+
+ @SuppressWarnings("unchecked")
+ public static Class<? extends Annotation> findAnnotationClass(Class<?> c, Class<?> base) {
+ if ( c == Object.class || c == null ) return null;
+ for ( Type iface : c.getGenericInterfaces() ) {
+ if ( iface instanceof ParameterizedType ) {
+ ParameterizedType p = (ParameterizedType)iface;
+ if ( !base.equals(p.getRawType()) ) continue;
+ Type target = p.getActualTypeArguments()[0];
+ if ( target instanceof Class<?> ) {
+ if ( Annotation.class.isAssignableFrom((Class<?>) target) ) {
+ return (Class<? extends Annotation>) target;
+ }
+ }
+
+ throw new ClassCastException("Not an annotation type: " + target);
+ }
+ }
+
+ Class<? extends Annotation> potential = findAnnotationClass(c.getSuperclass(), base);
+ if ( potential != null ) return potential;
+ for ( Class<?> iface : c.getInterfaces() ) {
+ potential = findAnnotationClass(iface, base);
+ if ( potential != null ) return potential;
+ }
+
+ return null;
+ }
+}
diff --git a/src/lombok/eclipse/HandlerLibrary.java b/src/lombok/eclipse/HandlerLibrary.java
index f458cf45..8a7f6edc 100644
--- a/src/lombok/eclipse/HandlerLibrary.java
+++ b/src/lombok/eclipse/HandlerLibrary.java
@@ -4,9 +4,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
-import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -15,6 +13,7 @@ import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
+import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
import lombok.eclipse.EclipseAST.Node;
@@ -60,7 +59,7 @@ public class HandlerLibrary {
@SuppressWarnings("unchecked")
public <A extends Annotation> A createAnnotation(Class<A> target,
CompilationUnitDeclaration ast,
- org.eclipse.jdt.internal.compiler.ast.Annotation node) throws EnumDecodeFail {
+ org.eclipse.jdt.internal.compiler.ast.Annotation node) throws AnnotationValueDecodeFail {
final Map<String, Object> values = new HashMap<String, Object>();
final MemberValuePair[] pairs = node.memberValuePairs();
@@ -87,12 +86,12 @@ public class HandlerLibrary {
}
private Object calculateValue(MemberValuePair pair,
- CompilationUnitDeclaration ast, Class<?> type, Expression e) throws EnumDecodeFail {
+ CompilationUnitDeclaration ast, Class<?> type, Expression e) throws AnnotationValueDecodeFail {
if ( e instanceof Literal ) {
((Literal)e).computeConstant();
return convertConstant(pair, type, e.constant);
} else if ( e instanceof ArrayInitializer ) {
- if ( !type.isArray() ) throw new EnumDecodeFail(pair, "Did not expect an array here.");
+ if ( !type.isArray() ) throw new AnnotationValueDecodeFail(pair, "Did not expect an array here.");
Class<?> component = type.getComponentType();
Expression[] expressions = ((ArrayInitializer)e).expressions;
@@ -104,19 +103,19 @@ public class HandlerLibrary {
return values;
} else if ( e instanceof ClassLiteralAccess ) {
if ( type == Class.class ) return toClass(pair, ast, str(((ClassLiteralAccess)e).type.getTypeName()));
- else throw new EnumDecodeFail(pair, "Expected a " + type + " literal.");
+ else throw new AnnotationValueDecodeFail(pair, "Expected a " + type + " literal.");
} else if ( e instanceof NameReference ) {
String s = null;
if ( e instanceof SingleNameReference ) s = new String(((SingleNameReference)e).token);
else if ( e instanceof QualifiedNameReference ) s = str(((QualifiedNameReference)e).tokens);
if ( Enum.class.isAssignableFrom(type) ) return toEnum(pair, type, s);
- throw new EnumDecodeFail(pair, "Lombok annotations must contain literals only.");
+ throw new AnnotationValueDecodeFail(pair, "Lombok annotations must contain literals only.");
} else {
- throw new EnumDecodeFail(pair, "Lombok could not decode this annotation parameter.");
+ throw new AnnotationValueDecodeFail(pair, "Lombok could not decode this annotation parameter.");
}
}
- private Enum<?> toEnum(MemberValuePair pair, Class<?> enumType, String ref) throws EnumDecodeFail {
+ private Enum<?> toEnum(MemberValuePair pair, Class<?> enumType, String ref) throws AnnotationValueDecodeFail {
int idx = ref.indexOf('.');
if ( idx > -1 ) ref = ref.substring(idx +1);
Object[] enumConstants = enumType.getEnumConstants();
@@ -124,10 +123,10 @@ public class HandlerLibrary {
String target = ((Enum<?>)constant).name();
if ( target.equals(ref) ) return (Enum<?>) constant;
}
- throw new EnumDecodeFail(pair, "I can't figure out which enum constant you mean.");
+ throw new AnnotationValueDecodeFail(pair, "I can't figure out which enum constant you mean.");
}
- private Class<?> toClass(MemberValuePair pair, CompilationUnitDeclaration ast, String typeName) throws EnumDecodeFail {
+ private Class<?> toClass(MemberValuePair pair, CompilationUnitDeclaration ast, String typeName) throws AnnotationValueDecodeFail {
Class<?> c;
boolean fqn = typeName.indexOf('.') > -1;
@@ -170,7 +169,7 @@ public class HandlerLibrary {
}
}
- throw new EnumDecodeFail(pair, "I can't find this class. Try using the fully qualified name.");
+ throw new AnnotationValueDecodeFail(pair, "I can't find this class. Try using the fully qualified name.");
}
private Class<?> tryClass(String name) {
@@ -181,7 +180,7 @@ public class HandlerLibrary {
}
}
- private Object convertConstant(MemberValuePair pair, Class<?> type, Constant constant) throws EnumDecodeFail {
+ private Object convertConstant(MemberValuePair pair, Class<?> type, Constant constant) throws AnnotationValueDecodeFail {
int targetTypeID;
boolean array = type.isArray();
if ( array ) type = type.getComponentType();
@@ -197,10 +196,10 @@ public class HandlerLibrary {
else if ( type == boolean.class ) targetTypeID = TypeIds.T_boolean;
else {
//Enum or Class, so a constant isn't going to be very useful.
- throw new EnumDecodeFail(pair, "Expected a constant of some sort here (a number or a string)");
+ throw new AnnotationValueDecodeFail(pair, "Expected a constant of some sort here (a number or a string)");
}
if ( !Expression.isConstantValueRepresentable(constant, constant.typeID(), targetTypeID) ) {
- throw new EnumDecodeFail(pair, "I can't turn this literal into a " + type);
+ throw new AnnotationValueDecodeFail(pair, "I can't turn this literal into a " + type);
}
Object o = null;
@@ -224,12 +223,12 @@ public class HandlerLibrary {
return o;
}
- private static class EnumDecodeFail extends Exception {
+ private static class AnnotationValueDecodeFail extends Exception {
private static final long serialVersionUID = 1L;
MemberValuePair pair;
- EnumDecodeFail(MemberValuePair pair, String msg) {
+ AnnotationValueDecodeFail(MemberValuePair pair, String msg) {
super(msg);
this.pair = pair;
}
@@ -259,7 +258,8 @@ public class HandlerLibrary {
while ( it.hasNext() ) {
try {
EclipseAnnotationHandler<?> handler = it.next();
- Class<? extends Annotation> annotationClass = lib.findAnnotationClass(handler.getClass());
+ Class<? extends Annotation> annotationClass =
+ SpiLoadUtil.findAnnotationClass(handler.getClass(), EclipseAnnotationHandler.class);
AnnotationHandlerContainer<?> container = new AnnotationHandlerContainer(handler, annotationClass);
if ( lib.annotationHandlers.put(container.annotationClass.getName(), container) != null ) {
Eclipse.error("Duplicate handlers for annotation type: " + container.annotationClass.getName());
@@ -282,34 +282,6 @@ public class HandlerLibrary {
}
}
- @SuppressWarnings("unchecked")
- private Class<? extends Annotation> findAnnotationClass(Class<?> c) {
- if ( c == Object.class || c == null ) return null;
- for ( Type iface : c.getGenericInterfaces() ) {
- if ( iface instanceof ParameterizedType ) {
- ParameterizedType p = (ParameterizedType)iface;
- if ( !EclipseAnnotationHandler.class.equals(p.getRawType()) ) continue;
- Type target = p.getActualTypeArguments()[0];
- if ( target instanceof Class<?> ) {
- if ( Annotation.class.isAssignableFrom((Class<?>) target) ) {
- return (Class<? extends Annotation>) target;
- }
- }
-
- throw new ClassCastException("Not an annotation type: " + target);
- }
- }
-
- Class<? extends Annotation> potential = findAnnotationClass(c.getSuperclass());
- if ( potential != null ) return potential;
- for ( Class<?> iface : c.getInterfaces() ) {
- potential = findAnnotationClass(iface);
- if ( potential != null ) return potential;
- }
-
- return null;
- }
-
public void handle(CompilationUnitDeclaration ast, EclipseAST.Node annotationNode,
org.eclipse.jdt.internal.compiler.ast.Annotation annotation) {
TypeResolver resolver = new TypeResolver(typeLibrary, annotationNode.top());
@@ -321,7 +293,7 @@ public class HandlerLibrary {
Object annInstance;
try {
annInstance = createAnnotation(container.annotationClass, ast, annotation);
- } catch ( EnumDecodeFail e ) {
+ } catch ( AnnotationValueDecodeFail e ) {
annotationNode.addError(e.getMessage(), e.pair.sourceStart, e.pair.sourceEnd);
return;
}
diff --git a/src/lombok/javac/HandlerLibrary.java b/src/lombok/javac/HandlerLibrary.java
new file mode 100644
index 00000000..6f33003f
--- /dev/null
+++ b/src/lombok/javac/HandlerLibrary.java
@@ -0,0 +1,222 @@
+package lombok.javac;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+
+import lombok.core.SpiLoadUtil;
+
+
+public class HandlerLibrary {
+ private final Map<String, AnnotationHandlerContainer<?>> annotationHandlers = new HashMap<String, AnnotationHandlerContainer<?>>();
+// private final Collection<JavacASTVisitor> visitorHandlers = new ArrayList<JavacASTVisitor>();
+
+ private static class AnnotationHandlerContainer<T extends Annotation> {
+ private JavacAnnotationHandler<T> handler;
+ private Class<T> annotationClass;
+
+ AnnotationHandlerContainer(JavacAnnotationHandler<T> handler, Class<T> annotationClass) {
+ this.handler = handler;
+ this.annotationClass = annotationClass;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void handle(JavacNode node, Object annInstance) {
+ handler.handle(node, (T) annInstance);
+ }
+ }
+
+ public static HandlerLibrary load(Messager messager) {
+ HandlerLibrary library = new HandlerLibrary();
+ loadAnnotationHandlers(messager, library);
+ return library;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void loadAnnotationHandlers(Messager messager, HandlerLibrary lib) {
+ //No, that seemingly superfluous reference to JavacAnnotationHandler's classloader is not in fact superfluous!
+ Iterator<JavacAnnotationHandler> it = ServiceLoader.load(JavacAnnotationHandler.class,
+ JavacAnnotationHandler.class.getClassLoader()).iterator();
+ while ( it.hasNext() ) {
+ try {
+ JavacAnnotationHandler<?> handler = it.next();
+ Class<? extends Annotation> annotationClass =
+ SpiLoadUtil.findAnnotationClass(handler.getClass(), JavacAnnotationHandler.class);
+ AnnotationHandlerContainer<?> container = new AnnotationHandlerContainer(handler, annotationClass);
+ if ( lib.annotationHandlers.put(container.annotationClass.getName(), container) != null ) {
+ messager.printMessage(Diagnostic.Kind.WARNING,
+ "Duplicate handlers for annotation type: " + container.annotationClass.getName());
+ }
+ } catch ( ServiceConfigurationError e ) {
+ messager.printMessage(Diagnostic.Kind.WARNING,
+ "Can't load Lombok annotation handler for javac: " + e);
+ }
+ }
+ }
+
+ public void handleAnnotation(JavacNode node, TypeElement annotationType) {
+ AnnotationHandlerContainer<?> container = annotationHandlers.get(annotationType.getQualifiedName().toString());
+ if ( container == null ) return;
+ try {
+ container.handle(node, createAnnotation(container.annotationClass, annotationType.getQualifiedName(), node));
+ } catch ( AnnotationValueDecodeFail e ) {
+ node.addError(e.getMessage(), e.mirror, e.value);
+ }
+ }
+
+ private Object createAnnotation(Class<? extends Annotation> target, Name annotationName, JavacNode node)
+ throws AnnotationValueDecodeFail {
+ AnnotationMirror mirror = fetchMirror(annotationName, node);
+ if ( mirror == null ) throw new AssertionError("This can't be.");
+
+ InvocationHandler invocations = new AnnotationMirrorInvocationHandler(target, mirror);
+ return Proxy.newProxyInstance(target.getClassLoader(), new Class[] { target }, invocations);
+ }
+
+ private static class AnnotationValueDecodeFail extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ AnnotationMirror mirror;
+ AnnotationValue value;
+
+ AnnotationValueDecodeFail(String msg, AnnotationMirror mirror, AnnotationValue value) {
+ super(msg);
+ this.mirror = mirror;
+ this.value = value;
+ }
+ }
+
+ private static class AnnotationMirrorInvocationHandler implements InvocationHandler {
+ private final AnnotationMirror mirror;
+ private final Map<String, Object> values = new HashMap<String, Object>();
+
+ AnnotationMirrorInvocationHandler(Class<?> target, AnnotationMirror mirror) throws AnnotationValueDecodeFail {
+ this.mirror = mirror;
+
+ for ( Method m : target.getDeclaredMethods() ) {
+ if ( !Modifier.isPublic(m.getModifiers()) ) continue;
+ values.put(m.getName(), decode(m));
+ }
+ }
+
+ private Object decode(Method m) throws AnnotationValueDecodeFail {
+ for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
+ mirror.getElementValues().entrySet() ) {
+
+ if ( entry.getKey().getSimpleName().contentEquals(m.getName()) ) {
+ AnnotationValue value = entry.getValue();
+ return convert(m.getReturnType(), mirror, value, value.getValue());
+ }
+ }
+
+ return m.getDefaultValue();
+ }
+
+ @Override public Object invoke(Object proxy, Method method, Object[] args) {
+ return values.get(method.getName());
+ }
+
+ private Object convert(Class<?> expected, AnnotationMirror mirror, AnnotationValue value, Object v) throws AnnotationValueDecodeFail {
+ if ( expected == int.class ) {
+ if ( v instanceof Number ) return ((Number)v).intValue();
+ else throw new AnnotationValueDecodeFail("Expected a numeric value here", mirror, value);
+ } else if ( expected == long.class ) {
+ if ( v instanceof Number ) return ((Number)v).longValue();
+ else throw new AnnotationValueDecodeFail("Expected a numeric value here", mirror, value);
+ } else if ( expected == short.class ) {
+ if ( v instanceof Number ) return ((Number)v).shortValue();
+ else throw new AnnotationValueDecodeFail("Expected a numeric value here", mirror, value);
+ } else if ( expected == byte.class ) {
+ if ( v instanceof Number ) return ((Number)v).byteValue();
+ else throw new AnnotationValueDecodeFail("Expected a numeric value here", mirror, value);
+ } else if ( expected == double.class ) {
+ if ( v instanceof Number ) return ((Number)v).doubleValue();
+ else throw new AnnotationValueDecodeFail("Expected a numeric value here", mirror, value);
+ } else if ( expected == float.class ) {
+ if ( v instanceof Number ) return ((Number)v).floatValue();
+ else throw new AnnotationValueDecodeFail("Expected a numeric value here", mirror, value);
+ } else if ( expected == char.class ) {
+ if ( v instanceof Character ) return v;
+ else throw new AnnotationValueDecodeFail("Expected a character here", mirror, value);
+ } else if ( expected == boolean.class ) {
+ if ( v instanceof Boolean ) return v;
+ else throw new AnnotationValueDecodeFail("Expected a boolean here", mirror, value);
+ } else if ( expected == String.class ) {
+ if ( v instanceof String ) return v;
+ else throw new AnnotationValueDecodeFail("Expected a String here", mirror, value);
+ } else if ( expected == Class.class ) {
+ if ( v instanceof TypeMirror ) {
+ try {
+ return Class.forName(v.toString());
+ } catch ( ClassNotFoundException e ) {
+ throw new AnnotationValueDecodeFail(
+ "I can't find this class. Lombok only works well with types in the core java libraries.",
+ mirror, value);
+ }
+ } else throw new AnnotationValueDecodeFail("Expected a class literal here", mirror, value);
+ } else if ( Enum.class.isAssignableFrom(expected) ) {
+ if ( v instanceof VariableElement ) {
+ String n = ((VariableElement)v).getSimpleName().toString();
+ @SuppressWarnings("unchecked")
+ Object enumVal = Enum.valueOf((Class<? extends Enum>)expected, n);
+ return enumVal;
+ } else throw new AnnotationValueDecodeFail("Expected an enum value here", mirror, value);
+ } else if ( expected.isArray() ) {
+ if ( v instanceof Collection<?> ) {
+ List<Object> convertedValues = new ArrayList<Object>();
+ Class<?> componentType = expected.getComponentType();
+ for ( Object innerV : (Collection<?>)v ) {
+ convertedValues.add(convert(componentType, mirror, value, innerV));
+ }
+
+ Object array = Array.newInstance(componentType, convertedValues.size());
+ int pos = 0;
+ for ( Object converted : convertedValues ) Array.set(array, pos++, converted);
+ return array;
+ } else throw new AnnotationValueDecodeFail("Expected an array value here", mirror, value);
+// Collection<AnnotationValue> result = (Collection<AnnotationValue>)entry.getValue().getValue();
+// return result;
+ } else {
+ throw new AssertionError("We didn't know this is even a legal annotation type: " + expected);
+ }
+ }
+ }
+
+ private AnnotationMirror fetchMirror(Name lookingFor, JavacNode node) {
+ for ( AnnotationMirror mirror : node.getJavacAST().getAnnotationMirrors() ) {
+ if ( !lookingFor.contentEquals(
+ ((TypeElement)(mirror.getAnnotationType()).asElement()).getQualifiedName()) ) continue;
+ return mirror;
+ }
+ return null;
+ }
+
+ public void handleType(TypeElement typeElement) {
+ //Later!
+ }
+
+ public boolean hasHandlerFor(TypeElement annotationType) {
+ return annotationHandlers.containsKey(annotationType.getQualifiedName().toString());
+ }
+}
diff --git a/src/lombok/javac/JavacAnnotationHandler.java b/src/lombok/javac/JavacAnnotationHandler.java
new file mode 100644
index 00000000..67542a12
--- /dev/null
+++ b/src/lombok/javac/JavacAnnotationHandler.java
@@ -0,0 +1,7 @@
+package lombok.javac;
+
+import java.lang.annotation.Annotation;
+
+public interface JavacAnnotationHandler<T extends Annotation> {
+ void handle(JavacNode annotedElement, T annotation);
+}
diff --git a/src/lombok/javac/JavacNode.java b/src/lombok/javac/JavacNode.java
new file mode 100644
index 00000000..2e65e1d1
--- /dev/null
+++ b/src/lombok/javac/JavacNode.java
@@ -0,0 +1,63 @@
+package lombok.javac;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.util.Name;
+
+public class JavacNode {
+ private final Element node;
+ private final Messager messager;
+ private final JavacProcessingEnvironment env;
+ private final Trees trees;
+
+ public JavacNode(Trees trees, JavacProcessingEnvironment env, Element node) {
+ this.trees = trees;
+ this.env = env;
+ this.node = node;
+ this.messager = env.getMessager();
+ }
+
+ public Element getJavacAST() {
+ return node;
+ }
+
+ public JCClassDecl getEnclosingType() {
+ Element parent = node;
+ while ( !(parent instanceof TypeElement) ) parent = node.getEnclosingElement();
+ TypeElement classElement = (TypeElement)parent;
+ return (JCClassDecl)trees.getTree(classElement);
+ }
+
+ public Name.Table createNameTable() {
+ return Name.Table.instance(env.getContext());
+ }
+
+ public TreeMaker createTreeMaker() {
+ return TreeMaker.instance(env.getContext());
+ }
+
+ public void addError(String message) {
+ this.messager.printMessage(Diagnostic.Kind.ERROR, message, node);
+ }
+
+ public void addError(String message, AnnotationMirror mirror, AnnotationValue value) {
+ this.messager.printMessage(Diagnostic.Kind.ERROR, message, node, mirror, value);
+ }
+
+ public void addWarning(String message) {
+ this.messager.printMessage(Diagnostic.Kind.WARNING, message, node);
+ }
+
+ public void addWarning(String message, AnnotationMirror mirror, AnnotationValue value) {
+ this.messager.printMessage(Diagnostic.Kind.WARNING, message, node, mirror, value);
+ }
+}
diff --git a/src/lombok/apt/PKG.java b/src/lombok/javac/apt/PKG.java
index 2808e31e..2ecf1c7a 100644
--- a/src/lombok/apt/PKG.java
+++ b/src/lombok/javac/apt/PKG.java
@@ -1,19 +1,13 @@
-package lombok.apt;
+package lombok.javac.apt;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import javax.lang.model.element.Element;
-import javax.lang.model.type.TypeKind;
-
import lombok.Lombok;
-import lombok.core.TransformationsUtil;
class PKG {
- static final String CURRENT_SUPPORT = "javac 1.6 and eclipse (ecj).";
-
private PKG() {}
static boolean isInstanceOf(Object o, String className) {
@@ -49,14 +43,6 @@ class PKG {
}
}
- static String toGetterName(Element field) {
- CharSequence fieldName = field.getSimpleName();
-
- boolean isBoolean = field.asType().getKind() == TypeKind.BOOLEAN;
-
- return TransformationsUtil.toGetterName(fieldName, isBoolean);
- }
-
static byte[] readStream(InputStream in) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[65536];
diff --git a/src/lombok/javac/apt/Processor.java b/src/lombok/javac/apt/Processor.java
new file mode 100644
index 00000000..14a62367
--- /dev/null
+++ b/src/lombok/javac/apt/Processor.java
@@ -0,0 +1,62 @@
+package lombok.javac.apt;
+
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import lombok.javac.HandlerLibrary;
+import lombok.javac.JavacNode;
+
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+
+
+@SupportedAnnotationTypes("*")
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+public class Processor extends AbstractProcessor {
+ private JavacProcessingEnvironment processingEnv;
+ private HandlerLibrary handlers;
+ private Trees trees;
+
+ @Override public void init(ProcessingEnvironment processingEnv) {
+ super.init(processingEnv);
+ if ( !(processingEnv instanceof JavacProcessingEnvironment) ) this.processingEnv = null;
+ else {
+ this.processingEnv = (JavacProcessingEnvironment) processingEnv;
+ handlers = HandlerLibrary.load(processingEnv.getMessager());
+ }
+ }
+
+ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if ( processingEnv == null ) return false;
+
+ trees = Trees.instance(processingEnv);
+
+ for ( TypeElement annotationType : annotations ) {
+ if ( !handlers.hasHandlerFor(annotationType) ) continue;
+ for ( Element element : roundEnv.getElementsAnnotatedWith(annotationType) ) {
+ System.out.println("HIGHER PING: " + element);
+ handlers.handleAnnotation(createNode(element), annotationType);
+ }
+ }
+
+ for ( Element element : roundEnv.getRootElements() ) {
+ if ( element instanceof TypeElement ) {
+ handlers.handleType((TypeElement)element);
+ }
+ }
+
+ return false;
+ }
+
+ private JavacNode createNode(Element element) {
+ return new JavacNode(trees, processingEnv, element);
+ }
+}
diff --git a/src/lombok/javac/handlers/HandleGetter_javac.java b/src/lombok/javac/handlers/HandleGetter_javac.java
new file mode 100644
index 00000000..77ce2b4f
--- /dev/null
+++ b/src/lombok/javac/handlers/HandleGetter_javac.java
@@ -0,0 +1,60 @@
+package lombok.javac.handlers;
+
+import static lombok.javac.handlers.PKG.*;
+
+import javax.lang.model.element.Element;
+
+import lombok.Getter;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.sun.source.tree.MethodTree;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+
+@ProviderFor(JavacAnnotationHandler.class)
+public class HandleGetter_javac implements JavacAnnotationHandler<Getter> {
+ @Override public void handle(JavacNode node, Getter getter) {
+ System.out.println("PING: " + node.getJavacAST());
+ if ( !node.getJavacAST().getKind().isField() ) {
+ node.addError("@Getter is only supported on a field.");
+ return;
+ }
+
+ JCClassDecl javacClassTree = node.getEnclosingType();
+
+ int access = toJavacModifier(getter.value());
+
+ MethodTree getterMethod = createGetter(access, node.getJavacAST(), node.createTreeMaker(), node.createNameTable());
+ javacClassTree.defs = javacClassTree.defs.append((JCTree)getterMethod);
+ }
+
+ private MethodTree createGetter(int access, Element field, TreeMaker treeMaker, Name.Table nameTable) {
+ JCStatement returnStatement = treeMaker.Return(treeMaker.Ident((Symbol)field));
+
+ JCBlock methodBody = treeMaker.Block(0, List.of(returnStatement));
+ Name methodName = Name.fromString(nameTable, toGetterName(field));
+ JCExpression methodType = treeMaker.Type((Type)field.asType());
+
+ List<JCTypeParameter> methodGenericParams = List.nil();
+ List<JCVariableDecl> parameters = List.nil();
+ List<JCExpression> throwsClauses = List.nil();
+ JCExpression annotationMethodDefaultValue = null;
+
+ return treeMaker.MethodDef(treeMaker.Modifiers(access, List.<JCAnnotation>nil()), methodName, methodType,
+ methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue);
+ }
+}
diff --git a/src/lombok/javac/handlers/PKG.java b/src/lombok/javac/handlers/PKG.java
new file mode 100644
index 00000000..4622c3ee
--- /dev/null
+++ b/src/lombok/javac/handlers/PKG.java
@@ -0,0 +1,34 @@
+package lombok.javac.handlers;
+
+import java.lang.reflect.Modifier;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeKind;
+
+import lombok.AccessLevel;
+import lombok.core.TransformationsUtil;
+
+class PKG {
+ static String toGetterName(Element field) {
+ CharSequence fieldName = field.getSimpleName();
+
+ boolean isBoolean = field.asType().getKind() == TypeKind.BOOLEAN;
+
+ return TransformationsUtil.toGetterName(fieldName, isBoolean);
+ }
+
+ static int toJavacModifier(AccessLevel accessLevel) {
+ switch ( accessLevel ) {
+ case MODULE:
+ case PACKAGE:
+ return 0;
+ default:
+ case PUBLIC:
+ return Modifier.PUBLIC;
+ case PRIVATE:
+ return Modifier.PRIVATE;
+ case PROTECTED:
+ return Modifier.PROTECTED;
+ }
+ }
+}