Allow @DefaultValue to be used on record components

See gh-29010
This commit is contained in:
Pavel Anisimov 2021-12-10 19:48:05 +03:00 committed by Andy Wilkinson
parent 1793cee00f
commit 976ed90cd7
4 changed files with 62 additions and 2 deletions

View File

@ -74,6 +74,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Andy Wilkinson
* @author Kris De Volder
* @author Jonas Keßler
* @author Pavel Anisimov
*/
class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGenerationTests {
@ -445,4 +446,24 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene
assertThat(metadata).doesNotHave(Metadata.withProperty("multi.some-integer"));
}
@Test
@EnabledForJreRange(min = JRE.JAVA_16)
void recordPropertiesWithDefaultValues(@TempDir File temp) throws IOException {
File exampleRecord = new File(temp, "ExampleRecord.java");
try (PrintWriter writer = new PrintWriter(new FileWriter(exampleRecord))) {
writer.println(
"@org.springframework.boot.configurationsample.ConfigurationProperties(\"record.defaults\")");
writer.println("public record ExampleRecord(");
writer.println("@org.springframework.boot.configurationsample.DefaultValue(\"An1s9n\") String someString,");
writer.println("@org.springframework.boot.configurationsample.DefaultValue(\"594\") Integer someInteger");
writer.println(") {");
writer.println("}");
}
ConfigurationMetadata metadata = compile(exampleRecord);
assertThat(metadata)
.has(Metadata.withProperty("record.defaults.some-string", String.class).withDefaultValue("An1s9n"));
assertThat(metadata)
.has(Metadata.withProperty("record.defaults.some-integer", Integer.class).withDefaultValue(594));
}
}

View File

@ -27,8 +27,9 @@ import java.lang.annotation.Target;
* dependency on the real annotation).
*
* @author Stephane Nicoll
* @author Pavel Anisimov
*/
@Target({ ElementType.PARAMETER })
@Target({ ElementType.PARAMETER, ElementType.RECORD_COMPONENT })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DefaultValue {

View File

@ -37,10 +37,11 @@ import java.lang.annotation.Target;
* must be constant.
*
* @author Madhura Bhave
* @author Pavel Anisimov
* @since 2.2.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
@Target({ ElementType.PARAMETER, ElementType.RECORD_COMPONENT })
@Documented
public @interface DefaultValue {

View File

@ -16,23 +16,35 @@
package org.springframework.boot.context.properties.bind;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MockConfigurationPropertySource;
import org.springframework.boot.testsupport.compiler.TestCompiler;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.Assert;
import static org.assertj.core.api.Assertions.assertThat;
@ -43,6 +55,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*
* @author Madhura Bhave
* @author Phillip Webb
* @author Pavel Anisimov
*/
class ValueObjectBinderTests {
@ -357,6 +370,30 @@ class ValueObjectBinderTests {
assertThat(bound.getImportName()).isEqualTo("test");
}
@Test
@EnabledForJreRange(min = JRE.JAVA_16)
void bindToRecordWithDefaultValue(@TempDir File tempDir) throws IOException, ClassNotFoundException {
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("test.record.property1", "value-from-config-1");
this.sources.add(source);
File recordProperties = new File(tempDir, "RecordProperties.java");
try (PrintWriter writer = new PrintWriter(new FileWriter(recordProperties))) {
writer.println("public record RecordProperties(");
writer.println(
"@org.springframework.boot.context.properties.bind.DefaultValue(\"default-value-1\") String property1,");
writer.println(
"@org.springframework.boot.context.properties.bind.DefaultValue(\"default-value-2\") String property2");
writer.println(") {");
writer.println("}");
}
TestCompiler compiler = new TestCompiler(tempDir);
compiler.getTask(Arrays.asList(recordProperties)).call();
ClassLoader ucl = new URLClassLoader(new URL[] { tempDir.toURI().toURL() });
Object bean = this.binder.bind("test.record", Class.forName("RecordProperties", true, ucl)).get();
assertThat(ReflectionTestUtils.getField(bean, "property1")).isEqualTo("value-from-config-1");
assertThat(ReflectionTestUtils.getField(bean, "property2")).isEqualTo("default-value-2");
}
private void noConfigurationProperty(BindException ex) {
assertThat(ex.getProperty()).isNull();
}