Skip to content

Commit bc0bf1f

Browse files
committed
Add additional shortcuts for hint registration
Add `MemberCategory` and `FieldMode` shortcuts for type registration. Helper `builtWith` methods have also been extracted to the Hint types to allow general reuse (for example with `registerTypes`). See gh-29011
1 parent da1005c commit bc0bf1f

File tree

8 files changed

+199
-6
lines changed

8 files changed

+199
-6
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.lang.reflect.Executable;
2121
import java.lang.reflect.Method;
2222
import java.util.List;
23+
import java.util.function.Consumer;
2324

2425
import org.springframework.lang.Nullable;
2526
import org.springframework.util.Assert;
@@ -80,6 +81,15 @@ public ExecutableMode getMode() {
8081
return this.mode;
8182
}
8283

84+
/**
85+
* Return a {@link Consumer} that applies the given {@link ExecutableMode}
86+
* to the accepted {@link Builder}.
87+
* @param mode the mode to apply
88+
* @return a consumer to apply the mode
89+
*/
90+
public static Consumer<Builder> builtWith(ExecutableMode mode) {
91+
return builder -> builder.withMode(mode);
92+
}
8393

8494
/**
8595
* Builder for {@link ExecutableHint}.

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.aot.hint;
1818

1919
import java.lang.reflect.Field;
20+
import java.util.function.Consumer;
2021

2122
import org.springframework.lang.Nullable;
2223
import org.springframework.util.Assert;
@@ -66,6 +67,16 @@ public boolean isAllowUnsafeAccess() {
6667
return this.allowUnsafeAccess;
6768
}
6869

70+
/**
71+
* Return a {@link Consumer} that applies the given {@link FieldMode}
72+
* to the accepted {@link Builder}.
73+
* @param mode the mode to apply
74+
* @return a consumer to apply the mode
75+
*/
76+
public static Consumer<Builder> builtWith(FieldMode mode) {
77+
return builder -> builder.withMode(mode);
78+
}
79+
6980

7081
/**
7182
* Builder for {@link FieldHint}.

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

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,28 @@ public ReflectionHints registerType(TypeReference type, Consumer<TypeHint.Builde
8686
return this;
8787
}
8888

89+
/**
90+
* Register or customize reflection hints for the specified type
91+
* using the specified {@link MemberCategory MemberCategories}.
92+
* @param type the type to customize
93+
* @param memberCategories the member categories to apply
94+
* @return {@code this}, to facilitate method chaining
95+
*/
96+
public ReflectionHints registerType(Class<?> type, MemberCategory... memberCategories) {
97+
return registerType(TypeReference.of(type), memberCategories);
98+
}
99+
100+
/**
101+
* Register or customize reflection hints for the specified type
102+
* using the specified {@link MemberCategory MemberCategories}.
103+
* @param type the type to customize
104+
* @param memberCategories the member categories to apply
105+
* @return {@code this}, to facilitate method chaining
106+
*/
107+
public ReflectionHints registerType(TypeReference type , MemberCategory... memberCategories) {
108+
return registerType(type, TypeHint.builtWith(memberCategories));
109+
}
110+
89111
/**
90112
* Register or customize reflection hints for the specified type.
91113
* @param type the type to customize
@@ -132,7 +154,17 @@ public ReflectionHints registerTypes(Iterable<TypeReference> types, Consumer<Typ
132154
* @return {@code this}, to facilitate method chaining
133155
*/
134156
public ReflectionHints registerField(Field field) {
135-
return registerField(field, fieldHint -> fieldHint.withMode(FieldMode.WRITE));
157+
return registerField(field, FieldMode.WRITE);
158+
}
159+
160+
/**
161+
* Register the need for reflection on the specified {@link Field}
162+
* using the specified {@link FieldMode}.
163+
* @param field the field that requires reflection
164+
* @return {@code this}, to facilitate method chaining
165+
*/
166+
public ReflectionHints registerField(Field field, FieldMode mode) {
167+
return registerField(field, FieldHint.builtWith(mode));
136168
}
137169

