Skip to content

Commit d6d4b98

Browse files
committed
Add ifPresent utility methods on RuntimeHints
This commit adds a utility method to register a type for reflection if it is available on the classpath. It also adds a method to register a resource pattern if a given location is available. Closes gh-28617
1 parent c4e8ffe commit d6d4b98

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import org.springframework.aot.hint.TypeHint.Builder;
3232
import org.springframework.lang.Nullable;
33+
import org.springframework.util.ClassUtils;
3334

3435
/**
3536
* Gather the need for reflection at runtime.
@@ -95,6 +96,22 @@ public ReflectionHints registerType(Class<?> type, Consumer<TypeHint.Builder> ty
9596
return registerType(TypeReference.of(type), typeHint);
9697
}
9798

99+
/**
100+
* Register or customize reflection hints for the specified type if it
101+
* is available using the specified {@link ClassLoader}.
102+
* @param classLoader the classloader to use to check if the type is present
103+
* @param typeName the type to customize
104+
* @param typeHint a builder to further customize hints for that type
105+
* @return {@code this}, to facilitate method chaining
106+
*/
107+
public ReflectionHints registerTypeIfPresent(@Nullable ClassLoader classLoader,
108+
String typeName, Consumer<TypeHint.Builder> typeHint) {
109+
if (ClassUtils.isPresent(typeName, classLoader)) {
110+
registerType(TypeReference.of(typeName), typeHint);
111+
}
112+
return this;
113+
}
114+
98115
/**
99116
* Register or customize reflection hints for the types defined by the
100117
* specified list of {@link TypeReference type references}. The specified

spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,24 @@ public Stream<ResourceBundleHint> resourceBundles() {
6565
return this.resourceBundleHints.stream();
6666
}
6767

68+
/**
69+
* Register a pattern if the given {@code location} is available on the
70+
* classpath. This delegates to {@link ClassLoader#getResource(String)}
71+
* which validates directories as well. The location is not included in
72+
* the hint.
73+
* @param classLoader the classloader to use
74+
* @param location a '/'-separated path name that should exist
75+
* @param resourceHint a builder to customize the resource pattern
76+
* @return {@code this}, to facilitate method chaining
77+
*/
78+
public ResourceHints registerPatternIfPresent(@Nullable ClassLoader classLoader, String location, Consumer<ResourcePatternHints.Builder> resourceHint) {
79+
ClassLoader classLoaderToUse = (classLoader != null) ? classLoader : getClass().getClassLoader();
80+
if (classLoaderToUse.getResource(location) != null) {
81+
registerPattern(resourceHint);
82+
}
83+
return this;
84+
}
85+
6886
/**
6987
* Register that the resources matching the specified pattern should be
7088
* made available at runtime.

spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.springframework.util.ReflectionUtils;
2828

2929
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.mockito.Mockito.mock;
31+
import static org.mockito.Mockito.verifyNoInteractions;
3032

3133
/**
3234
* Tests for {@link ReflectionHints}.
@@ -45,6 +47,23 @@ void registerType() {
4547
typeWithMemberCategories(String.class, MemberCategory.DECLARED_FIELDS));
4648
}
4749

50+
@Test
51+
void registerTypeIfPresentRegisterExistingClass() {
52+
this.reflectionHints.registerTypeIfPresent(null, String.class.getName(),
53+
hint -> hint.withMembers(MemberCategory.DECLARED_FIELDS));
54+
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(
55+
typeWithMemberCategories(String.class, MemberCategory.DECLARED_FIELDS));
56+
}
57+
58+
@Test
59+
@SuppressWarnings("unchecked")
60+
void registerTypeIfPresentIgnoreMissingClass() {
61+
Consumer<TypeHint.Builder> hintBuilder = mock(Consumer.class);
62+
this.reflectionHints.registerTypeIfPresent(null, "com.example.DoesNotExist", hintBuilder);
63+
assertThat(this.reflectionHints.typeHints()).isEmpty();
64+
verifyNoInteractions(hintBuilder);
65+
}
66+
4867
@Test
4968
void getTypeUsingType() {
5069
this.reflectionHints.registerType(TypeReference.of(String.class),

spring-core/src/test/java/org/springframework/aot/hint/ResourceHintsTests.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.springframework.aot.hint.ResourceHintsTests.Nested.Inner;
2727

2828
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.mockito.Mockito.mock;
30+
import static org.mockito.Mockito.verifyNoInteractions;
2931

3032
/**
3133
* Tests for {@link ResourceHints}.
@@ -91,6 +93,23 @@ void registerPatternWithIncludesAndExcludes() {
9193
List.of("com/example/to-ignore.properties")));
9294
}
9395

96+
@Test
97+
void registerIfPresentRegisterExistingLocation() {
98+
this.resourceHints.registerPatternIfPresent(null, "META-INF/",
99+
resourceHint -> resourceHint.includes("com/example/*.properties"));
100+
assertThat(this.resourceHints.resourcePatterns()).singleElement().satisfies(
101+
patternOf("com/example/*.properties"));
102+
}
103+
104+
@Test
105+
@SuppressWarnings("unchecked")
106+
void registerIfPresentIgnoreMissingLocation() {
107+
Consumer<ResourcePatternHints.Builder> hintBuilder = mock(Consumer.class);
108+
this.resourceHints.registerPatternIfPresent(null, "location/does-not-exist/", hintBuilder);
109+
assertThat(this.resourceHints.resourcePatterns()).isEmpty();
110+
verifyNoInteractions(hintBuilder);
111+
}
112+
94113
@Test
95114
void registerResourceBundle() {
96115
this.resourceHints.registerResourceBundle("com.example.message");

0 commit comments

Comments
 (0)