Skip to content

Commit 2270498

Browse files
committedSep 15, 2023
Fix RuntimeHintsPredicates matching rules
Prior to this commit, the `RuntimeHintsPredicates` would assume that registering introspection or invocation hints for "all declared methods" on a type would also include "all public methods". This is not true, as the Java reflection API itself behaves differently. `getDeclaredMethods()` does not return a superset of `getMethods()`, as the latter can return inherited methods, but not the former. Same reasoning applies to fields. This commit fixes the hints predicates to only match if the correct hint has been registered. Fixes gh-31224
1 parent 8f13031 commit 2270498

File tree

3 files changed

+35
-33
lines changed

3 files changed

+35
-33
lines changed
 

‎spring-core-test/src/test/java/org/springframework/aot/agent/InstrumentedMethodTests.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -408,15 +408,15 @@ void classGetMethodShouldMatchInvokePublicMethodsHint() {
408408
}
409409

410410
@Test
411-
void classGetMethodShouldMatchIntrospectDeclaredMethodsHint() {
411+
void classGetMethodShouldNotMatchIntrospectDeclaredMethodsHint() {
412412
hints.reflection().registerType(String.class, MemberCategory.INTROSPECT_DECLARED_METHODS);
413-
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod);
413+
assertThatInvocationDoesNotMatch(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod);
414414
}
415415

416416
@Test
417-
void classGetMethodShouldMatchInvokeDeclaredMethodsHint() {
417+
void classGetMethodShouldNotMatchInvokeDeclaredMethodsHint() {
418418
hints.reflection().registerType(String.class, MemberCategory.INVOKE_DECLARED_METHODS);
419-
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod);
419+
assertThatInvocationDoesNotMatch(InstrumentedMethod.CLASS_GETMETHOD, this.stringGetToStringMethod);
420420
}
421421

422422
@Test
@@ -544,9 +544,9 @@ void classGetFieldShouldMatchPublicFieldsHint() {
544544
}
545545

546546
@Test
547-
void classGetFieldShouldMatchDeclaredFieldsHint() {
547+
void classGetFieldShouldNotMatchDeclaredFieldsHint() {
548548
hints.reflection().registerType(PublicField.class, MemberCategory.DECLARED_FIELDS);
549-
assertThatInvocationMatches(InstrumentedMethod.CLASS_GETFIELD, this.getPublicField);
549+
assertThatInvocationDoesNotMatch(InstrumentedMethod.CLASS_GETFIELD, this.getPublicField);
550550
}
551551

552552
@Test

‎spring-core/src/main/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicates.java

+20-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -274,19 +274,6 @@ public ExecutableHintPredicate<T> invoke() {
274274
return this;
275275
}
276276

277-
@Override
278-
public boolean test(RuntimeHints runtimeHints) {
279-
return (new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
280-
.withAnyMemberCategory(getPublicMemberCategories())
281-
.and(hints -> Modifier.isPublic(this.executable.getModifiers())))
282-
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass())).withAnyMemberCategory(getDeclaredMemberCategories()))
283-
.or(exactMatch()).test(runtimeHints);
284-
}
285-
286-
abstract MemberCategory[] getPublicMemberCategories();
287-
288-
abstract MemberCategory[] getDeclaredMemberCategories();
289-
290277
abstract Predicate<RuntimeHints> exactMatch();
291278