138170
/**
@@ -164,7 +196,7 @@ public ReflectionHints registerConstructor(Constructor<?> constructor) {
164196
* @return {@code this}, to facilitate method chaining
165197
*/
166198
public ReflectionHints registerConstructor(Constructor<?> constructor, ExecutableMode mode) {
167-
return registerConstructor(constructor, constructorHint -> constructorHint.withMode(mode));
199+
return registerConstructor(constructor, ExecutableHint.builtWith(mode));
168200
}
169201

170202
/**
@@ -197,7 +229,7 @@ public ReflectionHints registerMethod(Method method) {
197229
* @return {@code this}, to facilitate method chaining
198230
*/
199231
public ReflectionHints registerMethod(Method method, ExecutableMode mode) {
200-
return registerMethod(method, methodHint -> methodHint.withMode(mode));
232+
return registerMethod(method, ExecutableHint.builtWith(mode));
201233
}
202234

203235
/**

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ public String toString() {
126126
.toString();
127127
}
128128

129+
/**
130+
* Return a {@link Consumer} that applies the given {@link MemberCategory
131+
* MemberCategories} to the accepted {@link Builder}.
132+
* @param memberCategories the memberCategories to apply
133+
* @return a consumer to apply the member categories
134+
*/
135+
public static Consumer<Builder> builtWith(MemberCategory... memberCategories) {
136+
return builder -> builder.withMembers(memberCategories);
137+
}
138+
139+
129140
/**
130141
* Builder for {@link TypeHint}.
131142
*/
@@ -180,7 +191,18 @@ public Builder onReachableType(Class<?> reachableType) {
180191
* @return {@code this}, to facilitate method chaining
181192
*/
182193
public Builder withField(String name) {
183-
return withField(name, fieldHint -> {});
194+
return withField(name, FieldMode.WRITE);
195+
}
196+
197+
/**
198+
* Register the need for reflection on the field with the specified name
199+
* using the specified {@link FieldMode}.
200+
* @param name the name of the field
201+
* @param mode the requested mode
202+
* @return {@code this}, to facilitate method chaining
203+
*/
204+
public Builder withField(String name, FieldMode mode) {
205+
return withField(name, FieldHint.builtWith(mode));
184206
}
185207

186208
/**
@@ -213,7 +235,7 @@ public Builder withConstructor(List<TypeReference> parameterTypes) {
213235
* @return {@code this}, to facilitate method chaining
214236
*/
215237
public Builder withConstructor(List<TypeReference> parameterTypes, ExecutableMode mode) {
216-
return withConstructor(parameterTypes, constructorHint -> constructorHint.withMode(mode));
238+
return withConstructor(parameterTypes, ExecutableHint.builtWith(mode));
217239
}
218240

219241
/**
@@ -252,7 +274,7 @@ public Builder withMethod(String name, List<TypeReference> parameterTypes) {
252274
* @return {@code this}, to facilitate method chaining
253275
*/
254276
public Builder withMethod(String name, List<TypeReference> parameterTypes, ExecutableMode mode) {
255-
return withMethod(name, parameterTypes, methodHint -> methodHint.withMode(mode));
277+
return withMethod(name, parameterTypes, ExecutableHint.builtWith(mode));
256278
}
257279

258280
/**
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.aot.hint;
18+
19+
import java.util.Collections;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import static org.assertj.core.api.Assertions.assertThat;
24+
25+
/**
26+
* Tests for {@link ExecutableHint}.
27+
*
28+
* @author Phillip Webb
29+
* @since 6.0
30+
*/
31+
class ExecutableHintTests {
32+
33+
@Test
34+
void builtWithAppliesMode() {
35+
ExecutableHint.Builder builder = new ExecutableHint.Builder("test", Collections.emptyList());
36+
assertThat(builder.build().getMode()).isEqualTo(ExecutableMode.INVOKE);
37+
ExecutableHint.builtWith(ExecutableMode.INTROSPECT).accept(builder);
38+
assertThat(builder.build().getMode()).isEqualTo(ExecutableMode.INTROSPECT);
39+
}
40+
41+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.aot.hint;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
/**
24+
* Tests for {@link FieldHint}.
25+
*
26+
* @author Phillip Webb
27+
*/
28+
class FieldHintTests {
29+
30+
@Test
31+
void builtWithAppliesMode() {
32+
FieldHint.Builder builder = new FieldHint.Builder("test");
33+
assertThat(builder.build().getMode()).isEqualTo(FieldMode.WRITE);
34+
FieldHint.builtWith(FieldMode.READ).accept(builder);
35+
assertThat(builder.build().getMode()).isEqualTo(FieldMode.READ);
36+
}
37+
38+
}

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
@@ -106,6 +106,14 @@ void registerClass() {
106106
typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
107107
}
108108

109+
@Test
110+
void registerClassWitCustomizer() {
111+
this.reflectionHints.registerType(Integer.class,
112+
typeHint -> typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
113+
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(
114+
typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
115+
}
116+
109117
@Test
110118
void registerTypesApplyTheSameHints() {
111119
this.reflectionHints.registerTypes(TypeReference.listOf(Integer.class, String.class, Double.class),
@@ -157,6 +165,17 @@ void registerFieldWithCustomizerAppliesCustomization() {
157165
});
158166
}
159167

168+
@Test
169+
void registerFieldWithMode() {
170+
Field field = ReflectionUtils.findField(TestType.class, "field");
171+
assertThat(field).isNotNull();
172+
this.reflectionHints.registerField(field, FieldMode.READ);
173+
assertTestTypeFieldHint(fieldHint -> {
174+
assertThat(fieldHint.getName()).isEqualTo("field");
175+
assertThat(fieldHint.getMode()).isEqualTo(FieldMode.READ);
176+
});
177+
}
178+
160179
@Test // gh-29055
161180
void registerFieldWithCustomizersCannotDowngradeWrite() {
162181
Field field = ReflectionUtils.findField(TestType.class, "field");

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ void createWithFieldReuseBuilder() {
102102
});
103103
}
104104

105+
@Test
106+
void createFieldWithFieldMode() {
107+
Builder builder = TypeHint.of(TypeReference.of(String.class));
108+
builder.withField("value", FieldMode.READ);
109+
assertFieldHint(builder, fieldHint -> {
110+
assertThat(fieldHint.getName()).isEqualTo("value");
111+
assertThat(fieldHint.getMode()).isEqualTo(FieldMode.READ);
112+
assertThat(fieldHint.isAllowUnsafeAccess()).isFalse();
113+
});
114+
}
115+
105116
void assertFieldHint(Builder builder, Consumer<FieldHint> fieldHint) {
106117
TypeHint hint = builder.build();
107118
assertThat(hint.fields()).singleElement().satisfies(fieldHint);
@@ -277,4 +288,13 @@ void typeHintHasAppropriateToString() {
277288
assertThat(hint).hasToString("TypeHint[type=java.lang.String]");
278289
}
279290

291+
@Test
292+
void builtWithAppliesMemberCategories() {
293+
TypeHint.Builder builder = new TypeHint.Builder(TypeReference.of(String.class));
294+
assertThat(builder.build().getMemberCategories()).isEmpty();
295+
TypeHint.builtWith(MemberCategory.DECLARED_CLASSES, MemberCategory.DECLARED_FIELDS).accept(builder);
296+
assertThat(builder.build().getMemberCategories()).containsExactlyInAnyOrder(MemberCategory.DECLARED_CLASSES,
297+
MemberCategory.DECLARED_FIELDS);
298+
}
299+
280300
}

0 commit comments

Comments
 (0)