diff options
author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-07-09 00:46:03 +0200 |
---|---|---|
committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-07-09 00:46:03 +0200 |
commit | b7e67345b998e2a40ff63fabc893393cc9327596 (patch) | |
tree | 3e468ae52735d856b44821602001aeefd0c640b2 /src/core/lombok | |
parent | 0984d14826c62c5b99a2887aa198766ef08fea16 (diff) | |
parent | 5ad6796b182c8071fe747493ed2f9ad2443dc212 (diff) | |
download | lombok-b7e67345b998e2a40ff63fabc893393cc9327596.tar.gz lombok-b7e67345b998e2a40ff63fabc893393cc9327596.tar.bz2 lombok-b7e67345b998e2a40ff63fabc893393cc9327596.zip |
Merge branch 'customlog'
Diffstat (limited to 'src/core/lombok')
23 files changed, 801 insertions, 265 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 975cb72e..dda0b54b 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -25,7 +25,9 @@ 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; import lombok.core.configuration.TypeName; @@ -309,17 +311,16 @@ public class ConfigurationKeys { // ----- NonNull ----- /** - * lombok configuration: {@code lombok.nonNull.exceptionType} = <String: <em>a java exception type</em>; either [{@code IllegalArgumentException} or: {@code NullPointerException}]. + * lombok configuration: {@code lombok.nonNull.exceptionType} = one of: [{@code IllegalArgumentException}, {@code NullPointerException}, or {@code Assertion}]. * - * Sets the exception to throw if {@code @NonNull} is applied to a method parameter, and a caller passes in {@code null}. + * Sets the exception to throw if {@code @NonNull} is applied to a method parameter, and a caller passes in {@code null}. If the chosen configuration is {@code Assertion}, an assertion is generated instead, + * which would mean your code throws an {@code AssertionError} if assertions are enabled, and does nothing if assertions are not enabled. */ public static final ConfigurationKey<NullCheckExceptionType> NON_NULL_EXCEPTION_TYPE = new ConfigurationKey<NullCheckExceptionType>("lombok.nonNull.exceptionType", "The type of the exception to throw if a passed-in argument is null (Default: NullPointerException).") {}; /** * lombok configuration: {@code lombok.nonNull.flagUsage} = {@code WARNING} | {@code ERROR}. * - * <em>Implementation note: This field is supposed to be lombok.NonNull itself, but jdk6 and 7 have bugs where fields in annotations don't work well.</em> - * * If set, <em>any</em> usage of {@code @NonNull} results in a warning / error. */ public static final ConfigurationKey<FlagUsageType> NON_NULL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.nonNull.flagUsage", "Emit a warning or error if @NonNull is used.") {}; @@ -423,7 +424,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<String> LOG_ANY_FIELD_NAME = new ConfigurationKey<String>("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log').") {}; + public static final ConfigurationKey<IdentifierName> LOG_ANY_FIELD_NAME = new ConfigurationKey<IdentifierName>("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log').") {}; /** * lombok configuration: {@code lombok.log.fieldIsStatic} = {@code true} | {@code false}. @@ -434,6 +435,40 @@ public class ConfigurationKeys { */ public static final ConfigurationKey<Boolean> LOG_ANY_FIELD_IS_STATIC = new ConfigurationKey<Boolean>("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, <em>any</em> usage of {@code @CustomLog} results in a warning / error. + */ + public static final ConfigurationKey<FlagUsageType> LOG_CUSTOM_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.custom.flagUsage", "Emit a warning or error if @CustomLog is used.") {}; + + /** + * lombok configuration: {@code lombok.log.custom.declaration} = <logDeclaration string>. + * + * The log declaration must follow the pattern: + * <br> + * {@code [LoggerType ]LoggerFactoryType.loggerFactoryMethod(loggerFactoryMethodParams)[(loggerFactoryMethodParams)]} + * <br> + * It consists of: + * <ul> + * <li>Optional fully qualified logger type, e.g. {@code my.cool.Logger}, followed by space. If not specified, it defaults to the <em>LoggerFactoryType</em>. + * <li>Fully qualified logger factory type, e.g. {@code my.cool.LoggerFactory}, followed by dot. + * <li>Factory method, e.g. {@code createLogger}. This must be a {@code public static} method in the <em>LoggerFactoryType</em>. + * <li>At least one definition of factory method parameters, e.g. {@code ()} or {@code (TOPIC,TYPE)}. The format inside the parentheses is a comma-separated list of parameter kinds.<br> + * The allowed parameters are: {@code TYPE} | {@code NAME} | {@code TOPIC} | {@code NULL}.<br> + * There can be at most one parameter definition with {@code TOPIC} and at most one without {@code TOPIC}. You can specify both. + * </ul> + * + * An example: {@code my.cool.Logger my.cool.LoggerFactory.createLogger(TYPE)(TYPE,TOPIC)}<br> + * If no topic is provided in the usage of {@code @CustomLog}, the above will invoke {@code LoggerFactory}'s {@code createLogger} method, passing in the type as a {@code java.lang.Class} variable.<br> + * If a topic is provided, the overload of that method is invoked with 2 parameters: First the type (as {@code Class}), then the topic (as {@code String}). + * <p> + * If this configuration key is not set, any usage of {@code @CustomLog} will result in an error. + */ + public static final ConfigurationKey<LogDeclaration> LOG_CUSTOM_DECLARATION = new ConfigurationKey<LogDeclaration>("lombok.log.custom.declaration", "Define the generated custom logger field.") {}; + // ##### Experimental ##### /** @@ -548,7 +583,7 @@ public class ConfigurationKeys { * * The names of the constants generated by {@code @FieldNameConstants} will be prefixed with this value. */ - public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_INNER_TYPE_NAME = new ConfigurationKey<String>("lombok.fieldNameConstants.innerTypeName", "The default name of the inner type generated by @FieldNameConstants. (default: 'Fields').") {}; + public static final ConfigurationKey<IdentifierName> FIELD_NAME_CONSTANTS_INNER_TYPE_NAME = new ConfigurationKey<IdentifierName>("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/CustomLog.java b/src/core/lombok/CustomLog.java new file mode 100644 index 00000000..d1f45f7c --- /dev/null +++ b/src/core/lombok/CustomLog.java @@ -0,0 +1,75 @@ +/* + * 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 based on a custom logger implementation. + * <p> + * Complete documentation is found at <a href="https://projectlombok.org/features/Log">the project lombok features page for lombok log annotations</a>. + * <p> + * Example: + * <pre> + * @CustomLog + * public class LogExample { + * } + * </pre> + * With configuration: + * <pre> + * lombok.log.custom.declaration=my.cool.Logger my.cool.LoggerFactory.getLogger(NAME) + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final my.cool.Logger log = my.cool.LoggerFactory.getLogger(LogExample.class.getName()); + * } + * </pre> + * <p> + * Configuration must be provided in lombok.config, otherwise any usage of this annotation will result in a compile-time error. + * + * This annotation is valid for classes and enumerations.<br> + * @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 { + /** + * + * Sets a custom topic/category. Note that this requires you to specify a parameter configuration for your custom logger that includes {@code TOPIC}. + * + * @return The topic/category of the constructed Logger. By default (or for the empty string as topic), the parameter configuration without {@code TOPIC} is invoked. + */ + String topic() default ""; +} diff --git a/src/core/lombok/core/configuration/ConfigurationDataType.java b/src/core/lombok/core/configuration/ConfigurationDataType.java index 7512d2e6..50b47a2e 100644 --- a/src/core/lombok/core/configuration/ConfigurationDataType.java +++ b/src/core/lombok/core/configuration/ConfigurationDataType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -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,23 +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 "<fully.qualified.Type>"; - } - }); 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; @@ -145,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> 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; @@ -155,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; @@ -178,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); } @@ -203,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..a44a5a83 --- /dev/null +++ b/src/core/lombok/core/configuration/ConfigurationValueType.java @@ -0,0 +1,37 @@ +/* + * 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.core.configuration; + +/** + * If a type used in {@link ConfigurationKey} type argument implements this interface, + * it is expected to provide the following three static methods: + * <ul> + * <li><code>public static SELF valueOf(String value)</code> + * <li><code>public static String description()</code> + * <li><code>public static String exampleValue()</code> + * </ul> + * None of them should throw checked exceptions. + * 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 new file mode 100644 index 00000000..db83c2cc --- /dev/null +++ b/src/core/lombok/core/configuration/IdentifierName.java @@ -0,0 +1,69 @@ +/* + * 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.core.configuration; + +import lombok.core.JavaIdentifiers; + +public final class IdentifierName implements ConfigurationValueType { + 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); + } + + public static String description() { + return "identifier-name"; + } + + public static String exampleValue() { + return "<javaIdentifier>"; + } + + @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; + } + + public char[] getCharArray() { + return name.toCharArray(); + } +} diff --git a/src/core/lombok/core/configuration/LogDeclaration.java b/src/core/lombok/core/configuration/LogDeclaration.java new file mode 100644 index 00000000..ad4102d4 --- /dev/null +++ b/src/core/lombok/core/configuration/LogDeclaration.java @@ -0,0 +1,171 @@ +/* + * 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.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<LogFactoryParameter> parametersWithoutTopic; + private final List<LogFactoryParameter> parametersWithTopic; + + private LogDeclaration(TypeName loggerType, TypeName loggerFactoryType, IdentifierName loggerFactoryMethod, List<LogFactoryParameter> parametersWithoutTopic, List<LogFactoryParameter> 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<List<LogFactoryParameter>> allParameters = parseParameters(matcher.group(4)); + + List<LogFactoryParameter> parametersWithoutTopic = null; + List<LogFactoryParameter> parametersWithTopic = null; + for (List<LogFactoryParameter> parameters: allParameters) { + if (parameters.contains(LogFactoryParameter.TOPIC)) { + if (parametersWithTopic != null) throw new IllegalArgumentException("There is more than one parameter definition that includes TOPIC: " + parametersWithTopic + " and " + parameters); + parametersWithTopic = parameters; + } else { + if (parametersWithoutTopic != null) throw new IllegalArgumentException("There is more than one parmaeter definition that does not include TOPIC: " + parametersWithoutTopic + " and " + parameters); + parametersWithoutTopic = parameters; + } + } + + // sanity check (the pattern should disallow this situation + if (parametersWithoutTopic == null && parametersWithTopic == null) throw new IllegalArgumentException("No logger factory method parameters specified."); + + return new LogDeclaration(loggerType, loggerFactoryType, loggerFactoryMethod, parametersWithoutTopic, parametersWithTopic); + } + + private static List<List<LogFactoryParameter>> parseParameters(String parametersDefinitions) { + List<List<LogFactoryParameter>> allParameters = new ArrayList<List<LogFactoryParameter>>(); + Matcher matcher = PARAMETERS_PATTERN.matcher(parametersDefinitions); + while (matcher.find()) { + String parametersDefinition = matcher.group(1); + List<LogFactoryParameter> parameters = new ArrayList<LogFactoryParameter>(); + 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-declaration"; + } + + 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<LogFactoryParameter> 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<LogFactoryParameter> getParametersWithoutTopic() { + return parametersWithoutTopic; + } + + public List<LogFactoryParameter> getParametersWithTopic() { + return parametersWithTopic; + } +} diff --git a/src/core/lombok/core/configuration/TypeName.java b/src/core/lombok/core/configuration/TypeName.java index 989e1b97..a1eac7bd 100644 --- a/src/core/lombok/core/configuration/TypeName.java +++ b/src/core/lombok/core/configuration/TypeName.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -21,7 +21,9 @@ */ package lombok.core.configuration; -public final class TypeName { +import lombok.core.JavaIdentifiers; + +public final class TypeName implements ConfigurationValueType { private final String name; private TypeName(String name) { @@ -29,7 +31,21 @@ 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); + } + + public static String description() { + return "type-name"; + } + + public static String exampleValue() { + return "<fully.qualified.Type>"; } @Override public boolean equals(Object obj) { @@ -44,4 +60,12 @@ public final class TypeName { @Override public String toString() { return name; } + + public String getName() { + return name; + } + + public char[] getCharArray() { + return name.toCharArray(); + } } diff --git a/src/core/lombok/core/handlers/LoggingFramework.java b/src/core/lombok/core/handlers/LoggingFramework.java new file mode 100644 index 00000000..88c0317b --- /dev/null +++ b/src/core/lombok/core/handlers/LoggingFramework.java @@ -0,0 +1,98 @@ +/* + * 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.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<? extends Annotation> annotationClass; + private final String annotationAsString; + private final LogDeclaration declaration; + + public LoggingFramework(Class<? extends Annotation> annotationClass, LogDeclaration declaration) { + this.annotationClass = annotationClass; + this.annotationAsString = "@" + annotationClass.getSimpleName(); + this.declaration = declaration; + } + + public Class<? extends Annotation> getAnnotationClass() { + return annotationClass; + } + + public String getAnnotationAsString() { + return annotationAsString; + } + + public LogDeclaration getDeclaration() { + return declaration; + } +} diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 463990d1..1a0633bf 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -761,7 +761,7 @@ public class EclipseHandlerUtil { TypeReference typeRef = annotation.type; boolean match = false; if (typeRef != null && typeRef.getTypeName() != null) { - for (TypeName cn : configuredCopyable) if (typeMatches(cn.toString(), node, typeRef)) { + for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, typeRef)) { result.add(annotation); match = true; break; diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index 574c1f41..2db7591c 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<FieldNameConstants> { - 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<FieldName return; } - String innerTypeName = annotationInstance.innerTypeName(); - if (innerTypeName.isEmpty()) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME); - if (innerTypeName == null || innerTypeName.isEmpty()) innerTypeName = "Fields"; + IdentifierName innerTypeName; + try { + innerTypeName = IdentifierName.valueOf(annotationInstance.innerTypeName()); + } catch(IllegalArgumentException e) { + annotationNode.addError("InnerTypeName " + annotationInstance.innerTypeName() + " is not a valid Java identifier."); + return; + } + if (innerTypeName == null) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME); + if (innerTypeName == null) innerTypeName = FIELDS; Boolean uppercase = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_UPPERCASE); if (uppercase == null) uppercase = false; generateFieldNameConstantsForType(node, annotationNode, level, asEnum, innerTypeName, annotationInstance.onlyExplicitlyIncluded(), uppercase); } - private void createInnerTypeFieldNameConstants(EclipseNode typeNode, EclipseNode errorNode, ASTNode source, AccessLevel level, List<EclipseNode> fields, boolean asEnum, String innerTypeName, boolean uppercase) { + private void createInnerTypeFieldNameConstants(EclipseNode typeNode, EclipseNode errorNode, ASTNode source, AccessLevel level, List<EclipseNode> 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.getCharArray(); 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..7a140193 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-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 @@ -21,24 +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.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; @@ -47,7 +43,18 @@ 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; + public class HandleLog { + private static final IdentifierName LOG = IdentifierName.valueOf("log"); + private HandleLog() { throw new UnsupportedOperationException(); } @@ -57,8 +64,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)); @@ -66,24 +73,32 @@ public class HandleLog { if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get(); int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; - boolean notAClass = (modifiers & - (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; + boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; if (typeDecl == null || notAClass) { annotationNode.addError(framework.getAnnotationAsString() + " is legal only on classes and enums."); 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); + if (loggerTopic != null && loggerTopic.trim().isEmpty()) loggerTopic = null; + if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) { + annotationNode.addError(framework.getAnnotationAsString() + " does not allow a topic."); + loggerTopic = null; + } + if (framework.getDeclaration().getParametersWithoutTopic() == null && loggerTopic == null) { + annotationNode.addError(framework.getAnnotationAsString() + " requires a topic."); + loggerTopic = ""; + } - FieldDeclaration fieldDeclaration = createField(framework, source, loggingType, logFieldName, useStatic, loggerTopic); + 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 + // TODO temporary workaround for issue 290. https://github.com/rzwitserloot/lombok/issues/290 // injectFieldSuppressWarnings(owner, fieldDeclaration); injectField(owner, fieldDeclaration); owner.rebuild(); @@ -95,12 +110,12 @@ public class HandleLog { public static ClassLiteralAccess selfType(EclipseNode type, Annotation source) { int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - + long p = (long) pS << 32 | pE; + TypeDeclaration typeDeclaration = (TypeDeclaration)type.get(); TypeReference typeReference = new SingleTypeReference(typeDeclaration.name, p); setGeneratedBy(typeReference, source); - + ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, typeReference); setGeneratedBy(result, source); @@ -111,30 +126,23 @@ public class HandleLog { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; - // private static final <loggerType> log = <factoryMethod>(<parameter>); + // private static final <loggerType> log = <factoryMethod>(<parameter>); FieldDeclaration fieldDecl = new FieldDeclaration(logFieldName.toCharArray(), 0, -1); setGeneratedBy(fieldDecl, source); 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<LogFactoryParameter> 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; @@ -146,25 +154,64 @@ public class HandleLog { public static TypeReference createTypeReference(String typeName, Annotation source) { int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; + 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<LogFactoryParameter> 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. */ @@ -253,92 +300,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<lombok.CustomLog> { + @Override public void handle(AnnotationValues<lombok.CustomLog> 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 annotation 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/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index a45a499c..22f7f967 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -98,7 +98,7 @@ public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> { fieldDecl.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 }); setGeneratedBy(fieldDecl.type, source); fieldDecl.initialization = arrayAlloc; - // TODO temporary workaround for issue 217. http://code.google.com/p/projectlombok/issues/detail?id=217 + // TODO temporary workaround for issue 290. https://github.com/rzwitserloot/lombok/issues/290 // injectFieldSuppressWarnings(annotationNode.up().up(), fieldDecl); injectField(annotationNode.up().up(), fieldDecl); } 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/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<FieldNameConstants> { - 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<FieldNameCo return; } - String innerTypeName = annotationInstance.innerTypeName(); - if (innerTypeName.isEmpty()) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME); - if (innerTypeName == null || innerTypeName.isEmpty()) innerTypeName = "Fields"; + IdentifierName innerTypeName; + try { + innerTypeName = IdentifierName.valueOf(annotationInstance.innerTypeName()); + } catch(IllegalArgumentException e) { + annotationNode.addError("InnerTypeName " + annotationInstance.innerTypeName() + " is not a valid Java identifier."); + return; + } + if (innerTypeName == null) innerTypeName = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_INNER_TYPE_NAME); + if (innerTypeName == null) innerTypeName = FIELDS; Boolean uppercase = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_UPPERCASE); if (uppercase == null) uppercase = false; generateFieldNameConstantsForType(node, annotationNode, level, asEnum, innerTypeName, annotationInstance.onlyExplicitlyIncluded(), uppercase); } - private void createInnerTypeFieldNameConstants(JavacNode typeNode, JavacNode errorNode, JCTree pos, AccessLevel level, java.util.List<JavacNode> fields, boolean asEnum, String innerTypeName, boolean uppercase) { + private void createInnerTypeFieldNameConstants(JavacNode typeNode, JavacNode errorNode, JCTree pos, AccessLevel level, java.util.List<JavacNode> 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.<JCTypeParameter>nil(), null, List.<JCExpression>nil(), List.<JCTree>nil()); diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 6d742e76..522f8576 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-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 @@ -22,15 +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.MemberExistsResult; import org.mangosdk.spi.ProviderFor; @@ -46,32 +50,44 @@ 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(); } - + public static void processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode, String loggerTopic) { deleteAnnotationIfNeccessary(annotationNode, framework.getAnnotationClass()); - + 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)); - if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE) != 0) { - annotationNode.addError("@Log is legal only on classes and enums."); + if ((((JCClassDecl) typeNode.get()).mods.flags & Flags.INTERFACE) != 0) { + annotationNode.addError(framework.getAnnotationAsString() + " 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; } - + + if (loggerTopic != null && loggerTopic.trim().isEmpty()) loggerTopic = null; + if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) { + annotationNode.addError(framework.getAnnotationAsString() + " does not allow a topic."); + loggerTopic = null; + } + if (framework.getDeclaration().getParametersWithoutTopic() == null && loggerTopic == null) { + annotationNode.addError(framework.getAnnotationAsString() + " requires a topic."); + loggerTopic = ""; + } + 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."); @@ -88,29 +104,51 @@ public class HandleLog { private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String logFieldName, boolean useStatic, String loggerTopic) { JavacTreeMaker maker = typeNode.getTreeMaker(); + LogDeclaration logDeclaration = framework.getDeclaration(); // private static final <loggerType> log = <factoryMethod>(<parameter>); - JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName()); - JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName()); + JCExpression loggerType = chainDotsString(typeNode, logDeclaration.getLoggerType().getName()); + JCExpression factoryMethod = chainDotsString(typeNode, logDeclaration.getLoggerFactoryType().getName() + "." + logDeclaration.getLoggerFactoryMethod().getName()); - JCExpression loggerName; - if (!framework.passTypeName) { - loggerName = null; - } else if (loggerTopic == null || loggerTopic.trim().length() == 0) { - loggerName = framework.createFactoryParameter(typeNode, loggingType); - } else { - loggerName = maker.Literal(loggerTopic); - } - - JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, loggerName != null ? List.<JCExpression>of(loggerName) : List.<JCExpression>nil()); + java.util.List<LogFactoryParameter> parameters = loggerTopic != null ? logDeclaration.getParametersWithTopic() : logDeclaration.getParametersWithoutTopic(); + JCExpression[] factoryParameters = createFactoryParameters(typeNode, loggingType, parameters, loggerTopic); + JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>from(factoryParameters)); JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( - maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)), - typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext()); + maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)), + typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext()); injectFieldAndMarkGenerated(typeNode, fieldDecl); return true; } + private static JCExpression[] createFactoryParameters(JavacNode typeNode, JCFieldAccess loggingType, java.util.List<LogFactoryParameter> parameters, String loggerTopic) { + JCExpression[] expressions = new JCExpression[parameters.size()]; + JavacTreeMaker maker = typeNode.getTreeMaker(); + + for (int i = 0; i < parameters.size(); i++) { + LogFactoryParameter parameter = parameters.get(i); + switch (parameter) { + case TYPE: + expressions[i] = loggingType; + break; + case NAME: + JCExpression method = maker.Select(loggingType, typeNode.toName("getName")); + expressions[i] = maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil()); + break; + case TOPIC: + expressions[i] = maker.Literal(loggerTopic); + break; + case NULL: + expressions[i] = maker.Literal(CTC_BOT, null); + break; + default: + throw new IllegalStateException("Unknown logger factory parameter type: " + parameter); + } + } + + return expressions; + } + /** * Handles the {@link lombok.extern.apachecommons.CommonsLog} annotation for javac. */ @@ -199,71 +237,20 @@ public class HandleLog { } } - enum LoggingFramework { - // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); - COMMONS(lombok.extern.apachecommons.CommonsLog.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.java.Log.class, "java.util.logging.Logger", "java.util.logging.Logger.getLogger") { - @Override public JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { - JavacTreeMaker maker = typeNode.getTreeMaker(); - JCExpression method = maker.Select(loggingType, typeNode.toName("getName")); - return maker.Apply(List.<JCExpression>nil(), method, List.<JCExpression>nil()); + /** + * Handles the {@link lombok.CustomLog} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleCustomLog extends JavacAnnotationHandler<lombok.CustomLog> { + @Override public void handle(AnnotationValues<lombok.CustomLog> annotation, JCAnnotation ast, JavacNode 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(lombok.extern.log4j.Log4j.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger.getLogger"), - - // private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TargetType.class); - LOG4J2(lombok.extern.log4j.Log4j2.class, "org.apache.logging.log4j.Logger", "org.apache.logging.log4j.LogManager.getLogger"), - - // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class); - SLF4J(lombok.extern.slf4j.Slf4j.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory.getLogger"), - - // private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(TargetType.class); - XSLF4J(lombok.extern.slf4j.XSlf4j.class, "org.slf4j.ext.XLogger", "org.slf4j.ext.XLoggerFactory.getXLogger"), - - // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); - JBOSSLOG(lombok.extern.jbosslog.JBossLog.class, "org.jboss.logging.Logger", "org.jboss.logging.Logger.getLogger"), - - // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); - FLOGGER(lombok.extern.flogger.Flogger.class, "com.google.common.flogger.FluentLogger", "com.google.common.flogger.FluentLogger.forEnclosingClass", false), - ; - - private final Class<? extends Annotation> annotationClass; - private final String loggerTypeName; - private final String loggerFactoryName; - private final boolean passTypeName; - - LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName, boolean passTypeName) { - this.annotationClass = annotationClass; - this.loggerTypeName = loggerTypeName; - this.loggerFactoryName = loggerFactoryName; - this.passTypeName = passTypeName; - } - - LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName) { - this.annotationClass = annotationClass; - this.loggerTypeName = loggerTypeName; - this.loggerFactoryName = loggerFactoryName; - this.passTypeName = true; - } - - final Class<? extends Annotation> getAnnotationClass() { - return annotationClass; - } - - final String getLoggerTypeName() { - return loggerTypeName; - } - - final String getLoggerFactoryMethodName() { - return loggerFactoryName; - } - - JCExpression createFactoryParameter(JavacNode typeNode, JCFieldAccess loggingType) { - return loggingType; + LoggingFramework framework = new LoggingFramework(lombok.CustomLog.class, logDeclaration); + processAnnotation(framework, annotation, annotationNode, annotation.getInstance().topic()); } } } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index ee012d2b..6fa70ff3 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1450,7 +1450,7 @@ public class JavacHandlerUtil { java.util.List<TypeName> configuredCopyable = node.getAst().readConfiguration(ConfigurationKeys.COPYABLE_ANNOTATIONS); if (!annoName.isEmpty()) { - for (TypeName cn : configuredCopyable) if (typeMatches(cn.toString(), node, anno.annotationType)) return List.of(anno); + for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, anno.annotationType)) return List.of(anno); for (String bn : BASE_COPYABLE_ANNOTATIONS) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno); } @@ -1459,7 +1459,7 @@ public class JavacHandlerUtil { if (child.getKind() == Kind.ANNOTATION) { JCAnnotation annotation = (JCAnnotation) child.get(); boolean match = false; - for (TypeName cn : configuredCopyable) if (typeMatches(cn.toString(), node, annotation.annotationType)) { + for (TypeName cn : configuredCopyable) if (cn != null && typeMatches(cn.toString(), node, annotation.annotationType)) { result.append(annotation); match = true; break; |