Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5a97d2e

Browse files
Merge branch '3.4.x'
Closes gh-45347
2 parents 6bb432d + a78187c commit 5a97d2e

File tree

3 files changed

+89
-37
lines changed

3 files changed

+89
-37
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ private void handleJavaBeanProperties(ReflectionHints hints) {
221221
if (setter != null) {
222222
hints.registerMethod(setter, ExecutableMode.INVOKE);
223223
}
224+
Field field = property.getField();
225+
if (field != null) {
226+
hints.registerField(field);
227+
}
224228
handleProperty(hints, name, property.getType());
225229
});
226230
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ Method getSetter() {
460460
return this.setter;
461461
}
462462

463+
Field getField() {
464+
return this.field;
465+
}
466+
463467
}
464468

465469
}

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

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
import org.junit.jupiter.api.Test;
2929

3030
import org.springframework.aot.hint.ExecutableHint;
31+
import org.springframework.aot.hint.FieldHint;
3132
import org.springframework.aot.hint.RuntimeHints;
3233
import org.springframework.aot.hint.TypeHint;
3334
import org.springframework.aot.hint.TypeReference;
@@ -108,39 +109,39 @@ void registerHintsWhenJavaBean() {
108109
void registerHintsWhenJavaBeanWithSeveralConstructors() throws NoSuchMethodException {
109110
RuntimeHints runtimeHints = registerHints(WithSeveralConstructors.class);
110111
assertThat(runtimeHints.reflection().typeHints()).singleElement()
111-
.satisfies(javaBeanBinding(WithSeveralConstructors.class,
112-
WithSeveralConstructors.class.getDeclaredConstructor()));
112+
.satisfies(javaBeanBinding(WithSeveralConstructors.class)
113+
.constructor(WithSeveralConstructors.class.getDeclaredConstructor()));
113114
}
114115

115116
@Test
116117
void registerHintsWhenJavaBeanWithMapOfPojo() {
117118
RuntimeHints runtimeHints = registerHints(WithMap.class);
118119
assertThat(runtimeHints.reflection().typeHints()).hasSize(2)
119-
.anySatisfy(javaBeanBinding(WithMap.class, "getAddresses"))
120+
.anySatisfy(javaBeanBinding(WithMap.class).methods("getAddresses"))
120121
.anySatisfy(javaBeanBinding(Address.class));
121122
}
122123

123124
@Test
124125
void registerHintsWhenJavaBeanWithListOfPojo() {
125126
RuntimeHints runtimeHints = registerHints(WithList.class);
126127
assertThat(runtimeHints.reflection().typeHints()).hasSize(2)
127-
.anySatisfy(javaBeanBinding(WithList.class, "getAllAddresses"))
128+
.anySatisfy(javaBeanBinding(WithList.class).methods("getAllAddresses"))
128129
.anySatisfy(javaBeanBinding(Address.class));
129130
}
130131

131132
@Test
132133
void registerHintsWhenJavaBeanWitArrayOfPojo() {
133134
RuntimeHints runtimeHints = registerHints(WithArray.class);
134135
assertThat(runtimeHints.reflection().typeHints()).hasSize(2)
135-
.anySatisfy(javaBeanBinding(WithArray.class, "getAllAddresses"))
136+
.anySatisfy(javaBeanBinding(WithArray.class).methods("getAllAddresses"))
136137
.anySatisfy(javaBeanBinding(Address.class));
137138
}
138139

139140
@Test
140141
void registerHintsWhenJavaBeanWithListOfJavaType() {
141142
RuntimeHints runtimeHints = registerHints(WithSimpleList.class);
142143
assertThat(runtimeHints.reflection().typeHints()).singleElement()
143-
.satisfies(javaBeanBinding(WithSimpleList.class, "getNames"));
144+
.satisfies(javaBeanBinding(WithSimpleList.class).methods("getNames"));
144145
}
145146

146147
@Test
@@ -177,18 +178,20 @@ void registerHintsWhenHasNestedTypeNotUsedIsIgnored() {
177178
void registerHintsWhenWhenHasNestedExternalType() {
178179
RuntimeHints runtimeHints = registerHints(WithExternalNested.class);
179180
assertThat(runtimeHints.reflection().typeHints()).hasSize(3)
180-
.anySatisfy(
181-
javaBeanBinding(WithExternalNested.class, "getName", "setName", "getSampleType", "setSampleType"))
182-
.anySatisfy(javaBeanBinding(SampleType.class, "getNested"))
181+
.anySatisfy(javaBeanBinding(WithExternalNested.class)
182+
.methods("getName", "setName", "getSampleType", "setSampleType")
183+
.fields("name", "sampleType"))
184+
.anySatisfy(javaBeanBinding(SampleType.class).methods("getNested").fields("nested"))
183185
.anySatisfy(javaBeanBinding(SampleType.Nested.class));
184186
}
185187

186188
@Test
187189
void registerHintsWhenHasRecursiveType() {
188190
RuntimeHints runtimeHints = registerHints(WithRecursive.class);
189191
assertThat(runtimeHints.reflection().typeHints()).hasSize(2)
190-
.anySatisfy(javaBeanBinding(WithRecursive.class, "getRecursive", "setRecursive"))
191-
.anySatisfy(javaBeanBinding(Recursive.class, "getRecursive", "setRecursive"));
192+
.anySatisfy(
193+
javaBeanBinding(WithRecursive.class).methods("getRecursive", "setRecursive").fields("recursive"))
194+
.anySatisfy(javaBeanBinding(Recursive.class).methods("getRecursive", "setRecursive").fields("recursive"));
192195
}
193196

194197
@Test
@@ -203,24 +206,28 @@ void registerHintsWhenValueObjectWithRecursiveType() {
203206
void registerHintsWhenHasWellKnownTypes() {
204207
RuntimeHints runtimeHints = registerHints(WithWellKnownTypes.class);
205208
assertThat(runtimeHints.reflection().typeHints()).singleElement()
206-
.satisfies(javaBeanBinding(WithWellKnownTypes.class, "getApplicationContext", "setApplicationContext",
207-
"getEnvironment", "setEnvironment"));
209+
.satisfies(javaBeanBinding(WithWellKnownTypes.class)
210+
.methods("getApplicationContext", "setApplicationContext", "getEnvironment", "setEnvironment")
211+
.fields("applicationContext", "environment"));
208212
}
209213

210214
@Test
211215
void registerHintsWhenHasCrossReference() {
212216
RuntimeHints runtimeHints = registerHints(WithCrossReference.class);
213217
assertThat(runtimeHints.reflection().typeHints()).hasSize(3)
214-
.anySatisfy(javaBeanBinding(WithCrossReference.class, "getCrossReferenceA", "setCrossReferenceA"))
215-
.anySatisfy(javaBeanBinding(CrossReferenceA.class, "getCrossReferenceB", "setCrossReferenceB"))
216-
.anySatisfy(javaBeanBinding(CrossReferenceB.class, "getCrossReferenceA", "setCrossReferenceA"));
218+
.anySatisfy(javaBeanBinding(WithCrossReference.class).methods("getCrossReferenceA", "setCrossReferenceA")
219+
.fields("crossReferenceA"))
220+
.anySatisfy(javaBeanBinding(CrossReferenceA.class).methods("getCrossReferenceB", "setCrossReferenceB")
221+
.fields("crossReferenceB"))
222+
.anySatisfy(javaBeanBinding(CrossReferenceB.class).methods("getCrossReferenceA", "setCrossReferenceA")
223+
.fields("crossReferenceA"));
217224
}
218225

219226
@Test
220227
void registerHintsWhenHasUnresolvedGeneric() {
221228
RuntimeHints runtimeHints = registerHints(WithGeneric.class);
222229
assertThat(runtimeHints.reflection().typeHints()).hasSize(2)
223-
.anySatisfy(javaBeanBinding(WithGeneric.class, "getGeneric"))
230+
.anySatisfy(javaBeanBinding(WithGeneric.class).methods("getGeneric").fields("generic"))
224231
.anySatisfy(javaBeanBinding(GenericObject.class));
225232
}
226233

@@ -246,8 +253,9 @@ void registerHintsWhenHasMultipleNestedClasses() {
246253
void registerHintsWhenHasPackagePrivateGettersAndSetters() {
247254
RuntimeHints runtimeHints = registerHints(PackagePrivateGettersAndSetters.class);
248255
assertThat(runtimeHints.reflection().typeHints()).singleElement()
249-
.satisfies(javaBeanBinding(PackagePrivateGettersAndSetters.class, "getAlpha", "setAlpha", "getBravo",
250-
"setBravo"));
256+
.satisfies(javaBeanBinding(PackagePrivateGettersAndSetters.class)
257+
.methods("getAlpha", "setAlpha", "getBravo", "setBravo")
258+
.fields("alpha", "bravo"));
251259
}
252260

253261
@Test
@@ -260,9 +268,9 @@ void registerHintsWhenHasInheritedNestedProperties() {
260268
.containsExactlyInAnyOrder("getInheritedNested", "setInheritedNested");
261269
});
262270
assertThat(runtimeHints.reflection().getTypeHint(ExtendingProperties.class))
263-
.satisfies(javaBeanBinding(ExtendingProperties.class, "getBravo", "setBravo"));
271+
.satisfies(javaBeanBinding(ExtendingProperties.class).methods("getBravo", "setBravo").fields("bravo"));
264272
assertThat(runtimeHints.reflection().getTypeHint(InheritedNested.class))
265-
.satisfies(javaBeanBinding(InheritedNested.class, "getAlpha", "setAlpha"));
273+
.satisfies(javaBeanBinding(InheritedNested.class).methods("getAlpha", "setAlpha").fields("alpha"));
266274
}
267275

268276
@Test
@@ -275,11 +283,11 @@ void registerHintsWhenHasComplexNestedProperties() {
275283
.containsExactlyInAnyOrder("getCount", "setCount");
276284
});
277285
assertThat(runtimeHints.reflection().getTypeHint(ListenerRetry.class))
278-
.satisfies(javaBeanBinding(ListenerRetry.class, "isStateless", "setStateless"));
286+
.satisfies(javaBeanBinding(ListenerRetry.class).methods("isStateless", "setStateless").fields("stateless"));
279287
assertThat(runtimeHints.reflection().getTypeHint(Simple.class))
280-
.satisfies(javaBeanBinding(Simple.class, "getRetry"));
288+
.satisfies(javaBeanBinding(Simple.class).methods("getRetry").fields("retry"));
281289
assertThat(runtimeHints.reflection().getTypeHint(ComplexNestedProperties.class))
282-
.satisfies(javaBeanBinding(ComplexNestedProperties.class, "getSimple"));
290+
.satisfies(javaBeanBinding(ComplexNestedProperties.class).methods("getSimple").fields("simple"));
283291
}
284292

