/* * 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.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; 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.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; 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); JCExpression annotationValue = (JCExpression) annotation.getActualExpression("value"); JCFieldAccess loggingType = null; if (annotationValue != null) { if (!(annotationValue instanceof JCFieldAccess)) return true; loggingType = (JCFieldAccess) annotationValue; if (!loggingType.name.contentEquals("class")) return true; } 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 (loggingType == null) { loggingType = selfType(typeNode); } createField(framework, typeNode, loggingType); return true; default: annotationNode.addError("@Log is legal only on types."); return true; } } private static JCFieldAccess selfType(JavacNode typeNode) { TreeMaker maker = typeNode.getTreeMaker(); Name name = ((JCClassDecl) typeNode.get()).name; return maker.Select(maker.Ident(name), typeNode.toName("class")); } private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType) { 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, loggingType); 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; } /** * Handles the {@link lombok.extern.apachecommons.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(LoggingFramework.COMMONS, annotation, annotationNode); } @Override public boolean isResolutionBased() { return false; } } /** * Handles the {@link lombok.extern.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(LoggingFramework.JUL, annotation, annotationNode); } @Override public boolean isResolutionBased() { return false; } } /** * Handles the {@link lombok.extern.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(LoggingFramework.LOG4J, annotation, annotationNode); } @Override public boolean isResolutionBased() { return false; } } /** * Handles the {@link lombok.extern.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(LoggingFramework.SLF4J, annotation, annotationNode); } @Override public boolean isResolutionBased() { return false; } } enum LoggingFramework { // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); COMMONS(lombok.extern.jul.Log.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"), // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); JUL(lombok.extern.jul.Log.class, "java.util.logging.Logger", "java.util.logging.Logger.getLogger") { @Override public JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { TreeMaker maker = typeNode.getTreeMaker(); JCExpression method = maker.Select(loggingType, typeNode.toName("getName")); return maker.Apply(List.nil(), method, List.nil()); } }, // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); LOG4J(lombok.extern.jul.Log.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger.getLogger"), // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); SLF4J(lombok.extern.slf4j.Log.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory.getLogger"), ; private final Class annotationClass; private final String loggerTypeName; private final String loggerFactoryName; LoggingFramework(Class annotationClass, String loggerTypeName, String loggerFactoryName) { this.annotationClass = annotationClass; this.loggerTypeName = loggerTypeName; this.loggerFactoryName = loggerFactoryName; } final Class getAnnotationClass() { return annotationClass; } final String getLoggerTypeName() { return loggerTypeName; } final String getLoggerFactoryMethodName() { return loggerFactoryName; } JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { return loggingType; } } }