From 713822db9894cf99184aff57b3387f99846aa870 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 27 May 2014 20:29:54 +0200 Subject: Changed the lombok.nonNull.exceptionType configkey to be an enum, partly to enforce only sensible exceptions and partly to make it possible to have the message be ‘x is null’ when throwing IAEs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/lombok/ConfigurationKeys.java | 7 ++-- src/core/lombok/core/FlagUsageType.java | 6 --- .../core/configuration/ConfigurationDataType.java | 36 +++++++++++++--- .../core/configuration/ExampleValueString.java | 37 +++++++++++++++++ .../lombok/core/configuration/FlagUsageType.java | 27 ++++++++++++ .../core/configuration/NullCheckExceptionType.java | 48 ++++++++++++++++++++++ src/core/lombok/core/handlers/HandlerUtil.java | 26 +----------- .../eclipse/handlers/EclipseHandlerUtil.java | 21 ++++------ .../lombok/javac/handlers/JavacHandlerUtil.java | 16 +++----- 9 files changed, 161 insertions(+), 63 deletions(-) delete mode 100644 src/core/lombok/core/FlagUsageType.java create mode 100644 src/core/lombok/core/configuration/ExampleValueString.java create mode 100644 src/core/lombok/core/configuration/FlagUsageType.java create mode 100644 src/core/lombok/core/configuration/NullCheckExceptionType.java (limited to 'src/core/lombok') diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index a93af395..427c5f83 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -23,8 +23,9 @@ package lombok; import java.util.List; -import lombok.core.FlagUsageType; import lombok.core.configuration.ConfigurationKey; +import lombok.core.configuration.FlagUsageType; +import lombok.core.configuration.NullCheckExceptionType; /** * A container class containing all lombok configuration keys that do not belong to a specific annotation. @@ -181,11 +182,11 @@ public class ConfigurationKeys { // ----- NonNull ----- /** - * lombok configuration: {@code lombok.nonNull.exceptionType} = <String: a java exception type, such as {@code java.lang.IllegalArgumentException}> (default: {@code java.lang.NullPointerException}). + * lombok configuration: {@code lombok.nonNull.exceptionType} = <String: a java exception type; either [{@code IllegalArgumentException} or: {@code NullPointerException}]. * * Sets the exception to throw if {@code @NonNull} is applied to a method parameter, and a caller passes in {@code null}. */ - public static final ConfigurationKey NON_NULL_EXCEPTION_TYPE = new ConfigurationKey("lombok.nonNull.exceptionType", "The type of the exception to throw if a passed-in argument is null.") {}; + public static final ConfigurationKey NON_NULL_EXCEPTION_TYPE = new ConfigurationKey("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}. diff --git a/src/core/lombok/core/FlagUsageType.java b/src/core/lombok/core/FlagUsageType.java deleted file mode 100644 index 42770ef1..00000000 --- a/src/core/lombok/core/FlagUsageType.java +++ /dev/null @@ -1,6 +0,0 @@ -package lombok.core; - -/** Used for lombok configuration to flag usages of certain lombok feature. */ -public enum FlagUsageType { - WARNING, ERROR; -} diff --git a/src/core/lombok/core/configuration/ConfigurationDataType.java b/src/core/lombok/core/configuration/ConfigurationDataType.java index ca0302ff..fa65f575 100644 --- a/src/core/lombok/core/configuration/ConfigurationDataType.java +++ b/src/core/lombok/core/configuration/ConfigurationDataType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Project Lombok Authors. + * Copyright (C) 2013-2014 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 @@ -36,9 +36,11 @@ public final class ConfigurationDataType { @Override public Object parse(String value) { return value; } + @Override public String description() { return "string"; } + @Override public String exampleValue() { return ""; } @@ -47,9 +49,11 @@ public final class ConfigurationDataType { @Override public Object parse(String value) { return Integer.parseInt(value); } + @Override public String description() { return "int"; } + @Override public String exampleValue() { return ""; } @@ -58,9 +62,11 @@ public final class ConfigurationDataType { @Override public Object parse(String value) { return Long.parseLong(value); } + @Override public String description() { return "long"; } + @Override public String exampleValue() { return ""; } @@ -69,9 +75,11 @@ public final class ConfigurationDataType { @Override public Object parse(String value) { return Double.parseDouble(value); } + @Override public String description() { return "double"; } + @Override public String exampleValue() { return ""; } @@ -80,9 +88,11 @@ public final class ConfigurationDataType { @Override public Object parse(String value) { return Boolean.parseBoolean(value); } + @Override public String description() { return "boolean"; } + @Override public String exampleValue() { return "[false | true]"; } @@ -91,9 +101,11 @@ public final class ConfigurationDataType { @Override public Object parse(String value) { return TypeName.valueOf(value); } + @Override public String description() { return "type-name"; } + @Override public String exampleValue() { return ""; } @@ -102,21 +114,33 @@ public final class ConfigurationDataType { } private static ConfigurationValueParser enumParser(Object enumType) { - @SuppressWarnings("rawtypes") final Class rawType = (Class)enumType; - return new ConfigurationValueParser(){ + final Class type = (Class) enumType; + @SuppressWarnings("rawtypes") final Class rawType = type; + + return new ConfigurationValueParser() { @SuppressWarnings("unchecked") @Override public Object parse(String value) { try { return Enum.valueOf(rawType, value); } catch (Exception e) { - return Enum.valueOf(rawType, value.toUpperCase()); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (Character.isUpperCase(c) && i > 0) sb.append("_"); + sb.append(Character.toUpperCase(c)); + } + return Enum.valueOf(rawType, sb.toString()); } } + @Override public String description() { - return "enum (" + rawType.getName() + ")"; + return "enum (" + type.getName() + ")"; } + @Override public String exampleValue() { - return Arrays.toString(rawType.getEnumConstants()).replace(",", " |"); + ExampleValueString evs = type.getAnnotation(ExampleValueString.class); + if (evs != null) return evs.value(); + return Arrays.toString(type.getEnumConstants()).replace(",", " |"); } }; } diff --git a/src/core/lombok/core/configuration/ExampleValueString.java b/src/core/lombok/core/configuration/ExampleValueString.java new file mode 100644 index 00000000..10cb1295 --- /dev/null +++ b/src/core/lombok/core/configuration/ExampleValueString.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * If a configuration key has an enum type, then the 'example values' string is built up by just joining all enum keys together with a bar separator, but you + * can add this annotation to the enum type to override this string. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ExampleValueString { + String value(); +} diff --git a/src/core/lombok/core/configuration/FlagUsageType.java b/src/core/lombok/core/configuration/FlagUsageType.java new file mode 100644 index 00000000..b7053b7c --- /dev/null +++ b/src/core/lombok/core/configuration/FlagUsageType.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 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; + +/** Used for lombok configuration to flag usages of certain lombok feature. */ +public enum FlagUsageType { + WARNING, ERROR; +} diff --git a/src/core/lombok/core/configuration/NullCheckExceptionType.java b/src/core/lombok/core/configuration/NullCheckExceptionType.java new file mode 100644 index 00000000..18a332fd --- /dev/null +++ b/src/core/lombok/core/configuration/NullCheckExceptionType.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 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; + + +@ExampleValueString("[NullPointerException | IllegalArgumentException]") +public enum NullCheckExceptionType { + ILLEGAL_ARGUMENT_EXCEPTION { + public String toExceptionMessage(String fieldName) { + return fieldName + " is null"; + } + + @Override public String getExceptionType() { + return "java.lang.IllegalArgumentException"; + } + }, + NULL_POINTER_EXCEPTION { + @Override public String toExceptionMessage(String fieldName) { + return fieldName; + } + + public String getExceptionType() { + return "java.lang.NullPointerException"; + } + }; + + public abstract String toExceptionMessage(String fieldName); + public abstract String getExceptionType(); +} diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index cbfd3f8c..0d48b624 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -41,10 +41,10 @@ import lombok.ToString; import lombok.Value; import lombok.core.AST; import lombok.core.AnnotationValues; -import lombok.core.FlagUsageType; import lombok.core.JavaIdentifiers; import lombok.core.LombokNode; import lombok.core.configuration.ConfigurationKey; +import lombok.core.configuration.FlagUsageType; import lombok.experimental.Accessors; import lombok.experimental.FieldDefaults; import lombok.experimental.Wither; @@ -68,30 +68,6 @@ public class HandlerUtil { return 97; } - /** Checks if the input is a valid class reference (not a primitive and does not have generics). */ - public static boolean isLegalBasicClassReference(String in) { - boolean atStartOfIdentifier = true; - - for (int i = 0; i < in.length(); i++) { - char c = in.charAt(i); - - if (atStartOfIdentifier) { - if (!Character.isJavaIdentifierStart(c)) return false; - atStartOfIdentifier = false; - continue; - } - - if (c == '.') { - atStartOfIdentifier = true; - continue; - } - - if (!Character.isJavaIdentifierPart(c)) return false; - } - - return !atStartOfIdentifier; - } - /** Checks if the given name is a valid identifier. * * If it is, this returns {@code true} and does nothing else. diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 022cad91..874efb4e 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -46,6 +46,7 @@ import lombok.core.AnnotationValues.AnnotationValue; import lombok.core.BooleanFieldAugment; import lombok.core.ReferenceFieldAugment; import lombok.core.TypeResolver; +import lombok.core.configuration.NullCheckExceptionType; import lombok.core.handlers.HandlerUtil; import lombok.eclipse.EclipseAST; import lombok.eclipse.EclipseNode; @@ -1402,15 +1403,8 @@ public class EclipseHandlerUtil { * @param exName The name of the exception to throw; normally {@code java.lang.NullPointerException}. */ public static Statement generateNullCheck(AbstractVariableDeclaration variable, EclipseNode sourceNode) { - String exceptionType = sourceNode.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE); - if (exceptionType == null) { - exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; - } else { - if (!HandlerUtil.isLegalBasicClassReference(exceptionType)) { - sourceNode.addWarning("Configuration key contains invalid java type reference '" + exceptionType + "'; use something like 'java.lang.NullPointerException' as value for this key."); - exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; - } - } + NullCheckExceptionType exceptionType = sourceNode.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE); + if (exceptionType == null) exceptionType = NullCheckExceptionType.NULL_POINTER_EXCEPTION; ASTNode source = sourceNode.get(); @@ -1421,12 +1415,15 @@ public class EclipseHandlerUtil { AllocationExpression exception = new AllocationExpression(); setGeneratedBy(exception, source); int partCount = 0; - for (int i = 0; i < exceptionType.length(); i++) if (exceptionType.charAt(i) == '.') partCount++; + String exceptionTypeStr = exceptionType.getExceptionType(); + for (int i = 0; i < exceptionTypeStr.length(); i++) if (exceptionTypeStr.charAt(i) == '.') partCount++; long[] ps = new long[partCount]; Arrays.fill(ps, 0L); - exception.type = new QualifiedTypeReference(fromQualifiedName(exceptionType), ps); + exception.type = new QualifiedTypeReference(fromQualifiedName(exceptionTypeStr), ps); setGeneratedBy(exception.type, source); - exception.arguments = new Expression[] { new StringLiteral(variable.name, pS, pE, 0)}; + exception.arguments = new Expression[] { + new StringLiteral(exceptionType.toExceptionMessage(new String(variable.name)).toCharArray(), pS, pE, 0) + }; setGeneratedBy(exception.arguments[0], source); ThrowStatement throwStatement = new ThrowStatement(exception, pS, pE); setGeneratedBy(throwStatement, source); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 524af5de..6a60a420 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -43,6 +43,7 @@ import lombok.core.AnnotationValues; import lombok.core.AnnotationValues.AnnotationValue; import lombok.core.ReferenceFieldAugment; import lombok.core.TypeResolver; +import lombok.core.configuration.NullCheckExceptionType; import lombok.core.handlers.HandlerUtil; import lombok.delombok.LombokOptionsFactory; import lombok.experimental.Accessors; @@ -1046,21 +1047,14 @@ public class JavacHandlerUtil { * @param exName The name of the exception to throw; normally {@code java.lang.NullPointerException}. */ public static JCStatement generateNullCheck(JavacTreeMaker maker, JavacNode variable, JavacNode source) { - String exceptionType = source.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE); - if (exceptionType == null) { - exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; - } else { - if (!HandlerUtil.isLegalBasicClassReference(exceptionType)) { - source.addWarning("Configuration key contains invalid java type reference '" + exceptionType + "'; use something like 'java.lang.NullPointerException' as value for this key."); - exceptionType = HandlerUtil.DEFAULT_EXCEPTION_FOR_NON_NULL; - } - } + NullCheckExceptionType exceptionType = source.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE); + if (exceptionType == null) exceptionType = NullCheckExceptionType.NULL_POINTER_EXCEPTION; JCVariableDecl varDecl = (JCVariableDecl) variable.get(); if (isPrimitive(varDecl.vartype)) return null; Name fieldName = varDecl.name; - JCExpression exType = genTypeRef(variable, exceptionType); - JCExpression exception = maker.NewClass(null, List.nil(), exType, List.of(maker.Literal(fieldName.toString())), null); + JCExpression exType = genTypeRef(variable, exceptionType.getExceptionType()); + JCExpression exception = maker.NewClass(null, List.nil(), exType, List.of(maker.Literal(exceptionType.toExceptionMessage(fieldName.toString()))), null); JCStatement throwStatement = maker.Throw(exception); JCBlock throwBlock = maker.Block(0, List.of(throwStatement)); return maker.If(maker.Binary(CTC_EQUAL, maker.Ident(fieldName), maker.Literal(CTC_BOT, null)), throwBlock, null); -- cgit