/* * 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.eclipse.handlers; import static lombok.eclipse.Eclipse.fromQualifiedName; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; import java.util.Arrays; import lombok.core.AnnotationValues; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; public class HandleLog { private HandleLog() { throw new UnsupportedOperationException(); } public static void processAnnotation(LoggingFramework framework, AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { EclipseNode owner = annotationNode.up(); switch (owner.getKind()) { case TYPE: TypeDeclaration typeDecl = null; if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get(); int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; if (typeDecl == null || notAClass) { annotationNode.addError("@Log is legal only on classes and enums."); return; } if (fieldExists("log", owner) != MemberExistsResult.NOT_EXISTS) { annotationNode.addWarning("Field 'log' already exists."); return; } ClassLiteralAccess loggingType = selfType(owner, source); injectField(owner, createField(framework, source, loggingType)); owner.rebuild(); break; default: annotationNode.addError("@Log is legal only on types."); break; } } private static ClassLiteralAccess selfType(EclipseNode type, Annotation source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; TypeDeclaration typeDeclaration = (TypeDeclaration)type.get(); TypeReference typeReference = new SingleTypeReference(typeDeclaration.name, p); Eclipse.setGeneratedBy(typeReference, source); ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, typeReference); Eclipse.setGeneratedBy(result, source); return result; } private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; // private static final log = (); FieldDeclaration fieldDecl = new FieldDeclaration("log".toCharArray(), 0, -1); Eclipse.setGeneratedBy(fieldDecl, source); fieldDecl.declarationSourceEnd = -1; fieldDecl.modifiers = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source); MessageSend factoryMethodCall = new MessageSend(); Eclipse.setGeneratedBy(factoryMethodCall, source); factoryMethodCall.receiver = createNameReference(framework.getLoggerFactoryTypeName(), source); factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray(); Expression parameter = framework.createFactoryParameter(loggingType, source); factoryMethodCall.arguments = new Expression[] { parameter }; factoryMethodCall.nameSourcePosition = p; factoryMethodCall.sourceStart = pS; factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE; fieldDecl.initialization = factoryMethodCall; return fieldDecl; } private static TypeReference createTypeReference(String typeName, Annotation source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; TypeReference typeReference; if (typeName.contains(".")) { char[][] typeNameTokens = fromQualifiedName(typeName); long[] pos = new long[typeNameTokens.length]; Arrays.fill(pos, p); typeReference = new QualifiedTypeReference(typeNameTokens, pos); } else { typeReference = null; } Eclipse.setGeneratedBy(typeReference, source); return typeReference; } /** * Handles the {@link lombok.extern.apachecommons.CommonsLog} annotation for Eclipse. */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleCommonsLog implements EclipseAnnotationHandler { @Override public boolean deferUntilPostDiet() { return false; } @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode); } } /** * Handles the {@link lombok.extern.java.Log} annotation for Eclipse. */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleJulLog implements EclipseAnnotationHandler { @Override public boolean deferUntilPostDiet() { return false; } @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode); } } /** * Handles the {@link lombok.extern.log4j.Log4j} annotation for Eclipse. */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleLog4jLog implements EclipseAnnotationHandler { @Override public boolean deferUntilPostDiet() { return false; } @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode); } } /** * Handles the {@link lombok.extern.slf4j.Slf4j} annotation for Eclipse. */ @ProviderFor(EclipseAnnotationHandler.class) public static class HandleSlf4jLog implements EclipseAnnotationHandler { @Override public boolean deferUntilPostDiet() { return false; } @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode); } } enum LoggingFramework { // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); COMMONS("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("java.util.logging.Logger", "java.util.logging.Logger", "getLogger") { @Override public Expression createFactoryParameter(ClassLiteralAccess type, Annotation source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; MessageSend factoryParameterCall = new MessageSend(); Eclipse.setGeneratedBy(factoryParameterCall, source); factoryParameterCall.receiver = super.createFactoryParameter(type, source); factoryParameterCall.selector = "getName".toCharArray(); factoryParameterCall.nameSourcePosition = p; factoryParameterCall.sourceStart = pS; factoryParameterCall.sourceEnd = factoryParameterCall.statementEnd = pE; return factoryParameterCall; } }, // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); LOG4J("org.apache.log4j.Logger", "org.apache.log4j.Logger", "getLogger"), // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); SLF4J("org.slf4j.Logger", "org.slf4j.LoggerFactory", "getLogger"), ; private final String loggerTypeName; private final String loggerFactoryTypeName; private final String loggerFactoryMethodName; LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName) { this.loggerTypeName = loggerTypeName; this.loggerFactoryTypeName = loggerFactoryTypeName; this.loggerFactoryMethodName = loggerFactoryMethodName; } final String getLoggerTypeName() { return loggerTypeName; } final String getLoggerFactoryTypeName() { return loggerFactoryTypeName; } final String getLoggerFactoryMethodName() { return loggerFactoryMethodName; } Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source){ TypeReference copy = Eclipse.copyType(loggingType.type, source); ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); Eclipse.setGeneratedBy(result, source); return result; }; } }