From a265f150acf0846ccecccd382ebc0adb190174b3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 1 Mar 2022 17:38:19 +0000 Subject: [PATCH] Improve parsing of numeric default values Previously, all integral numbers were parsed as integers. This caused two problems: 1. Compilation would fail if the default value for a long wasn't a valid integer. 2. The default value for a byte or short could be out of range, resulting in the generation of invalid metadata and an error that could have been caught at compile time not being caught until runtime. This commit updates the parsing of all numeric values to use the parse method of the target primitive type. For example, Short.parseShort(String) is now used to parse a short. Fixes gh-30020 --- ...onstructorParameterPropertyDescriptor.java | 38 ++++++++----------- ...uctorParameterPropertyDescriptorTests.java | 29 ++++++++------ 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java index d2fdc0787d19..dfc6f006530d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; @@ -106,21 +107,14 @@ private static class DefaultValueCoercionTypeVisitor extends TypeKindVisitor8 T parseNumber(String value, Function parser, + PrimitiveType primitiveType) { try { - return Integer.valueOf(value); + return parser.apply(value); } catch (NumberFormatException ex) { - throw new IllegalArgumentException(String.format("Invalid number representation '%s'", value)); - } - } - - private Double parseFloatingPoint(String value) { - try { - return Double.valueOf(value); - } - catch (NumberFormatException ex) { - throw new IllegalArgumentException(String.format("Invalid floating point representation '%s'", value)); + throw new IllegalArgumentException( + String.format("Invalid %s representation '%s'", primitiveType, value)); } } @@ -131,22 +125,22 @@ public Object visitPrimitiveAsBoolean(PrimitiveType t, String value) { @Override public Object visitPrimitiveAsByte(PrimitiveType t, String value) { - return parseInteger(value); + return parseNumber(value, Byte::parseByte, t); } @Override public Object visitPrimitiveAsShort(PrimitiveType t, String value) { - return parseInteger(value); + return parseNumber(value, Short::parseShort, t); } @Override public Object visitPrimitiveAsInt(PrimitiveType t, String value) { - return parseInteger(value); + return parseNumber(value, Integer::parseInt, t); } @Override public Object visitPrimitiveAsLong(PrimitiveType t, String value) { - return parseInteger(value); + return parseNumber(value, Long::parseLong, t); } @Override @@ -159,12 +153,12 @@ public Object visitPrimitiveAsChar(PrimitiveType t, String value) { @Override public Object visitPrimitiveAsFloat(PrimitiveType t, String value) { - return parseFloatingPoint(value); + return parseNumber(value, Float::parseFloat, t); } @Override public Object visitPrimitiveAsDouble(PrimitiveType t, String value) { - return parseFloatingPoint(value); + return parseNumber(value, Double::parseDouble, t); } } @@ -180,12 +174,12 @@ public Object visitPrimitiveAsBoolean(PrimitiveType t, Void ignore) { @Override public Object visitPrimitiveAsByte(PrimitiveType t, Void ignore) { - return 0; + return (byte) 0; } @Override public Object visitPrimitiveAsShort(PrimitiveType t, Void ignore) { - return 0; + return (short) 0; } @Override @@ -205,7 +199,7 @@ public Object visitPrimitiveAsChar(PrimitiveType t, Void ignore) { @Override public Object visitPrimitiveAsFloat(PrimitiveType t, Void ignore) { - return 0; + return 0F; } @Override diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptorTests.java index d3d6589315c7..c4a01ad1ca89 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -155,12 +155,13 @@ void constructorParameterPropertyWithPrimitiveTypes() throws IOException { process(ImmutablePrimitiveProperties.class, (roundEnv, metadataEnv) -> { TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveProperties.class); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "flag")).hasDefaultValue(false); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "octet")).hasDefaultValue(0); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "octet")).hasDefaultValue((byte) 0); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "letter")).hasDefaultValue(null); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "number")).hasDefaultValue(0); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "number")) + .hasDefaultValue((short) 0); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "counter")).hasDefaultValue(0); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(0L); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0F); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(0D); }); } @@ -170,12 +171,14 @@ void constructorParameterPropertyWithPrimitiveTypesAndDefaultValues() throws IOE process(ImmutablePrimitiveWithDefaultsProperties.class, (roundEnv, metadataEnv) -> { TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWithDefaultsProperties.class); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "flag")).hasDefaultValue(true); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "octet")).hasDefaultValue(120); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "octet")) + .hasDefaultValue((byte) 120); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "letter")).hasDefaultValue("a"); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "number")).hasDefaultValue(1000); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "number")) + .hasDefaultValue((short) 1000); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "counter")).hasDefaultValue(42); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000L); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5F); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(42.42); }); } @@ -185,12 +188,14 @@ void constructorParameterPropertyWithPrimitiveWrapperTypesAndDefaultValues() thr process(ImmutablePrimitiveWrapperWithDefaultsProperties.class, (roundEnv, metadataEnv) -> { TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWrapperWithDefaultsProperties.class); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "flag")).hasDefaultValue(true); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "octet")).hasDefaultValue(120); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "octet")) + .hasDefaultValue((byte) 120); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "letter")).hasDefaultValue("a"); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "number")).hasDefaultValue(1000); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "number")) + .hasDefaultValue((short) 1000); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "counter")).hasDefaultValue(42); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000); - assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000L); + assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5F); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(42.42); }); }