From c3eddf66cfb16d5d27c7a9562ea539344bfcb2d6 Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Sat, 6 Nov 2010 13:30:22 +0100 Subject: Added support for Log4J, Commons and JUL in the javac handler --- src/core/lombok/commons/Log.java | 34 +++ src/core/lombok/javac/handlers/HandleLog.java | 236 +++++++++++++++++++++ src/core/lombok/javac/handlers/HandleSlf4jLog.java | 114 ---------- .../lombok/javac/handlers/JavacHandlerUtil.java | 15 ++ src/core/lombok/jul/Log.java | 34 +++ src/core/lombok/log4j/Log.java | 34 +++ 6 files changed, 353 insertions(+), 114 deletions(-) create mode 100644 src/core/lombok/commons/Log.java create mode 100644 src/core/lombok/javac/handlers/HandleLog.java delete mode 100644 src/core/lombok/javac/handlers/HandleSlf4jLog.java create mode 100644 src/core/lombok/jul/Log.java create mode 100644 src/core/lombok/log4j/Log.java (limited to 'src') diff --git a/src/core/lombok/commons/Log.java b/src/core/lombok/commons/Log.java new file mode 100644 index 00000000..974979b7 --- /dev/null +++ b/src/core/lombok/commons/Log.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.commons; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + + Class value() default void.class; +} diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java new file mode 100644 index 00000000..abeca18e --- /dev/null +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -0,0 +1,236 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.handlers; + +import static lombok.javac.handlers.JavacHandlerUtil.*; + +import java.lang.annotation.Annotation; + +import lombok.core.AnnotationValues; +import lombok.core.AST.Kind; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; + +import org.mangosdk.spi.ProviderFor; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.List; + +public class HandleLog { + + private HandleLog() { + throw new UnsupportedOperationException(); + } + + public static boolean processAnnotation(LoggingFramework framework, AnnotationValues annotation, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, framework.getAnnotationClass()); + + String loggingClassName = annotation.getRawExpression("value"); + if (loggingClassName == null) loggingClassName = "void"; + if (loggingClassName.endsWith(".class")) loggingClassName = loggingClassName.substring(0, loggingClassName.length() - 6); + + JavacNode typeNode = annotationNode.up(); + switch (typeNode.getKind()) { + case TYPE: + if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE)!= 0) { + annotationNode.addError("@Log is legal only on classes and enums."); + return true; + } + + if (fieldExists("log", typeNode)!= MemberExistsResult.NOT_EXISTS) { + annotationNode.addWarning("Field 'log' already exists."); + return true; + } + + if (loggingClassName.equals("void")) { + loggingClassName = getSelfName(typeNode); + } + createField(typeNode, loggingClassName, framework); + return true; + default: + annotationNode.addError("@Log is legal only on types."); + return true; + } + } + + private static String getSelfName(JavacNode typeNode) { + String typeName = ((JCClassDecl) typeNode.get()).name.toString(); + JavacNode upType = typeNode.up(); + while (upType.getKind() == Kind.TYPE) { + typeName = ((JCClassDecl) upType.get()).name.toString() + "." + typeName; + upType = upType.up(); + } + + String packageDeclaration = typeNode.getPackageDeclaration(); + if (packageDeclaration != null) { + typeName = packageDeclaration + "." + typeName; + } + return typeName; + } + + private static boolean createField(JavacNode typeNode, String loggerClassName, LoggingFramework framework) { + TreeMaker maker = typeNode.getTreeMaker(); + + // private static final log = (); + JCExpression loggerType = chainDotsString(maker, typeNode, framework.getLoggerTypeName()); + JCExpression factoryMethod = chainDotsString(maker, typeNode, framework.getLoggerFactoryMethodName()); + + JCExpression loggerName = framework.createFactoryParameter(typeNode, loggerClassName); + JCMethodInvocation factoryMethodCall = maker.Apply(List.nil(), factoryMethod, List.of(loggerName)); + + JCVariableDecl fieldDecl = maker.VarDef( + maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC), + typeNode.toName("log"), loggerType, factoryMethodCall); + + injectField(typeNode, fieldDecl); + return true; + } + + static interface LoggingFramework { + Class getAnnotationClass(); + String getLoggerTypeName(); + String getLoggerFactoryMethodName(); + JCExpression createFactoryParameter(JavacNode typeNode, String typeName); + } + + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + private static LoggingFramework COMMONS = new LoggingFramework() { + @Override public Class getAnnotationClass() { + return lombok.jul.Log.class; + } + + @Override public String getLoggerTypeName() { + return "org.apache.commons.logging.Log"; + } + + @Override public String getLoggerFactoryMethodName() { + return "org.apache.commons.logging.LogFactory.getLog"; + } + + @Override public JCExpression createFactoryParameter(JavacNode typeNode, String typeName) { + return chainDotsString(typeNode.getTreeMaker(), typeNode, typeName + ".class"); + } + }; + + /** + * Handles the {@link lombok.commons.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleCommonsLog implements JavacAnnotationHandler { + @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(COMMONS, annotation, annotationNode); + } + } + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger("TargetType"); + private static LoggingFramework JUL = new LoggingFramework() { + @Override public Class getAnnotationClass() { + return lombok.jul.Log.class; + } + + @Override public String getLoggerTypeName() { + return "java.util.logging.Logger"; + } + + @Override public String getLoggerFactoryMethodName() { + return "java.util.logging.Logger.getLogger"; + } + + @Override public JCExpression createFactoryParameter(JavacNode typeNode, String typeName) { + return typeNode.getTreeMaker().Literal(typeName); + } + }; + + /** + * Handles the {@link lombok.jul.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleJulLog implements JavacAnnotationHandler { + @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(JUL, annotation, annotationNode); + } + } + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + private static LoggingFramework LOG4J = new LoggingFramework() { + @Override public Class getAnnotationClass() { + return lombok.jul.Log.class; + } + + @Override public String getLoggerTypeName() { + return "org.apache.log4j.Logger"; + } + + @Override public String getLoggerFactoryMethodName() { + return "org.apache.log4j.Logger.getLogger"; + } + + @Override public JCExpression createFactoryParameter(JavacNode typeNode, String typeName) { + return chainDotsString(typeNode.getTreeMaker(), typeNode, typeName + ".class"); + } + }; + + /** + * Handles the {@link lombok.log4j.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleLog4jLog implements JavacAnnotationHandler { + @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(LOG4J, annotation, annotationNode); + } + } + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + private static LoggingFramework SLF4J = new LoggingFramework() { + @Override public Class getAnnotationClass() { + return lombok.slf4j.Log.class; + } + + @Override public String getLoggerTypeName() { + return "org.slf4j.Logger"; + } + + @Override public String getLoggerFactoryMethodName() { + return "org.slf4j.LoggerFactory.getLogger"; + } + + @Override public JCExpression createFactoryParameter(JavacNode typeNode, String typeName) { + return chainDotsString(typeNode.getTreeMaker(), typeNode, typeName + ".class"); + } + }; + + /** + * Handles the {@link lombok.slf4j.Log} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleSlf4jLog implements JavacAnnotationHandler { + @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + return processAnnotation(SLF4J, annotation, annotationNode); + } + } +} diff --git a/src/core/lombok/javac/handlers/HandleSlf4jLog.java b/src/core/lombok/javac/handlers/HandleSlf4jLog.java deleted file mode 100644 index 01e0b69e..00000000 --- a/src/core/lombok/javac/handlers/HandleSlf4jLog.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. - * - * 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.handlers; - -import static lombok.javac.handlers.JavacHandlerUtil.*; -import lombok.core.AnnotationValues; -import lombok.core.AST.Kind; -import lombok.javac.JavacAnnotationHandler; -import lombok.javac.JavacNode; -import lombok.slf4j.Log; - -import org.mangosdk.spi.ProviderFor; - -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.tree.JCTree.JCAnnotation; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.List; - -/** - * Handles the {@code lombok.slf4j.Log} annotation for javac. - */ -@ProviderFor(JavacAnnotationHandler.class) -public class HandleSlf4jLog implements JavacAnnotationHandler { - @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { - markAnnotationAsProcessed(annotationNode, Log.class); - - String loggingClassName = annotation.getRawExpression("value"); - if (loggingClassName == null) loggingClassName = "void.class"; - if (!loggingClassName.endsWith(".class")) loggingClassName = loggingClassName + ".class"; - - - JavacNode owner = annotationNode.up(); - switch (owner.getKind()) { - case TYPE: - if ((((JCClassDecl)owner.get()).mods.flags & Flags.INTERFACE)!= 0) { - annotationNode.addError("@Log is legal only on classes and enums."); - return true; - } - - if (loggingClassName.equals("void.class")) { - loggingClassName = getSelfName(owner); - } - return handleType(annotationNode, loggingClassName); - default: - annotationNode.addError("@Log is legal only on types."); - return true; - } - } - - private String getSelfName(JavacNode typeNode) { - String typeName = ((JCClassDecl) typeNode.get()).name.toString(); - JavacNode upType = typeNode.up(); - while (upType.getKind() == Kind.TYPE) { - typeName = ((JCClassDecl) upType.get()).name.toString() + "." + typeName; - upType = upType.up(); - } - - String packageDeclaration = typeNode.getPackageDeclaration(); - if (packageDeclaration != null) { - typeName = packageDeclaration + "." + typeName; - } - return typeName + ".class"; - } - - private boolean handleType(JavacNode annotation, String loggerClassName) { - JavacNode typeNode = annotation.up(); - - TreeMaker maker = typeNode.getTreeMaker(); - - switch (fieldExists("log", typeNode)) { - case NOT_EXISTS: - // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerLog4j.class); - JCExpression loggerType = chainDots(maker, typeNode, "org", "slf4j", "Logger"); - JCExpression factoryMethod = chainDots(maker, typeNode, "org", "slf4j", "LoggerFactory", "getLogger"); - - JCExpression loggerName = chainDots(maker, typeNode, loggerClassName.split("\\.")); - JCMethodInvocation factoryMethodCall = maker.Apply(List.nil(), factoryMethod, List.of(loggerName)); - - JCVariableDecl fieldDecl = maker.VarDef( - maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC), - typeNode.toName("log"), loggerType, factoryMethodCall); - - injectField(typeNode, fieldDecl); - return true; - case EXISTS_BY_USER: - annotation.addWarning("Field 'log' already exists."); - } - - return true; - } -} diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 3e734f8b..5dacf2ca 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -489,6 +489,21 @@ public class JavacHandlerUtil { return e; } + + + /** + * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} + * is represented by a fold-left of {@code Select} nodes with the leftmost string represented by + * a {@code Ident} node. This method generates such an expression. + * + * For example, maker.Select(maker.Select(maker.Ident(NAME[java]), NAME[lang]), NAME[String]). + * + * @see com.sun.tools.javac.tree.JCTree.JCIdent + * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess + */ + public static JCExpression chainDotsString(TreeMaker maker, JavacNode node, String elems) { + return chainDots(maker, node, elems.split("\\.")); + } /** * Searches the given field node for annotations and returns each one that matches the provided regular expression pattern. diff --git a/src/core/lombok/jul/Log.java b/src/core/lombok/jul/Log.java new file mode 100644 index 00000000..5d41d1df --- /dev/null +++ b/src/core/lombok/jul/Log.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.jul; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + + Class value() default void.class; +} diff --git a/src/core/lombok/log4j/Log.java b/src/core/lombok/log4j/Log.java new file mode 100644 index 00000000..6a0e6b0a --- /dev/null +++ b/src/core/lombok/log4j/Log.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * 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.log4j; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Log { + + Class value() default void.class; +} -- cgit