285293
@Test
@@ -292,17 +300,8 @@ void registerHintsDoesNotThrowWhenParameterInformationForConstructorBindingIsNot
292300
assertThatNoException().isThrownBy(() -> registerHints(PoolProperties.class));
293301
}
294302

295-
private Consumer<TypeHint> javaBeanBinding(Class<?> type, String... expectedMethods) {
296-
return javaBeanBinding(type, type.getDeclaredConstructors()[0], expectedMethods);
297-
}
298-
299-
private Consumer<TypeHint> javaBeanBinding(Class<?> type, Constructor<?> constructor, String... expectedMethods) {
300-
return (entry) -> {
301-
assertThat(entry.getType()).isEqualTo(TypeReference.of(type));
302-
assertThat(entry.constructors()).singleElement().satisfies(match(constructor));
303-
assertThat(entry.getMemberCategories()).isEmpty();
304-
assertThat(entry.methods()).extracting(ExecutableHint::getName).containsExactlyInAnyOrder(expectedMethods);
305-
};
303+
private JavaBeanBinding javaBeanBinding(Class<?> type) {
304+
return new JavaBeanBinding(type);
306305
}
307306

308307
private Consumer<TypeHint> valueObjectBinding(Class<?> type) {
@@ -318,7 +317,7 @@ private Consumer<TypeHint> valueObjectBinding(Class<?> type, Constructor<?> cons
318317
};
319318
}
320319

321-
private Consumer<ExecutableHint> match(Constructor<?> constructor) {
320+
private staticConsumer<ExecutableHint> match(Constructor<?> constructor) {
322321
return (executableHint) -> {
323322
assertThat(executableHint.getName()).isEqualTo("<init>");
324323
assertThat(Arrays.stream(constructor.getParameterTypes()).map(TypeReference::of).toList())
@@ -804,4 +803,49 @@ public void setStateless(boolean stateless) {
804803

805804
}
806805

806+
private static final class JavaBeanBinding implements Consumer<TypeHint> {
807+
808+
private final Class<?> type;
809+
810+
private Constructor<?> constructor;
811+
812+
private List<String> expectedMethods = Collections.emptyList();
813+
814+
private List<String> expectedFields = Collections.emptyList();
815+
816+
private JavaBeanBinding(Class<?> type) {
817+
this.type = type;
818+
this.constructor = this.type.getDeclaredConstructors()[0];
819+
}
820+
821+
@Override
822+
public void accept(TypeHint entry) {
823+
assertThat(entry.getType()).isEqualTo(TypeReference.of(this.type));
824+
assertThat(entry.constructors()).singleElement().satisfies(match(this.constructor));
825+
assertThat(entry.getMemberCategories()).isEmpty();
826+
assertThat(entry.methods()).as("Methods requiring reflection")
827+
.extracting(ExecutableHint::getName)
828+
.containsExactlyInAnyOrderElementsOf(this.expectedMethods);
829+
assertThat(entry.fields()).as("Fields requiring reflection")
830+
.extracting(FieldHint::getName)
831+
.containsExactlyInAnyOrderElementsOf(this.expectedFields);
832+
}
833+
834+
private JavaBeanBinding constructor(Constructor<?> constructor) {
835+
this.constructor = constructor;
836+
return this;
837+
}
838+
839+
private JavaBeanBinding methods(String... methods) {
840+
this.expectedMethods = List.of(methods);
841+
return this;
842+
}
843+
844+
private JavaBeanBinding fields(String... fields) {
845+
this.expectedFields = List.of(fields);
846+
return this;
847+
}
848+
849+
}
850+
807851
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /