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
This commit is contained in:
parent
da1005cd66
commit
bc0bf1fac3
|
|
@ -20,6 +20,7 @@ import java.lang.reflect.Constructor;
|
|||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -80,6 +81,15 @@ public final class ExecutableHint extends MemberHint {
|
|||
return this.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Consumer} that applies the given {@link ExecutableMode}
|
||||
* to the accepted {@link Builder}.
|
||||
* @param mode the mode to apply
|
||||
* @return a consumer to apply the mode
|
||||
*/
|
||||
public static Consumer<Builder> builtWith(ExecutableMode mode) {
|
||||
return builder -> builder.withMode(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link ExecutableHint}.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.aot.hint;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -66,6 +67,16 @@ public final class FieldHint extends MemberHint {
|
|||
return this.allowUnsafeAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Consumer} that applies the given {@link FieldMode}
|
||||
* to the accepted {@link Builder}.
|
||||
* @param mode the mode to apply
|
||||
* @return a consumer to apply the mode
|
||||
*/
|
||||
public static Consumer<Builder> builtWith(FieldMode mode) {
|
||||
return builder -> builder.withMode(mode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder for {@link FieldHint}.
|
||||
|
|
|
|||
|
|
@ -86,6 +86,28 @@ public class ReflectionHints {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register or customize reflection hints for the specified type
|
||||
* using the specified {@link MemberCategory MemberCategories}.
|
||||
* @param type the type to customize
|
||||
* @param memberCategories the member categories to apply
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerType(Class<?> type, MemberCategory... memberCategories) {
|
||||
return registerType(TypeReference.of(type), memberCategories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register or customize reflection hints for the specified type
|
||||
* using the specified {@link MemberCategory MemberCategories}.
|
||||
* @param type the type to customize
|
||||
* @param memberCategories the member categories to apply
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerType(TypeReference type , MemberCategory... memberCategories) {
|
||||
return registerType(type, TypeHint.builtWith(memberCategories));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register or customize reflection hints for the specified type.
|
||||
* @param type the type to customize
|
||||
|
|
@ -132,7 +154,17 @@ public class ReflectionHints {
|
|||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerField(Field field) {
|
||||
return registerField(field, fieldHint -> fieldHint.withMode(FieldMode.WRITE));
|
||||
return registerField(field, FieldMode.WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the need for reflection on the specified {@link Field}
|
||||
* using the specified {@link FieldMode}.
|
||||
* @param field the field that requires reflection
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerField(Field field, FieldMode mode) {
|
||||
return registerField(field, FieldHint.builtWith(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -164,7 +196,7 @@ public class ReflectionHints {
|
|||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerConstructor(Constructor<?> constructor, ExecutableMode mode) {
|
||||
return registerConstructor(constructor, constructorHint -> constructorHint.withMode(mode));
|
||||
return registerConstructor(constructor, ExecutableHint.builtWith(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -197,7 +229,7 @@ public class ReflectionHints {
|
|||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerMethod(Method method, ExecutableMode mode) {
|
||||
return registerMethod(method, methodHint -> methodHint.withMode(mode));
|
||||
return registerMethod(method, ExecutableHint.builtWith(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -126,6 +126,17 @@ public final class TypeHint implements ConditionalHint {
|
|||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Consumer} that applies the given {@link MemberCategory
|
||||
* MemberCategories} to the accepted {@link Builder}.
|
||||
* @param memberCategories the memberCategories to apply
|
||||
* @return a consumer to apply the member categories
|
||||
*/
|
||||
public static Consumer<Builder> builtWith(MemberCategory... memberCategories) {
|
||||
return builder -> builder.withMembers(memberCategories);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder for {@link TypeHint}.
|
||||
*/
|
||||
|
|
@ -180,7 +191,18 @@ public final class TypeHint implements ConditionalHint {
|
|||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public Builder withField(String name) {
|
||||
return withField(name, fieldHint -> {});
|
||||
return withField(name, FieldMode.WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the need for reflection on the field with the specified name
|
||||
* using the specified {@link FieldMode}.
|
||||
* @param name the name of the field
|
||||
* @param mode the requested mode
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public Builder withField(String name, FieldMode mode) {
|
||||
return withField(name, FieldHint.builtWith(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -213,7 +235,7 @@ public final class TypeHint implements ConditionalHint {
|
|||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public Builder withConstructor(List<TypeReference> parameterTypes, ExecutableMode mode) {
|
||||
return withConstructor(parameterTypes, constructorHint -> constructorHint.withMode(mode));
|
||||
return withConstructor(parameterTypes, ExecutableHint.builtWith(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -252,7 +274,7 @@ public final class TypeHint implements ConditionalHint {
|
|||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public Builder withMethod(String name, List<TypeReference> parameterTypes, ExecutableMode mode) {
|
||||
return withMethod(name, parameterTypes, methodHint -> methodHint.withMode(mode));
|
||||
return withMethod(name, parameterTypes, ExecutableHint.builtWith(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aot.hint;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ExecutableHint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 6.0
|
||||
*/
|
||||
class ExecutableHintTests {
|
||||
|
||||
@Test
|
||||
void builtWithAppliesMode() {
|
||||
ExecutableHint.Builder builder = new ExecutableHint.Builder("test", Collections.emptyList());
|
||||
assertThat(builder.build().getMode()).isEqualTo(ExecutableMode.INVOKE);
|
||||
ExecutableHint.builtWith(ExecutableMode.INTROSPECT).accept(builder);
|
||||
assertThat(builder.build().getMode()).isEqualTo(ExecutableMode.INTROSPECT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aot.hint;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link FieldHint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class FieldHintTests {
|
||||
|
||||
@Test
|
||||
void builtWithAppliesMode() {
|
||||
FieldHint.Builder builder = new FieldHint.Builder("test");
|
||||
assertThat(builder.build().getMode()).isEqualTo(FieldMode.WRITE);
|
||||
FieldHint.builtWith(FieldMode.READ).accept(builder);
|
||||
assertThat(builder.build().getMode()).isEqualTo(FieldMode.READ);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -106,6 +106,14 @@ class ReflectionHintsTests {
|
|||
typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerClassWitCustomizer() {
|
||||
this.reflectionHints.registerType(Integer.class,
|
||||
typeHint -> typeHint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
|
||||
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(
|
||||
typeWithMemberCategories(Integer.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerTypesApplyTheSameHints() {
|
||||
this.reflectionHints.registerTypes(TypeReference.listOf(Integer.class, String.class, Double.class),
|
||||
|
|
@ -157,6 +165,17 @@ class ReflectionHintsTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerFieldWithMode() {
|
||||
Field field = ReflectionUtils.findField(TestType.class, "field");
|
||||
assertThat(field).isNotNull();
|
||||
this.reflectionHints.registerField(field, FieldMode.READ);
|
||||
assertTestTypeFieldHint(fieldHint -> {
|
||||
assertThat(fieldHint.getName()).isEqualTo("field");
|
||||
assertThat(fieldHint.getMode()).isEqualTo(FieldMode.READ);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-29055
|
||||
void registerFieldWithCustomizersCannotDowngradeWrite() {
|
||||
Field field = ReflectionUtils.findField(TestType.class, "field");
|
||||
|
|
|
|||
|
|
@ -102,6 +102,17 @@ class TypeHintTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void createFieldWithFieldMode() {
|
||||
Builder builder = TypeHint.of(TypeReference.of(String.class));
|
||||
builder.withField("value", FieldMode.READ);
|
||||
assertFieldHint(builder, fieldHint -> {
|
||||
assertThat(fieldHint.getName()).isEqualTo("value");
|
||||
assertThat(fieldHint.getMode()).isEqualTo(FieldMode.READ);
|
||||
assertThat(fieldHint.isAllowUnsafeAccess()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
void assertFieldHint(Builder builder, Consumer<FieldHint> fieldHint) {
|
||||
TypeHint hint = builder.build();
|
||||
assertThat(hint.fields()).singleElement().satisfies(fieldHint);
|
||||
|
|
@ -277,4 +288,13 @@ class TypeHintTests {
|
|||
assertThat(hint).hasToString("TypeHint[type=java.lang.String]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void builtWithAppliesMemberCategories() {
|
||||
TypeHint.Builder builder = new TypeHint.Builder(TypeReference.of(String.class));
|
||||
assertThat(builder.build().getMemberCategories()).isEmpty();
|
||||
TypeHint.builtWith(MemberCategory.DECLARED_CLASSES, MemberCategory.DECLARED_FIELDS).accept(builder);
|
||||
assertThat(builder.build().getMemberCategories()).containsExactlyInAnyOrder(MemberCategory.DECLARED_CLASSES,
|
||||
MemberCategory.DECLARED_FIELDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue