From 4ea4b8d27bb13ad71e3cce2312dce6d488959fd7 Mon Sep 17 00:00:00 2001 From: Adam Juraszek Date: Thu, 9 May 2019 08:29:52 +0200 Subject: IdentifierName instead of String --- src/core/lombok/ConfigurationKeys.java | 5 +- .../core/configuration/ConfigurationDataType.java | 13 +++++ .../lombok/core/configuration/IdentifierName.java | 60 ++++++++++++++++++++++ src/core/lombok/core/configuration/TypeName.java | 17 +++++- .../eclipse/handlers/HandleFieldNameConstants.java | 23 ++++++--- src/core/lombok/eclipse/handlers/HandleLog.java | 11 ++-- .../javac/handlers/HandleFieldNameConstants.java | 23 ++++++--- src/core/lombok/javac/handlers/HandleLog.java | 11 ++-- 8 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 src/core/lombok/core/configuration/IdentifierName.java (limited to 'src') diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 84b594f5..f70590f9 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -26,6 +26,7 @@ import java.util.List; import lombok.core.configuration.CallSuperType; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; +import lombok.core.configuration.IdentifierName; import lombok.core.configuration.NullCheckExceptionType; import lombok.core.configuration.TypeName; @@ -416,7 +417,7 @@ public class ConfigurationKeys { * * If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name. */ - public static final ConfigurationKey LOG_ANY_FIELD_NAME = new ConfigurationKey("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log').") {}; + public static final ConfigurationKey LOG_ANY_FIELD_NAME = new ConfigurationKey("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log').") {}; /** * lombok configuration: {@code lombok.log.fieldIsStatic} = {@code true} | {@code false}. @@ -541,7 +542,7 @@ public class ConfigurationKeys { * * The names of the constants generated by {@code @FieldNameConstants} will be prefixed with this value. */ - public static final ConfigurationKey FIELD_NAME_CONSTANTS_INNER_TYPE_NAME = new ConfigurationKey("lombok.fieldNameConstants.innerTypeName", "The default name of the inner type generated by @FieldNameConstants. (default: 'Fields').") {}; + public static final ConfigurationKey FIELD_NAME_CONSTANTS_INNER_TYPE_NAME = new ConfigurationKey("lombok.fieldNameConstants.innerTypeName", "The default name of the inner type generated by @FieldNameConstants. (default: 'Fields').") {}; /** * lombok configuration: {@code lombok.fieldNameConstants.uppercase} = {@code true} | {@code false}. diff --git a/src/core/lombok/core/configuration/ConfigurationDataType.java b/src/core/lombok/core/configuration/ConfigurationDataType.java index 7512d2e6..40de65cf 100644 --- a/src/core/lombok/core/configuration/ConfigurationDataType.java +++ b/src/core/lombok/core/configuration/ConfigurationDataType.java @@ -110,6 +110,19 @@ public final class ConfigurationDataType { return ""; } }); + map.put(IdentifierName.class, new ConfigurationValueParser() { + @Override public Object parse(String value) { + return IdentifierName.valueOf(value); + } + + @Override public String description() { + return "identifier-name"; + } + + @Override public String exampleValue() { + return ""; + } + }); SIMPLE_TYPES = map; } diff --git a/src/core/lombok/core/configuration/IdentifierName.java b/src/core/lombok/core/configuration/IdentifierName.java new file mode 100644 index 00000000..fa8e03af --- /dev/null +++ b/src/core/lombok/core/configuration/IdentifierName.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Project Lombok Authors. + * + * 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.configuration; + +import lombok.core.JavaIdentifiers; + +public final class IdentifierName { + private final String name; + + private IdentifierName(String name) { + this.name = name; + } + + public static IdentifierName valueOf(String name) { + if (name == null || name.trim().isEmpty()) { + return null; + } + String trimmedName = name.trim(); + if (!JavaIdentifiers.isValidJavaIdentifier(trimmedName)) { + throw new IllegalArgumentException("Invalid identifier " + trimmedName); + } + return new IdentifierName(trimmedName); + } + + @Override public boolean equals(Object obj) { + if (!(obj instanceof IdentifierName)) return false; + return name.equals(((IdentifierName) obj).name); + } + + @Override public int hashCode() { + return name.hashCode(); + } + + @Override public String toString() { + return name; + } + + public String getName() { + return name; + } +} diff --git a/src/core/lombok/core/configuration/TypeName.java b/src/core/lombok/core/configuration/TypeName.java index 989e1b97..8bcb2e5a 100644 --- a/src/core/lombok/core/configuration/TypeName.java +++ b/src/core/lombok/core/configuration/TypeName.java @@ -21,6 +21,8 @@ */ package lombok.core.configuration; +import lombok.core.JavaIdentifiers; + public final class TypeName { private final String name; @@ -29,7 +31,16 @@ public final class TypeName { } public static TypeName valueOf(String name) { - return new TypeName(name); + if (name == null || name.trim().isEmpty()) { + return null; + } + String trimmedName = name.trim(); + for (String identifier : trimmedName.split(".")) { + if (!JavaIdentifiers.isValidJavaIdentifier(identifier)) { + throw new IllegalArgumentException("Invalid type name " + trimmedName + " (part " + identifier + ")"); + } + } + return new TypeName(trimmedName); } @Override public boolean equals(Object obj) { @@ -44,4 +55,8 @@ public final class TypeName { @Override public String toString() { return name; } + + public String getName() { + return name; + } } diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index 574c1f41..710a26f8 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -47,6 +47,7 @@ import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.configuration.IdentifierName; import lombok.core.handlers.HandlerUtil; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; @@ -56,7 +57,9 @@ import lombok.experimental.FieldNameConstants; @ProviderFor(EclipseAnnotationHandler.class) public class HandleFieldNameConstants extends EclipseAnnotationHandler { - public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit, boolean uppercase) { + private static final IdentifierName FIELDS = IdentifierName.valueOf("Fields"); + + public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, boolean asEnum, IdentifierName innerTypeName, boolean onlyExplicit, boolean uppercase) { TypeDeclaration typeDecl = null; if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get(); @@ -110,23 +113,29 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler fields, boolean asEnum, String innerTypeName, boolean uppercase) { + private void createInnerTypeFieldNameConstants(EclipseNode typeNode, EclipseNode errorNode, ASTNode source, AccessLevel level, List fields, boolean asEnum, IdentifierName innerTypeName, boolean uppercase) { if (fields.isEmpty()) return; ASTVisitor generatedByVisitor = new SetGeneratedByVisitor(source); TypeDeclaration parent = (TypeDeclaration) typeNode.get(); - EclipseNode fieldsType = findInnerClass(typeNode, innerTypeName); + EclipseNode fieldsType = findInnerClass(typeNode, innerTypeName.getName()); boolean genConstr = false, genClinit = false; - char[] name = innerTypeName.toCharArray(); + char[] name = innerTypeName.getName().toCharArray(); TypeDeclaration generatedInnerType = null; if (fieldsType == null) { generatedInnerType = new TypeDeclaration(parent.compilationResult); diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 8c7f7971..62ad8fab 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -30,6 +30,7 @@ import java.util.Arrays; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; +import lombok.core.configuration.IdentifierName; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; @@ -48,6 +49,8 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; public class HandleLog { + private static final IdentifierName LOG = IdentifierName.valueOf("log"); + private HandleLog() { throw new UnsupportedOperationException(); } @@ -57,8 +60,8 @@ public class HandleLog { switch (owner.getKind()) { case TYPE: - String logFieldName = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_NAME); - if (logFieldName == null) logFieldName = "log"; + IdentifierName logFieldName = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_NAME); + if (logFieldName == null) logFieldName = LOG; boolean useStatic = !Boolean.FALSE.equals(annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_IS_STATIC)); @@ -74,14 +77,14 @@ public class HandleLog { return; } - if (fieldExists(logFieldName, owner) != MemberExistsResult.NOT_EXISTS) { + if (fieldExists(logFieldName.getName(), owner) != MemberExistsResult.NOT_EXISTS) { annotationNode.addWarning("Field '" + logFieldName + "' already exists."); return; } ClassLiteralAccess loggingType = selfType(owner, source); - FieldDeclaration fieldDeclaration = createField(framework, source, loggingType, logFieldName, useStatic, loggerTopic); + FieldDeclaration fieldDeclaration = createField(framework, source, loggingType, logFieldName.getName(), useStatic, loggerTopic); fieldDeclaration.traverse(new SetGeneratedByVisitor(source), typeDecl.staticInitializerScope); // TODO temporary workaround for issue 217. http://code.google.com/p/projectlombok/issues/detail?id=217 // injectFieldSuppressWarnings(owner, fieldDeclaration); diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java index 628e83dc..ec4015c7 100644 --- a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java @@ -30,6 +30,7 @@ import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.configuration.IdentifierName; import lombok.core.handlers.HandlerUtil; import lombok.experimental.FieldNameConstants; import lombok.javac.JavacAnnotationHandler; @@ -54,7 +55,9 @@ import com.sun.tools.javac.util.Name; @ProviderFor(JavacAnnotationHandler.class) public class HandleFieldNameConstants extends JavacAnnotationHandler { - public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit, boolean uppercase) { + private static final IdentifierName FIELDS = IdentifierName.valueOf("Fields"); + + public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean asEnum, IdentifierName innerTypeName, boolean onlyExplicit, boolean uppercase) { JCClassDecl typeDecl = null; if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get(); @@ -115,24 +118,30 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler fields, boolean asEnum, String innerTypeName, boolean uppercase) { + private void createInnerTypeFieldNameConstants(JavacNode typeNode, JavacNode errorNode, JCTree pos, AccessLevel level, java.util.List fields, boolean asEnum, IdentifierName innerTypeName, boolean uppercase) { if (fields.isEmpty()) return; JavacTreeMaker maker = typeNode.getTreeMaker(); JCModifiers mods = maker.Modifiers(toJavacModifier(level) | (asEnum ? Flags.ENUM : Flags.STATIC | Flags.FINAL)); - Name fieldsName = typeNode.toName(innerTypeName); + Name fieldsName = typeNode.toName(innerTypeName.getName()); - JavacNode fieldsType = findInnerClass(typeNode, innerTypeName); + JavacNode fieldsType = findInnerClass(typeNode, innerTypeName.getName()); boolean genConstr = false; if (fieldsType == null) { JCClassDecl innerType = maker.ClassDef(mods, fieldsName, List.nil(), null, List.nil(), List.nil()); diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 6d742e76..da180cec 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -28,6 +28,7 @@ import java.lang.annotation.Annotation; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; +import lombok.core.configuration.IdentifierName; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -46,6 +47,8 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; public class HandleLog { + private static final IdentifierName LOG = IdentifierName.valueOf("log"); + private HandleLog() { throw new UnsupportedOperationException(); } @@ -56,8 +59,8 @@ public class HandleLog { JavacNode typeNode = annotationNode.up(); switch (typeNode.getKind()) { case TYPE: - String logFieldName = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_NAME); - if (logFieldName == null) logFieldName = "log"; + IdentifierName logFieldName = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_NAME); + if (logFieldName == null) logFieldName = LOG; boolean useStatic = !Boolean.FALSE.equals(annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_IS_STATIC)); @@ -65,13 +68,13 @@ public class HandleLog { annotationNode.addError("@Log is legal only on classes and enums."); return; } - if (fieldExists(logFieldName, typeNode) != MemberExistsResult.NOT_EXISTS) { + if (fieldExists(logFieldName.getName(), typeNode) != MemberExistsResult.NOT_EXISTS) { annotationNode.addWarning("Field '" + logFieldName + "' already exists."); return; } JCFieldAccess loggingType = selfType(typeNode); - createField(framework, typeNode, loggingType, annotationNode.get(), logFieldName, useStatic, loggerTopic); + createField(framework, typeNode, loggingType, annotationNode.get(), logFieldName.getName(), useStatic, loggerTopic); break; default: annotationNode.addError("@Log is legal only on types."); -- cgit From 399c516bd3a7d08830710e6eb1283897754805fd Mon Sep 17 00:00:00 2001 From: Adam Juraszek Date: Tue, 14 May 2019 09:27:19 +0200 Subject: Configuration types without explicit registration --- .../core/configuration/ConfigurationDataType.java | 82 ++++++++++++++-------- .../core/configuration/ConfigurationValueType.java | 36 ++++++++++ .../lombok/core/configuration/IdentifierName.java | 14 +++- src/core/lombok/core/configuration/TypeName.java | 14 +++- 4 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 src/core/lombok/core/configuration/ConfigurationValueType.java (limited to 'src') diff --git a/src/core/lombok/core/configuration/ConfigurationDataType.java b/src/core/lombok/core/configuration/ConfigurationDataType.java index 40de65cf..7dc77301 100644 --- a/src/core/lombok/core/configuration/ConfigurationDataType.java +++ b/src/core/lombok/core/configuration/ConfigurationDataType.java @@ -21,6 +21,8 @@ */ package lombok.core.configuration; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Arrays; @@ -97,36 +99,10 @@ public final class ConfigurationDataType { return "[false | true]"; } }); - map.put(TypeName.class, new ConfigurationValueParser() { - @Override public Object parse(String value) { - return TypeName.valueOf(value); - } - - @Override public String description() { - return "type-name"; - } - - @Override public String exampleValue() { - return ""; - } - }); - map.put(IdentifierName.class, new ConfigurationValueParser() { - @Override public Object parse(String value) { - return IdentifierName.valueOf(value); - } - - @Override public String description() { - return "identifier-name"; - } - - @Override public String exampleValue() { - return ""; - } - }); SIMPLE_TYPES = map; } - private static ConfigurationValueParser enumParser(Object enumType) { + private static ConfigurationValueParser enumParser(Type enumType) { final Class type = (Class) enumType; @SuppressWarnings("rawtypes") final Class rawType = type; @@ -158,6 +134,38 @@ public final class ConfigurationDataType { }; } + private static ConfigurationValueParser valueTypeParser(Type argumentType) { + final Class type = (Class) argumentType; + final Method valueOfMethod = getMethod(type, "valueOf", String.class); + final Method descriptionMethod = getMethod(type, "description"); + final Method exampleValueMethod = getMethod(type, "exampleValue"); + return new ConfigurationValueParser() { + @Override public Object parse(String value) { + return invokeStaticMethod(valueOfMethod, value); + } + + @Override public String description() { + return invokeStaticMethod(descriptionMethod); + } + + @Override public String exampleValue() { + return invokeStaticMethod(exampleValueMethod); + } + + @SuppressWarnings("unchecked") + private R invokeStaticMethod(Method method, Object... arguments) { + try { + return (R) method.invoke(null, arguments); + } catch (IllegalAccessException e) { + throw new IllegalStateException("The method " + method.getName() + " ", e); + } catch (InvocationTargetException e) { + // There shouldn't be any checked Exception, only IllegalArgumentException is expected + throw (RuntimeException) e.getTargetException(); + } + } + }; + } + private final boolean isList; private final ConfigurationValueParser parser; @@ -168,7 +176,7 @@ public final class ConfigurationDataType { Type type = keyClass.getGenericSuperclass(); if (!(type instanceof ParameterizedType)) { - throw new IllegalArgumentException("Missing type parameter in "+ type); + throw new IllegalArgumentException("Missing type parameter in " + type); } ParameterizedType parameterized = (ParameterizedType) type; @@ -191,6 +199,10 @@ public final class ConfigurationDataType { return new ConfigurationDataType(isList, enumParser(argumentType)); } + if (isConfigurationValueType(argumentType)) { + return new ConfigurationDataType(isList, valueTypeParser(argumentType)); + } + throw new IllegalArgumentException("Unsupported type parameter in " + type); } @@ -216,4 +228,18 @@ public final class ConfigurationDataType { private static boolean isEnum(Type argumentType) { return argumentType instanceof Class && ((Class) argumentType).isEnum(); } + + private static boolean isConfigurationValueType(Type argumentType) { + return argumentType instanceof Class && ConfigurationValueType.class.isAssignableFrom((Class) argumentType); + } + + private static Method getMethod(Class argumentType, String name, Class... parameterTypes) { + try { + return argumentType.getMethod(name, parameterTypes); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Method " + name + " with parameters " + Arrays.toString(parameterTypes) + "was not found.", e); + } catch (SecurityException e) { + throw new IllegalStateException("Cannot inspect methods of type " + argumentType, e); + } + } } \ No newline at end of file diff --git a/src/core/lombok/core/configuration/ConfigurationValueType.java b/src/core/lombok/core/configuration/ConfigurationValueType.java new file mode 100644 index 00000000..f287f62a --- /dev/null +++ b/src/core/lombok/core/configuration/ConfigurationValueType.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 The Project Lombok Authors. + * + * 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.configuration; + +/** + * If a type used in {@link ConfigurationKey} type argument implements this interface, + * it is expected to provide the following three static methods: + *
    + *
  • public static SELF valueOf(String value) + *
  • public static String description() + *
  • public static String exampleValue() + *
+ * Based on these methods, an instance of {@link ConfigurationValueParser} is created + * and used by the configuration system. + */ +public interface ConfigurationValueType { +} diff --git a/src/core/lombok/core/configuration/IdentifierName.java b/src/core/lombok/core/configuration/IdentifierName.java index fa8e03af..52e51bd7 100644 --- a/src/core/lombok/core/configuration/IdentifierName.java +++ b/src/core/lombok/core/configuration/IdentifierName.java @@ -23,7 +23,7 @@ package lombok.core.configuration; import lombok.core.JavaIdentifiers; -public final class IdentifierName { +public final class IdentifierName implements ConfigurationValueType { private final String name; private IdentifierName(String name) { @@ -41,6 +41,14 @@ public final class IdentifierName { return new IdentifierName(trimmedName); } + public static String description() { + return "identifier-name"; + } + + public static String exampleValue() { + return ""; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof IdentifierName)) return false; return name.equals(((IdentifierName) obj).name); @@ -57,4 +65,8 @@ public final class IdentifierName { public String getName() { return name; } + + public char[] getCharArray() { + return name.toCharArray(); + } } diff --git a/src/core/lombok/core/configuration/TypeName.java b/src/core/lombok/core/configuration/TypeName.java index 8bcb2e5a..a3128527 100644 --- a/src/core/lombok/core/configuration/TypeName.java +++ b/src/core/lombok/core/configuration/TypeName.java @@ -23,7 +23,7 @@ package lombok.core.configuration; import lombok.core.JavaIdentifiers; -public final class TypeName { +public final class TypeName implements ConfigurationValueType { private final String name; private TypeName(String name) { @@ -43,6 +43,14 @@ public final class TypeName { return new TypeName(trimmedName); } + public static String description() { + return "type-name"; + } + + public static String exampleValue() { + return ""; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof TypeName)) return false; return name.equals(((TypeName) obj).name); @@ -59,4 +67,8 @@ public final class TypeName { public String getName() { return name; } + + public char[] getCharArray() { + return name.toCharArray(); + } } -- cgit From bb66465751b8f0b129e53e639854f95fcdb3dca8 Mon Sep 17 00:00:00 2001 From: Adam Juraszek Date: Tue, 14 May 2019 11:57:21 +0200 Subject: Custom log declaration --- src/core/lombok/ConfigurationKeys.java | 31 +++ src/core/lombok/CustomLog.java | 70 +++++++ .../lombok/core/configuration/LogDeclaration.java | 179 ++++++++++++++++++ .../lombok/core/handlers/LoggingFramework.java | 77 ++++++++ src/core/lombok/eclipse/handlers/HandleLog.java | 207 +++++++++------------ .../lombok/extern/apachecommons/CommonsLog.java | 1 + src/core/lombok/extern/flogger/Flogger.java | 1 + src/core/lombok/extern/java/Log.java | 1 + src/core/lombok/extern/jbosslog/JBossLog.java | 3 +- src/core/lombok/extern/log4j/Log4j.java | 1 + src/core/lombok/extern/log4j/Log4j2.java | 1 + src/core/lombok/extern/slf4j/Slf4j.java | 1 + src/core/lombok/extern/slf4j/XSlf4j.java | 1 + src/core/lombok/javac/handlers/HandleLog.java | 137 ++++++-------- 14 files changed, 512 insertions(+), 199 deletions(-) create mode 100644 src/core/lombok/CustomLog.java create mode 100644 src/core/lombok/core/configuration/LogDeclaration.java create mode 100644 src/core/lombok/core/handlers/LoggingFramework.java (limited to 'src') diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index f70590f9..951b2893 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -25,6 +25,7 @@ import java.util.List; import lombok.core.configuration.CallSuperType; import lombok.core.configuration.ConfigurationKey; +import lombok.core.configuration.LogDeclaration; import lombok.core.configuration.FlagUsageType; import lombok.core.configuration.IdentifierName; import lombok.core.configuration.NullCheckExceptionType; @@ -428,6 +429,36 @@ public class ConfigurationKeys { */ public static final ConfigurationKey LOG_ANY_FIELD_IS_STATIC = new ConfigurationKey("lombok.log.fieldIsStatic", "Make the generated logger fields static (default: true).") {}; + // ----- Custom Logging ----- + + /** + * lombok configuration: {@code lombok.log.custom.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, any usage of {@code @CustomLog} results in a warning / error. + */ + public static final ConfigurationKey LOG_CUSTOM_FLAG_USAGE = new ConfigurationKey("lombok.log.custom.flagUsage", "Emit a warning or error if @CustomLog is used.") {}; + + /** + * lombok configuration: {@code lombok.log.custom.declaration} = <String: logDeclaration>. + * + * The log declaration must follow the pattern: + *
+ * {@code [LoggerType ]LoggerFactoryType.loggerFactoryMethod(loggerFactoryMethodParams)[(loggerFactoryMethodParams)]} + *
+ * It consists of: + *
    + *
  • Optional fully qualified logger type, e.g. {@code my.cool.Logger}, followed by space. If not specified, it defaults to the logger factory type. + *
  • Fully qualified logger factory type, e.g. {@code my.cool.LoggerFactory}, followed by dot. + *
  • Factory method, e.g. {@code createLogger}. The method must be defined on the logger factory type and must be static. + *
  • At least one definition of factory method parameters, e.g. {@code ()} or {@code (TOPIC,TYPE)}. The format is comma-separated list of parameters wrapped in parentheses. + * The allowed parameters are: {@code TYPE} | {@code NAME} | {@code TOPIC} | {@code NULL}. + * There can be at most one parameter definition with {@code TOPIC} and at most one without {@code TOPIC}. + *
+ * + * If not set, any usage of {@code @CustomLog} will result in an error. + */ + public static final ConfigurationKey LOG_CUSTOM_DECLARATION = new ConfigurationKey("lombok.log.custom.declaration", "Define the generated custom logger field.") {}; + // ##### Experimental ##### /** diff --git a/src/core/lombok/CustomLog.java b/src/core/lombok/CustomLog.java new file mode 100644 index 00000000..48c9f2ab --- /dev/null +++ b/src/core/lombok/CustomLog.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 The Project Lombok Authors. + * + * 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; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + *

+ * Complete documentation is found at the project lombok features page for lombok log annotations. + *

+ * Example: + *

+ * @CustomLog
+ * public class LogExample {
+ * }
+ * 
+ * With configuration: + *
+ * lombok.log.custom.declaration=my.cool.Logger my.cool.LoggerFactory.getLogger(NAME)
+ * 
+ * + * will generate: + * + *
+ * public class LogExample {
+ *     private static final my.cool.Logger log = my.cool.LoggerFactory.getLogger(LogExample.class.getName());
+ * }
+ * 
+ *

+ * Configuration must be provided in lombok.config, otherwise any usage will lead to errors. + * + * This annotation is valid for classes and enumerations.
+ * @see lombok.extern.java.Log @Log + * @see lombok.extern.apachecommons.CommonsLog @CommonsLog + * @see lombok.extern.log4j.Log4j @Log4j + * @see lombok.extern.log4j.Log4j2 @Log4j2 + * @see lombok.extern.slf4j.Slf4j @Slf4j + * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface CustomLog { + /** @return The category of the constructed Logger. By default, it will use the type where the annotation is placed. */ + String topic() default ""; +} diff --git a/src/core/lombok/core/configuration/LogDeclaration.java b/src/core/lombok/core/configuration/LogDeclaration.java new file mode 100644 index 00000000..36f280e2 --- /dev/null +++ b/src/core/lombok/core/configuration/LogDeclaration.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2013 The Project Lombok Authors. + * + * 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.configuration; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class LogDeclaration implements ConfigurationValueType { + private static final Pattern PARAMETERS_PATTERN = Pattern.compile("(?:\\(([A-Z,]*)\\))"); + private static final Pattern DECLARATION_PATTERN = Pattern.compile("^(?:([^ ]+) )?([^(]+)\\.([^(]+)(" + PARAMETERS_PATTERN.pattern() + "+)$"); + + public enum LogFactoryParameter { + TYPE, NAME, TOPIC, NULL; + } + + private final TypeName loggerType; + private final TypeName loggerFactoryType; + private final IdentifierName loggerFactoryMethod; + private final List parametersWithoutTopic; + private final List parametersWithTopic; + + private LogDeclaration(TypeName loggerType, TypeName loggerFactoryType, IdentifierName loggerFactoryMethod, List parametersWithoutTopic, List parametersWithTopic) { + this.loggerType = loggerType; + this.loggerFactoryType = loggerFactoryType; + this.loggerFactoryMethod = loggerFactoryMethod; + this.parametersWithoutTopic = parametersWithoutTopic; + this.parametersWithTopic = parametersWithTopic; + } + + public static LogDeclaration valueOf(String declaration) { + if (declaration == null) { + return null; + } + + Matcher matcher = DECLARATION_PATTERN.matcher(declaration); + if (!matcher.matches()) { + throw new IllegalArgumentException("The declaration must follow the pattern: [LoggerType ]LoggerFactoryType.loggerFactoryMethod(loggerFactoryMethodParams)[(loggerFactoryMethodParams)]"); + } + TypeName loggerFactoryType = TypeName.valueOf(matcher.group(2)); + TypeName loggerType = TypeName.valueOf(matcher.group(1)); + if (loggerType == null) loggerType = loggerFactoryType; + IdentifierName loggerFactoryMethod = IdentifierName.valueOf(matcher.group(3)); + List> allParameters = parseParameters(matcher.group(4)); + + List parametersWithoutTopic = null; + List parametersWithTopic = null; + for (List parameters: allParameters) { + if (parameters.contains(LogFactoryParameter.TOPIC)) { + if (parametersWithTopic != null) { + throw new IllegalArgumentException("There are too many parameters with TOPIC: " + parametersWithTopic + " and " + parameters); + } + parametersWithTopic = parameters; + } else { + if (parametersWithoutTopic != null) { + throw new IllegalArgumentException("There are too many parameters without TOPIC: " + parametersWithoutTopic + " and " + parameters); + } + parametersWithoutTopic = parameters; + } + } + if (parametersWithoutTopic == null && parametersWithTopic == null) { + // shouldn't happen the pattern does not allow it + throw new IllegalArgumentException("No logger factory method parameters specified."); + } + + return new LogDeclaration(loggerType, loggerFactoryType, loggerFactoryMethod, parametersWithoutTopic, parametersWithTopic); + } + + private static List> parseParameters(String parametersDefinitions) { + List> allParameters = new ArrayList>(); + Matcher matcher = PARAMETERS_PATTERN.matcher(parametersDefinitions); + while (matcher.find()) { + String parametersDefinition = matcher.group(1); + List parameters = new ArrayList(); + if (!parametersDefinition.isEmpty()) { + for (String parameter : parametersDefinition.split(",")) { + parameters.add(LogFactoryParameter.valueOf(parameter)); + } + } + allParameters.add(parameters); + } + return allParameters; + } + + public static String description() { + return "custom-log-declartation"; + } + + public static String exampleValue() { + return "my.cool.Logger my.cool.LoggerFactory.createLogger()(TOPIC,TYPE)"; + } + + @Override public boolean equals(Object obj) { + if (!(obj instanceof LogDeclaration)) return false; + return loggerType.equals(((LogDeclaration) obj).loggerType) + && loggerFactoryType.equals(((LogDeclaration) obj).loggerFactoryType) + && loggerFactoryMethod.equals(((LogDeclaration) obj).loggerFactoryMethod) + && parametersWithoutTopic == ((LogDeclaration) obj).parametersWithoutTopic || parametersWithoutTopic.equals(((LogDeclaration) obj).parametersWithoutTopic) + && parametersWithTopic == ((LogDeclaration) obj).parametersWithTopic || parametersWithTopic.equals(((LogDeclaration) obj).parametersWithTopic); + } + + @Override public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + loggerType.hashCode(); + result = prime * result + loggerFactoryType.hashCode(); + result = prime * result + loggerFactoryMethod.hashCode(); + result = prime * result + ((parametersWithTopic == null) ? 0 : parametersWithTopic.hashCode()); + result = prime * result + ((parametersWithoutTopic == null) ? 0 : parametersWithoutTopic.hashCode()); + return result; + } + + @Override public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(loggerType); + sb.append(" "); + sb.append(loggerFactoryType); + sb.append("."); + sb.append(loggerFactoryMethod); + appendParams(sb, parametersWithoutTopic); + appendParams(sb, parametersWithTopic); + return sb.toString(); + } + + private static void appendParams(StringBuilder sb, List params) { + if (params != null) { + sb.append("("); + boolean first = true; + for (LogFactoryParameter param : params) { + if (!first) { + sb.append(","); + } + first = false; + sb.append(param); + } + sb.append(")"); + } + } + + public TypeName getLoggerType() { + return loggerType; + } + + public TypeName getLoggerFactoryType() { + return loggerFactoryType; + } + + public IdentifierName getLoggerFactoryMethod() { + return loggerFactoryMethod; + } + + public List getParametersWithoutTopic() { + return parametersWithoutTopic; + } + + public List getParametersWithTopic() { + return parametersWithTopic; + } +} diff --git a/src/core/lombok/core/handlers/LoggingFramework.java b/src/core/lombok/core/handlers/LoggingFramework.java new file mode 100644 index 00000000..38eadd17 --- /dev/null +++ b/src/core/lombok/core/handlers/LoggingFramework.java @@ -0,0 +1,77 @@ +package lombok.core.handlers; + +import java.lang.annotation.Annotation; + +import lombok.core.configuration.LogDeclaration; + +public class LoggingFramework { + // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); + public static final LoggingFramework COMMONS = new LoggingFramework( + lombok.extern.apachecommons.CommonsLog.class, + LogDeclaration.valueOf("org.apache.commons.logging.Log org.apache.commons.logging.LogFactory.getLog(TYPE)(TOPIC)") + ); + + // private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(TargetType.class.getName()); + public static final LoggingFramework JUL = new LoggingFramework( + lombok.extern.java.Log.class, + LogDeclaration.valueOf("java.util.logging.Logger java.util.logging.Logger.getLogger(NAME)(TOPIC)") + ); + + // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class); + public static final LoggingFramework LOG4J = new LoggingFramework( + lombok.extern.log4j.Log4j.class, + LogDeclaration.valueOf("org.apache.log4j.Logger org.apache.log4j.Logger.getLogger(TYPE)(TOPIC)") + ); + + // private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TargetType.class); + public static final LoggingFramework LOG4J2 = new LoggingFramework( + lombok.extern.log4j.Log4j2.class, + LogDeclaration.valueOf("org.apache.logging.log4j.Logger org.apache.logging.log4j.LogManager.getLogger(TYPE)(TOPIC)") + ); + + // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); + public static final LoggingFramework SLF4J = new LoggingFramework( + lombok.extern.slf4j.Slf4j.class, + LogDeclaration.valueOf("org.slf4j.Logger org.slf4j.LoggerFactory.getLogger(TYPE)(TOPIC)") + ); + + // private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(TargetType.class); + public static final LoggingFramework XSLF4J = new LoggingFramework( + lombok.extern.slf4j.XSlf4j.class, + LogDeclaration.valueOf("org.slf4j.ext.XLogger org.slf4j.ext.XLoggerFactory.getXLogger(TYPE)(TOPIC)") + ); + + // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); + public static final LoggingFramework JBOSSLOG = new LoggingFramework( + lombok.extern.jbosslog.JBossLog.class, + LogDeclaration.valueOf("org.jboss.logging.Logger org.jboss.logging.Logger.getLogger(TYPE)(TOPIC)") + ); + + // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + public static final LoggingFramework FLOGGER = new LoggingFramework( + lombok.extern.flogger.Flogger.class, + LogDeclaration.valueOf("com.google.common.flogger.FluentLogger com.google.common.flogger.FluentLogger.forEnclosingClass()") + ); + + private final Class annotationClass; + private final String annotationAsString; + private final LogDeclaration declaration; + + public LoggingFramework(Class annotationClass, LogDeclaration declaration) { + this.annotationClass = annotationClass; + this.annotationAsString = "@" + annotationClass.getSimpleName(); + this.declaration = declaration; + } + + public Class getAnnotationClass() { + return annotationClass; + } + + public String getAnnotationAsString() { + return annotationAsString; + } + + public LogDeclaration getDeclaration() { + return declaration; + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 62ad8fab..e445685d 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -21,25 +21,20 @@ */ package lombok.eclipse.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.eclipse.Eclipse.fromQualifiedName; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; import java.util.Arrays; - -import lombok.ConfigurationKeys; -import lombok.core.AnnotationValues; -import lombok.core.configuration.IdentifierName; -import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; +import java.util.List; 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.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; @@ -48,6 +43,16 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; +import lombok.ConfigurationKeys; +import lombok.core.AnnotationValues; +import lombok.core.configuration.IdentifierName; +import lombok.core.configuration.LogDeclaration; +import lombok.core.configuration.LogDeclaration.LogFactoryParameter; +import lombok.core.handlers.LoggingFramework; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; + public class HandleLog { private static final IdentifierName LOG = IdentifierName.valueOf("log"); @@ -82,8 +87,12 @@ public class HandleLog { return; } - ClassLiteralAccess loggingType = selfType(owner, source); + if (loggerTopic != null && loggerTopic.trim().isEmpty()) loggerTopic = null; + if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) { + annotationNode.addError(framework.getAnnotationAsString() + " does not allow to set a topic."); + } + ClassLiteralAccess loggingType = selfType(owner, source); FieldDeclaration fieldDeclaration = createField(framework, source, loggingType, logFieldName.getName(), useStatic, loggerTopic); fieldDeclaration.traverse(new SetGeneratedByVisitor(source), typeDecl.staticInitializerScope); // TODO temporary workaround for issue 217. http://code.google.com/p/projectlombok/issues/detail?id=217 @@ -120,24 +129,17 @@ public class HandleLog { fieldDecl.declarationSourceEnd = -1; fieldDecl.modifiers = Modifier.PRIVATE | (useStatic ? Modifier.STATIC : 0) | Modifier.FINAL; - fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source); + LogDeclaration logDeclaration = framework.getDeclaration(); + fieldDecl.type = createTypeReference(logDeclaration.getLoggerType().getName(), source); MessageSend factoryMethodCall = new MessageSend(); setGeneratedBy(factoryMethodCall, source); - factoryMethodCall.receiver = createNameReference(framework.getLoggerFactoryTypeName(), source); - factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray(); - - Expression parameter; - if (!framework.passTypeName) { - parameter = null; - } else if (loggerTopic == null || loggerTopic.trim().length() == 0) { - parameter = framework.createFactoryParameter(loggingType, source); - } else { - parameter = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0); - } + factoryMethodCall.receiver = createNameReference(logDeclaration.getLoggerFactoryType().getName(), source); + factoryMethodCall.selector = logDeclaration.getLoggerFactoryMethod().getCharArray(); - factoryMethodCall.arguments = parameter != null ? new Expression[] { parameter } : null; + List parameters = loggerTopic != null ? logDeclaration.getParametersWithTopic() : logDeclaration.getParametersWithoutTopic(); + factoryMethodCall.arguments = createFactoryParameters(loggingType, source, parameters, loggerTopic); factoryMethodCall.nameSourcePosition = p; factoryMethodCall.sourceStart = pS; factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE; @@ -151,22 +153,61 @@ public class HandleLog { 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; - } + char[][] typeNameTokens = fromQualifiedName(typeName); + long[] pos = new long[typeNameTokens.length]; + Arrays.fill(pos, p); + TypeReference typeReference = new QualifiedTypeReference(typeNameTokens, pos); setGeneratedBy(typeReference, source); return typeReference; } + + private static final Expression[] createFactoryParameters(ClassLiteralAccess loggingType, Annotation source, List parameters, String loggerTopic) { + Expression[] expressions = new Expression[parameters.size()]; + int pS = source.sourceStart, pE = source.sourceEnd; + + for (int i = 0; i < parameters.size(); i++) { + LogFactoryParameter parameter = parameters.get(i); + + switch(parameter) { + case TYPE: + expressions[i] = createFactoryTypeParameter(loggingType, source); + break; + case NAME: + long p = (long)pS << 32 | pE; + + MessageSend factoryParameterCall = new MessageSend(); + setGeneratedBy(factoryParameterCall, source); + + factoryParameterCall.receiver = createFactoryTypeParameter(loggingType, source); + factoryParameterCall.selector = "getName".toCharArray(); + + factoryParameterCall.nameSourcePosition = p; + factoryParameterCall.sourceStart = pS; + factoryParameterCall.sourceEnd = factoryParameterCall.statementEnd = pE; + + expressions[i] = factoryParameterCall; + break; + case TOPIC: + expressions[i] = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0); + break; + case NULL: + expressions[i] = new NullLiteral(pS, pE); + break; + default: + throw new IllegalStateException("Unknown logger factory parameter type: " + parameter); + } + } + + return expressions; + } + + private static final Expression createFactoryTypeParameter(ClassLiteralAccess loggingType, Annotation source) { + TypeReference copy = copyType(loggingType.type, source); + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); + setGeneratedBy(result, source); + return result; + } /** * Handles the {@link lombok.extern.apachecommons.CommonsLog} annotation for Eclipse. @@ -256,92 +297,20 @@ public class HandleLog { } } - 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", "@CommonsLog"), - - // 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", "@Log") { - @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(); - 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; + /** + * Handles the {@link lombok.CustomLog} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleCustomLog extends EclipseAnnotationHandler { + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.LOG_CUSTOM_FLAG_USAGE, "@CustomLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); + LogDeclaration logDeclaration = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_CUSTOM_DECLARATION); + if (logDeclaration == null) { + annotationNode.addError("The @CustomLog is not configured; please set log.custom.declaration in lombok.config."); + return; } - }, - - // 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", "@Log4j"), - - // private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TargetType.class); - LOG4J2("org.apache.logging.log4j.Logger", "org.apache.logging.log4j.LogManager", "getLogger", "@Log4j2"), - - // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); - SLF4J("org.slf4j.Logger", "org.slf4j.LoggerFactory", "getLogger", "@Slf4j"), - - // private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(TargetType.class); - XSLF4J("org.slf4j.ext.XLogger", "org.slf4j.ext.XLoggerFactory", "getXLogger", "@XSlf4j"), - - // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); - JBOSSLOG("org.jboss.logging.Logger", "org.jboss.logging.Logger", "getLogger", "@JBossLog"), - - // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); - FLOGGER("com.google.common.flogger.FluentLogger", "com.google.common.flogger.FluentLogger", "forEnclosingClass", "@Flogger", false), - ; - - private final String loggerTypeName; - private final String loggerFactoryTypeName; - private final String loggerFactoryMethodName; - private final String annotationAsString; - private final boolean passTypeName; - - LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName, String annotationAsString, boolean passTypeName) { - this.loggerTypeName = loggerTypeName; - this.loggerFactoryTypeName = loggerFactoryTypeName; - this.loggerFactoryMethodName = loggerFactoryMethodName; - this.annotationAsString = annotationAsString; - this.passTypeName = passTypeName; - } - - LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName, String annotationAsString) { - this.loggerTypeName = loggerTypeName; - this.loggerFactoryTypeName = loggerFactoryTypeName; - this.loggerFactoryMethodName = loggerFactoryMethodName; - this.annotationAsString = annotationAsString; - this.passTypeName = true; - } - - final String getAnnotationAsString() { - return annotationAsString; - } - - final String getLoggerTypeName() { - return loggerTypeName; + LoggingFramework framework = new LoggingFramework(lombok.CustomLog.class, logDeclaration); + processAnnotation(framework, annotation, source, annotationNode, annotation.getInstance().topic()); } - - final String getLoggerFactoryTypeName() { - return loggerFactoryTypeName; - } - - final String getLoggerFactoryMethodName() { - return loggerFactoryMethodName; - } - - Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source) { - TypeReference copy = copyType(loggingType.type, source); - ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); - setGeneratedBy(result, source); - return result; - }; } } diff --git a/src/core/lombok/extern/apachecommons/CommonsLog.java b/src/core/lombok/extern/apachecommons/CommonsLog.java index fa3d6f09..ca808329 100644 --- a/src/core/lombok/extern/apachecommons/CommonsLog.java +++ b/src/core/lombok/extern/apachecommons/CommonsLog.java @@ -57,6 +57,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog * @see lombok.extern.flogger.Flogger @Flogger + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/flogger/Flogger.java b/src/core/lombok/extern/flogger/Flogger.java index ecbfd28c..3446e949 100644 --- a/src/core/lombok/extern/flogger/Flogger.java +++ b/src/core/lombok/extern/flogger/Flogger.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/java/Log.java b/src/core/lombok/extern/java/Log.java index 9a1ee412..f2b5024f 100644 --- a/src/core/lombok/extern/java/Log.java +++ b/src/core/lombok/extern/java/Log.java @@ -56,6 +56,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog * @see lombok.extern.flogger.Flogger @Flogger + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/jbosslog/JBossLog.java b/src/core/lombok/extern/jbosslog/JBossLog.java index 684585e0..960a111b 100644 --- a/src/core/lombok/extern/jbosslog/JBossLog.java +++ b/src/core/lombok/extern/jbosslog/JBossLog.java @@ -56,7 +56,8 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.flogger.Flogger @Flogger - * */ + * @see lombok.CustomLog @CustomLog + */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface JBossLog { diff --git a/src/core/lombok/extern/log4j/Log4j.java b/src/core/lombok/extern/log4j/Log4j.java index 249ef71a..1b4a973b 100644 --- a/src/core/lombok/extern/log4j/Log4j.java +++ b/src/core/lombok/extern/log4j/Log4j.java @@ -57,6 +57,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog * @see lombok.extern.flogger.Flogger @Flogger + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/log4j/Log4j2.java b/src/core/lombok/extern/log4j/Log4j2.java index a6aa90c0..571b0563 100644 --- a/src/core/lombok/extern/log4j/Log4j2.java +++ b/src/core/lombok/extern/log4j/Log4j2.java @@ -57,6 +57,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog * @see lombok.extern.flogger.Flogger @Flogger + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/slf4j/Slf4j.java b/src/core/lombok/extern/slf4j/Slf4j.java index 347d81d2..c4aded24 100644 --- a/src/core/lombok/extern/slf4j/Slf4j.java +++ b/src/core/lombok/extern/slf4j/Slf4j.java @@ -56,6 +56,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog * @see lombok.extern.flogger.Flogger @Flogger + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/slf4j/XSlf4j.java b/src/core/lombok/extern/slf4j/XSlf4j.java index 4d53a1eb..b99554a5 100644 --- a/src/core/lombok/extern/slf4j/XSlf4j.java +++ b/src/core/lombok/extern/slf4j/XSlf4j.java @@ -56,6 +56,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog * @see lombok.extern.flogger.Flogger @Flogger + * @see lombok.CustomLog @CustomLog */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index da180cec..a00cc496 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -22,16 +22,19 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.javac.Javac.CTC_BOT; import static lombok.javac.handlers.JavacHandlerUtil.*; -import java.lang.annotation.Annotation; - import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; import lombok.core.configuration.IdentifierName; +import lombok.core.configuration.LogDeclaration; +import lombok.core.configuration.LogDeclaration.LogFactoryParameter; +import lombok.core.handlers.LoggingFramework; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.JavacHandlerUtil.MemberExists