292279
/**
@@ -309,6 +296,14 @@ public static class ConstructorHintPredicate extends ExecutableHintPredicate<Con
309296
}
310297

311298
@Override
299+
public boolean test(RuntimeHints runtimeHints) {
300+
return (new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
301+
.withAnyMemberCategory(getPublicMemberCategories())
302+
.and(hints -> Modifier.isPublic(this.executable.getModifiers())))
303+
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass())).withAnyMemberCategory(getDeclaredMemberCategories()))
304+
.or(exactMatch()).test(runtimeHints);
305+
}
306+
312307
MemberCategory[] getPublicMemberCategories() {
313308
if (this.executableMode == ExecutableMode.INTROSPECT) {
314309
return new MemberCategory[] { MemberCategory.INTROSPECT_PUBLIC_CONSTRUCTORS,
@@ -317,7 +312,6 @@ MemberCategory[] getPublicMemberCategories() {
317312
return new MemberCategory[] { MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS };
318313
}
319314

320-
@Override
321315
MemberCategory[] getDeclaredMemberCategories() {
322316
if (this.executableMode == ExecutableMode.INTROSPECT) {
323317
return new MemberCategory[] { MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS,
@@ -344,6 +338,16 @@ public static class MethodHintPredicate extends ExecutableHintPredicate<Method>
344338
}
345339

346340
@Override
341+
public boolean test(RuntimeHints runtimeHints) {
342+
return (new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
343+
.withAnyMemberCategory(getPublicMemberCategories())
344+
.and(hints -> Modifier.isPublic(this.executable.getModifiers())))
345+
.or(new TypeHintPredicate(TypeReference.of(this.executable.getDeclaringClass()))
346+
.withAnyMemberCategory(getDeclaredMemberCategories())
347+
.and(hints -> !Modifier.isPublic(this.executable.getModifiers())))
348+
.or(exactMatch()).test(runtimeHints);
349+
}
350+
347351
MemberCategory[] getPublicMemberCategories() {
348352
if (this.executableMode == ExecutableMode.INTROSPECT) {
349353
return new MemberCategory[] { MemberCategory.INTROSPECT_PUBLIC_METHODS,
@@ -352,7 +356,6 @@ MemberCategory[] getPublicMemberCategories() {
352356
return new MemberCategory[] { MemberCategory.INVOKE_PUBLIC_METHODS };
353357
}
354358

355-
@Override
356359
MemberCategory[] getDeclaredMemberCategories() {
357360

358361
if (this.executableMode == ExecutableMode.INTROSPECT) {
@@ -392,8 +395,7 @@ public boolean test(RuntimeHints runtimeHints) {
392395

393396
private boolean memberCategoryMatch(TypeHint typeHint) {
394397
if (Modifier.isPublic(this.field.getModifiers())) {
395-
return typeHint.getMemberCategories().contains(MemberCategory.PUBLIC_FIELDS) ||
396-
typeHint.getMemberCategories().contains(MemberCategory.DECLARED_FIELDS);
398+
return typeHint.getMemberCategories().contains(MemberCategory.PUBLIC_FIELDS);
397399
}
398400
else {
399401
return typeHint.getMemberCategories().contains(MemberCategory.DECLARED_FIELDS);

‎spring-core/src/test/java/org/springframework/aot/hint/predicate/ReflectionHintsPredicatesTests.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -329,15 +329,15 @@ void methodIntrospectionMatchesInvokePublicMethods() {
329329
}
330330

331331
@Test
332-
void methodIntrospectionMatchesIntrospectDeclaredMethods() {
332+
void methodIntrospectionDoesNotMatchIntrospectDeclaredMethods() {
333333
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INTROSPECT_DECLARED_METHODS);
334-
assertPredicateMatches(reflection.onMethod(SampleClass.class, "publicMethod").introspect());
334+
assertPredicateDoesNotMatch(reflection.onMethod(SampleClass.class, "publicMethod").introspect());
335335
}
336336

337337
@Test
338-
void methodIntrospectionMatchesInvokeDeclaredMethods() {
338+
void methodIntrospectionDoesNotMatchInvokeDeclaredMethods() {
339339
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_DECLARED_METHODS);
340-
assertPredicateMatches(reflection.onMethod(SampleClass.class, "publicMethod").introspect());
340+
assertPredicateDoesNotMatch(reflection.onMethod(SampleClass.class, "publicMethod").introspect());
341341
}
342342

343343
@Test
@@ -373,9 +373,9 @@ void methodInvocationDoesNotMatchIntrospectDeclaredMethods() {
373373
}
374374

375375
@Test
376-
void methodInvocationMatchesInvokeDeclaredMethods() {
376+
void methodInvocationDoesNotMatchInvokeDeclaredMethods() {
377377
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.INVOKE_DECLARED_METHODS);
378-
assertPredicateMatches(reflection.onMethod(SampleClass.class, "publicMethod").invoke());
378+
assertPredicateDoesNotMatch(reflection.onMethod(SampleClass.class, "publicMethod").invoke());
379379
}
380380

381381
@Test
@@ -482,9 +482,9 @@ void fieldReflectionMatchesPublicFieldsHint() {
482482
}
483483

484484
@Test
485-
void fieldReflectionMatchesDeclaredFieldsHint() {
485+
void fieldReflectionDoesNotMatchDeclaredFieldsHint() {
486486
runtimeHints.reflection().registerType(SampleClass.class, MemberCategory.DECLARED_FIELDS);
487-
assertPredicateMatches(reflection.onField(SampleClass.class, "publicField"));
487+
assertPredicateDoesNotMatch(reflection.onField(SampleClass.class, "publicField"));
488488
}
489489

490490
@Test

0 commit comments

Comments
 (0)
Please sign in to comment.