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
pull/30505/head
Andy Wilkinson 3 years ago
parent 355f80ab98
commit a265f150ac

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package org.springframework.boot.configurationprocessor;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
@ -106,21 +107,14 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable
private static final DefaultValueCoercionTypeVisitor INSTANCE = new DefaultValueCoercionTypeVisitor(); private static final DefaultValueCoercionTypeVisitor INSTANCE = new DefaultValueCoercionTypeVisitor();
private Integer parseInteger(String value) { private <T extends Number> T parseNumber(String value, Function<String, T> parser,
PrimitiveType primitiveType) {
try { try {
return Integer.valueOf(value); return parser.apply(value);
} }
catch (NumberFormatException ex) { catch (NumberFormatException ex) {
throw new IllegalArgumentException(String.format("Invalid number representation '%s'", value)); throw new IllegalArgumentException(
} String.format("Invalid %s representation '%s'", primitiveType, 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));
} }
} }
@ -131,22 +125,22 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable
@Override @Override
public Object visitPrimitiveAsByte(PrimitiveType t, String value) { public Object visitPrimitiveAsByte(PrimitiveType t, String value) {
return parseInteger(value); return parseNumber(value, Byte::parseByte, t);
} }
@Override @Override
public Object visitPrimitiveAsShort(PrimitiveType t, String value) { public Object visitPrimitiveAsShort(PrimitiveType t, String value) {
return parseInteger(value); return parseNumber(value, Short::parseShort, t);
} }
@Override @Override
public Object visitPrimitiveAsInt(PrimitiveType t, String value) { public Object visitPrimitiveAsInt(PrimitiveType t, String value) {
return parseInteger(value); return parseNumber(value, Integer::parseInt, t);
} }
@Override @Override
public Object visitPrimitiveAsLong(PrimitiveType t, String value) { public Object visitPrimitiveAsLong(PrimitiveType t, String value) {
return parseInteger(value); return parseNumber(value, Long::parseLong, t);
} }
@Override @Override
@ -159,12 +153,12 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable
@Override @Override
public Object visitPrimitiveAsFloat(PrimitiveType t, String value) { public Object visitPrimitiveAsFloat(PrimitiveType t, String value) {
return parseFloatingPoint(value); return parseNumber(value, Float::parseFloat, t);
} }
@Override @Override
public Object visitPrimitiveAsDouble(PrimitiveType t, String value) { public Object visitPrimitiveAsDouble(PrimitiveType t, String value) {
return parseFloatingPoint(value); return parseNumber(value, Double::parseDouble, t);
} }
} }
@ -180,12 +174,12 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable
@Override @Override
public Object visitPrimitiveAsByte(PrimitiveType t, Void ignore) { public Object visitPrimitiveAsByte(PrimitiveType t, Void ignore) {
return 0; return (byte) 0;
} }
@Override @Override
public Object visitPrimitiveAsShort(PrimitiveType t, Void ignore) { public Object visitPrimitiveAsShort(PrimitiveType t, Void ignore) {
return 0; return (short) 0;
} }
@Override @Override
@ -205,7 +199,7 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable
@Override @Override
public Object visitPrimitiveAsFloat(PrimitiveType t, Void ignore) { public Object visitPrimitiveAsFloat(PrimitiveType t, Void ignore) {
return 0; return 0F;
} }
@Override @Override

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -155,12 +155,13 @@ class ConstructorParameterPropertyDescriptorTests extends PropertyDescriptorTest
process(ImmutablePrimitiveProperties.class, (roundEnv, metadataEnv) -> { process(ImmutablePrimitiveProperties.class, (roundEnv, metadataEnv) -> {
TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveProperties.class); TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveProperties.class);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "flag")).hasDefaultValue(false); 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, "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, "counter")).hasDefaultValue(0);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(0L); 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); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(0D);
}); });
} }
@ -170,12 +171,14 @@ class ConstructorParameterPropertyDescriptorTests extends PropertyDescriptorTest
process(ImmutablePrimitiveWithDefaultsProperties.class, (roundEnv, metadataEnv) -> { process(ImmutablePrimitiveWithDefaultsProperties.class, (roundEnv, metadataEnv) -> {
TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWithDefaultsProperties.class); TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWithDefaultsProperties.class);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "flag")).hasDefaultValue(true); 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, "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, "counter")).hasDefaultValue(42);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000L);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5F);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(42.42); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(42.42);
}); });
} }
@ -185,12 +188,14 @@ class ConstructorParameterPropertyDescriptorTests extends PropertyDescriptorTest
process(ImmutablePrimitiveWrapperWithDefaultsProperties.class, (roundEnv, metadataEnv) -> { process(ImmutablePrimitiveWrapperWithDefaultsProperties.class, (roundEnv, metadataEnv) -> {
TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWrapperWithDefaultsProperties.class); TypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWrapperWithDefaultsProperties.class);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "flag")).hasDefaultValue(true); 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, "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, "counter")).hasDefaultValue(42);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(2000L);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "percentage")).hasDefaultValue(0.5F);
assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(42.42); assertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(42.42);
}); });
} }

Loading…
Cancel
Save