Skip to content

Commit 976ed90

Browse files
An1s9nwilkinsona
authored andcommitted
Allow @DefaultValue to be used on record components
See gh-29010
1 parent 1793cee commit 976ed90

File tree

4 files changed

+62
-2
lines changed

4 files changed

+62
-2
lines changed

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
* @author Andy Wilkinson
7575
* @author Kris De Volder
7676
* @author Jonas Keßler
77+
* @author Pavel Anisimov
7778
*/
7879
class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGenerationTests {
7980

@@ -445,4 +446,24 @@ void multiConstructorRecordProperties(@TempDir File temp) throws IOException {
445446
assertThat(metadata).doesNotHave(Metadata.withProperty("multi.some-integer"));
446447
}
447448

449+
@Test
450+
@EnabledForJreRange(min = JRE.JAVA_16)
451+
void recordPropertiesWithDefaultValues(@TempDir File temp) throws IOException {
452+
File exampleRecord = new File(temp, "ExampleRecord.java");
453+
try (PrintWriter writer = new PrintWriter(new FileWriter(exampleRecord))) {
454+
writer.println(
455+
"@org.springframework.boot.configurationsample.ConfigurationProperties(\"record.defaults\")");
456+
writer.println("public record ExampleRecord(");
457+
writer.println("@org.springframework.boot.configurationsample.DefaultValue(\"An1s9n\") String someString,");
458+
writer.println("@org.springframework.boot.configurationsample.DefaultValue(\"594\") Integer someInteger");
459+
writer.println(") {");
460+
writer.println("}");
461+
}
462+
ConfigurationMetadata metadata = compile(exampleRecord);
463+
assertThat(metadata)
464+
.has(Metadata.withProperty("record.defaults.some-string", String.class).withDefaultValue("An1s9n"));
465+
assertThat(metadata)
466+
.has(Metadata.withProperty("record.defaults.some-integer", Integer.class).withDefaultValue(594));
467+
}
468+
448469
}

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DefaultValue.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@
2727
* dependency on the real annotation).
2828
*
2929
* @author Stephane Nicoll
30+
* @author Pavel Anisimov
3031
*/
31-
@Target({ ElementType.PARAMETER })
32+
@Target({ ElementType.PARAMETER, ElementType.RECORD_COMPONENT })
3233
@Retention(RetentionPolicy.RUNTIME)
3334
@Documented
3435
public @interface DefaultValue {

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DefaultValue.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@
3737
* must be constant.
3838
*
3939
* @author Madhura Bhave
40+
* @author Pavel Anisimov
4041
* @since 2.2.0
4142
*/
4243
@Retention(RetentionPolicy.RUNTIME)
43-
@Target({ ElementType.PARAMETER })
44+
@Target({ ElementType.PARAMETER, ElementType.RECORD_COMPONENT })
4445
@Documented
4546
public @interface DefaultValue {
4647

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,35 @@
1616

1717
package org.springframework.boot.context.properties.bind;
1818

19+
import java.io.File;
20+
import java.io.FileWriter;
21+
import java.io.IOException;
22+
import java.io.PrintWriter;
1923
import java.lang.reflect.Constructor;
24+
import java.net.URL;
25+
import java.net.URLClassLoader;
2026
import java.nio.file.Path;
2127
import java.nio.file.Paths;
2228
import java.time.LocalDate;
2329
import java.util.ArrayList;
30+
import java.util.Arrays;
2431
import java.util.List;
2532
import java.util.Map;
2633
import java.util.Objects;
2734

2835
import org.junit.jupiter.api.Test;
36+
import org.junit.jupiter.api.condition.EnabledForJreRange;
37+
import org.junit.jupiter.api.condition.JRE;
38+
import org.junit.jupiter.api.io.TempDir;
2939

3040
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
3141
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
3242
import org.springframework.boot.context.properties.source.MockConfigurationPropertySource;
43+
import org.springframework.boot.testsupport.compiler.TestCompiler;
3344
import org.springframework.core.ResolvableType;
3445
import org.springframework.core.convert.ConversionService;
3546
import org.springframework.format.annotation.DateTimeFormat;
47+
import org.springframework.test.util.ReflectionTestUtils;
3648
import org.springframework.util.Assert;
3749

3850
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,6 +55,7 @@
4355
*
4456
* @author Madhura Bhave
4557
* @author Phillip Webb
58+
* @author Pavel Anisimov
4659
*/
4760
class ValueObjectBinderTests {
4861

@@ -357,6 +370,30 @@ void bindToAnnotationNamedParameter() {
357370
assertThat(bound.getImportName()).isEqualTo("test");
358371
}
359372

373+
@Test
374+
@EnabledForJreRange(min = JRE.JAVA_16)
375+
void bindToRecordWithDefaultValue(@TempDir File tempDir) throws IOException, ClassNotFoundException {
376+
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
377+
source.put("test.record.property1", "value-from-config-1");
378+
this.sources.add(source);
379+
File recordProperties = new File(tempDir, "RecordProperties.java");
380+
try (PrintWriter writer = new PrintWriter(new FileWriter(recordProperties))) {
381+
writer.println("public record RecordProperties(");
382+
writer.println(
383+
"@org.springframework.boot.context.properties.bind.DefaultValue(\"default-value-1\") String property1,");
384+
writer.println(
385+
"@org.springframework.boot.context.properties.bind.DefaultValue(\"default-value-2\") String property2");
386+
writer.println(") {");
387+
writer.println("}");
388+
}
389+
TestCompiler compiler = new TestCompiler(tempDir);
390+
compiler.getTask(Arrays.asList(recordProperties)).call();
391+
ClassLoader ucl = new URLClassLoader(new URL[] { tempDir.toURI().toURL() });
392+
Object bean = this.binder.bind("test.record", Class.forName("RecordProperties", true, ucl)).get();
393+
assertThat(ReflectionTestUtils.getField(bean, "property1")).isEqualTo("value-from-config-1");
394+
assertThat(ReflectionTestUtils.getField(bean, "property2")).isEqualTo("default-value-2");
395+
}
396+
360397
private void noConfigurationProperty(BindException ex) {
361398
assertThat(ex.getProperty()).isNull();
362399
}

0 commit comments

Comments
 (0)