Detect default enum value

This commit improves the configuration metadata annotation processor to
detect a default enum value. The algorithm is best-effort, similarly to
what it already does for well known prefixes (period, duration, etc).

Based on an expression and an identifier, the default value is inferred
if the expression matches the declaration of the property type.

See gh-7562
This commit is contained in:
Stéphane Nicoll
2024-08-01 13:19:34 +02:00
parent f4b4f4f0bf
commit 477bd7d15a
13 changed files with 233 additions and 50 deletions

View File

@@ -16,6 +16,9 @@
package org.springframework.boot.configurationprocessor;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Test;
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
@@ -50,6 +53,7 @@ import org.springframework.boot.configurationsample.specific.DeprecatedSimplePoj
import org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo;
import org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties;
import org.springframework.boot.configurationsample.specific.EmptyDefaultValueProperties;
import org.springframework.boot.configurationsample.specific.EnumValuesPojo;
import org.springframework.boot.configurationsample.specific.ExcludedTypesPojo;
import org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig;
import org.springframework.boot.configurationsample.specific.InnerClassHierarchicalProperties;
@@ -173,6 +177,15 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene
.fromSource(HierarchicalProperties.class));
}
@Test
void enumValues() {
ConfigurationMetadata metadata = compile(EnumValuesPojo.class);
assertThat(metadata).has(Metadata.withGroup("test").fromSource(EnumValuesPojo.class));
assertThat(metadata).has(Metadata.withProperty("test.seconds", ChronoUnit.class).withDefaultValue("seconds"));
assertThat(metadata)
.has(Metadata.withProperty("test.hour-of-day", ChronoField.class).withDefaultValue("hour-of-day"));
}
@Test
void descriptionProperties() {
ConfigurationMetadata metadata = compile(DescriptionProperties.class);

View File

@@ -48,7 +48,7 @@ public abstract class AbstractFieldValuesProcessorTests {
protected abstract FieldValuesParser createProcessor(ProcessingEnvironment env);
@Test
void getFieldValues() throws Exception {
void getFieldValues() {
TestProcessor processor = new TestProcessor();
TestCompiler compiler = TestCompiler.forSystem()
.withProcessors(processor)
@@ -105,6 +105,11 @@ public abstract class AbstractFieldValuesProcessorTests {
assertThat(values.get("periodMonths")).isEqualTo("10m");
assertThat(values.get("periodYears")).isEqualTo("15y");
assertThat(values.get("periodZero")).isEqualTo(0);
assertThat(values.get("enumNone")).isNull();
assertThat(values.get("enumSimple")).isEqualTo("seconds");
assertThat(values.get("enumQualified")).isEqualTo("hour-of-day");
assertThat(values.get("enumWithIndirection")).isNull();
assertThat(values.get("memberSelectInt")).isNull();
}
@SupportedAnnotationTypes({ "org.springframework.boot.configurationsample.ConfigurationProperties" })

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2024 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.
@@ -14,18 +14,18 @@
* limitations under the License.
*/
package org.springframework.boot.configurationprocessor.metadata;
package org.springframework.boot.configurationprocessor.support;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ConfigurationMetadata}.
* Tests for {@link ConventionUtils}.
*
* @author Stephane Nicoll
*/
class ConfigurationMetadataTests {
class ConventionUtilsTests {
@Test
void toDashedCaseCamelCase() {
@@ -78,7 +78,7 @@ class ConfigurationMetadataTests {
}
private String toDashedCase(String name) {
return ConfigurationMetadata.toDashedCase(name);
return ConventionUtils.toDashedCase(name);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2024 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.
@@ -20,6 +20,7 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import org.springframework.boot.configurationsample.ConfigurationProperties;
import org.springframework.util.MimeType;
@@ -151,4 +152,22 @@ public class FieldValues {
private Period periodZero = Period.ZERO;
private ChronoUnit enumNone;
private ChronoUnit enumSimple = ChronoUnit.SECONDS;
private java.time.temporal.ChronoField enumQualified = java.time.temporal.ChronoField.HOUR_OF_DAY;
private ChronoUnit enumWithIndirection = SampleOptions.DEFAULT_UNIT;
private int memberSelectInt = SampleOptions.DEFAULT_MAX_RETRIES;
public static class SampleOptions {
static final Integer DEFAULT_MAX_RETRIES = 20;
static final ChronoUnit DEFAULT_UNIT = ChronoUnit.SECONDS;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2012-2024 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.configurationsample.specific;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import org.springframework.boot.configurationsample.ConfigurationProperties;
/**
* Sample config for enum and default values.
*
* @author Stephane Nicoll
*/
@ConfigurationProperties("test")
public class EnumValuesPojo {
private ChronoUnit seconds = ChronoUnit.SECONDS;
private ChronoField hourOfDay = ChronoField.HOUR_OF_DAY;
public ChronoUnit getSeconds() {
return this.seconds;
}
public void setSeconds(ChronoUnit seconds) {
this.seconds = seconds;
}
public ChronoField getHourOfDay() {
return this.hourOfDay;
}
public void setHourOfDay(ChronoField hourOfDay) {
this.hourOfDay = hourOfDay;
}
}