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.
2828import org .junit .jupiter .api .Test ;
2929
3030import org .springframework .aot .hint .ExecutableHint ;
31+ import org .springframework .aot .hint .FieldHint ;
3132import org .springframework .aot .hint .RuntimeHints ;
3233import org .springframework .aot .hint .TypeHint ;
3334import 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 static Consumer <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