Polish 'Add reflection hints for PropertyNamingStrategies'
See gh-33080
This commit is contained in:
parent
e9bca3e6de
commit
0d5c13cb28
|
@ -26,17 +26,22 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
|
||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
||||
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
|
@ -75,6 +80,7 @@ import org.springframework.util.ReflectionUtils;
|
|||
* @author Johannes Edmeier
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @author Ralf Ueberfuhr
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
|
@ -342,4 +348,36 @@ public class JacksonAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
static class JacksonAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
if (ClassUtils.isPresent("com.fasterxml.jackson.databind.PropertyNamingStrategy", classLoader)) {
|
||||
registerPropertyNamingStrategyHints(hints.reflection());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hints for the {@code configurePropertyNamingStrategyField} method to
|
||||
* use.
|
||||
* @param hints reflection hints
|
||||
*/
|
||||
private void registerPropertyNamingStrategyHints(ReflectionHints hints) {
|
||||
registerPropertyNamingStrategyHints(hints, PropertyNamingStrategies.class);
|
||||
// PropertyNamingStrategy is used pre Jackson 2.12
|
||||
registerPropertyNamingStrategyHints(hints, PropertyNamingStrategy.class);
|
||||
}
|
||||
|
||||
private void registerPropertyNamingStrategyHints(ReflectionHints hints, Class<?> type) {
|
||||
Stream.of(type.getDeclaredFields()).filter(this::isPropertyNamingStrategyField)
|
||||
.forEach(hints::registerField);
|
||||
}
|
||||
|
||||
private boolean isPropertyNamingStrategyField(Field candidate) {
|
||||
return ReflectionUtils.isPublicStaticFinal(candidate)
|
||||
&& candidate.getType().isAssignableFrom(PropertyNamingStrategy.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
package org.springframework.boot.autoconfigure.jackson;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for Jackson.
|
||||
* This is necessary for the configuration of Jackson's propertyNamingStrategy
|
||||
* to work in native build and execution.
|
||||
*
|
||||
* @author Ralf Ueberfuhr
|
||||
*/
|
||||
class JacksonRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
/*
|
||||
* We need this for
|
||||
*
|
||||
* JacksonAutoConfiguration
|
||||
* .Jackson2ObjectMapperBuilderCustomizerConfiguration
|
||||
* .StandardJackson2ObjectMapperBuilderCustomizer
|
||||
* .configurePropertyNamingStrategyField(...)
|
||||
*
|
||||
* to get the field using reflection!
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
if(ClassUtils.isPresent("com.fasterxml.jackson.databind.PropertyNamingStrategy", classLoader)) {
|
||||
registerHints(hints.reflection());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerHints(ReflectionHints reflection) {
|
||||
Field[] fieldsOfStrategies = PropertyNamingStrategies.class.getDeclaredFields();
|
||||
// Jackson 2.12 pre
|
||||
Field[] fieldsOfStrategy = PropertyNamingStrategy.class.getDeclaredFields();
|
||||
// Find all static fields that provide a PropertyNamingStrategy
|
||||
// (this way we automatically support new constants
|
||||
// that may be added by Jackson in the future)
|
||||
Stream.concat(Stream.of(fieldsOfStrategies), Stream.of(fieldsOfStrategy))
|
||||
.filter(f -> Modifier.isStatic(f.getModifiers()))
|
||||
.filter(f -> f.getType().isAssignableFrom(PropertyNamingStrategy.class))
|
||||
.forEach(reflection::registerField);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||
org.springframework.boot.autoconfigure.template.TemplateRuntimeHints,\
|
||||
org.springframework.boot.autoconfigure.jackson.JacksonRuntimeHints
|
||||
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.JacksonAutoConfigurationRuntimeHints,\
|
||||
org.springframework.boot.autoconfigure.template.TemplateRuntimeHints
|
||||
|
||||
org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\
|
||||
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingProcessor
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.time.Duration;
|
|||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator.Mode;
|
||||
|
@ -38,7 +39,9 @@ import com.fasterxml.jackson.databind.JsonSerializer;
|
|||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
|
||||
|
@ -50,10 +53,14 @@ import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
|||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.predicate.ReflectionHintsPredicates;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.JacksonAutoConfigurationRuntimeHints;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.boot.jackson.JsonMixin;
|
||||
import org.springframework.boot.jackson.JsonMixinModule;
|
||||
|
@ -81,6 +88,7 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Sebastien Deleuze
|
||||
* @author Johannes Edmeier
|
||||
* @author Grzegorz Poznachowski
|
||||
* @author Ralf Ueberfuhr
|
||||
*/
|
||||
class JacksonAutoConfigurationTests {
|
||||
|
||||
|
@ -456,6 +464,22 @@ class JacksonAutoConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRegisterPropertyNamingStrategyHints() {
|
||||
shouldRegisterPropertyNamingStrategyHints(PropertyNamingStrategies.class, "LOWER_CAMEL_CASE",
|
||||
"UPPER_CAMEL_CASE", "SNAKE_CASE", "UPPER_SNAKE_CASE", "LOWER_CASE", "KEBAB_CASE", "LOWER_DOT_CASE");
|
||||
shouldRegisterPropertyNamingStrategyHints(PropertyNamingStrategy.class, "LOWER_CAMEL_CASE", "UPPER_CAMEL_CASE",
|
||||
"SNAKE_CASE", "LOWER_CASE", "KEBAB_CASE", "LOWER_DOT_CASE");
|
||||
}
|
||||
|
||||
private void shouldRegisterPropertyNamingStrategyHints(Class<?> type, String... fieldNames) {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new JacksonAutoConfigurationRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();
|
||||
Stream.of(fieldNames).map((name) -> reflection.onField(type, name))
|
||||
.forEach((predicate) -> assertThat(predicate).accepts(hints));
|
||||
}
|
||||
|
||||
private void assertParameterNamesModuleCreatorBinding(Mode expectedMode, Class<?>... configClasses) {
|
||||
this.contextRunner.withUserConfiguration(configClasses).run((context) -> {
|
||||
DeserializationConfig deserializationConfig = context.getBean(ObjectMapper.class)
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
package org.springframework.boot.autoconfigure.jackson;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.predicate.ReflectionHintsPredicates;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class JacksonRuntimeHintsTests {
|
||||
|
||||
@Test
|
||||
void shouldRegisterHints() {
|
||||
shouldRegisterFieldHintsFor(PropertyNamingStrategies.class,
|
||||
"LOWER_CAMEL_CASE", "UPPER_CAMEL_CASE",
|
||||
"SNAKE_CASE", "UPPER_SNAKE_CASE",
|
||||
"LOWER_CASE", "KEBAB_CASE", "LOWER_DOT_CASE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRegisterJackson_2_12_pre_Hints() {
|
||||
shouldRegisterFieldHintsFor(PropertyNamingStrategy.class,
|
||||
"LOWER_CAMEL_CASE", "UPPER_CAMEL_CASE",
|
||||
"SNAKE_CASE",
|
||||
"LOWER_CASE", "KEBAB_CASE", "LOWER_DOT_CASE");
|
||||
}
|
||||
|
||||
private void shouldRegisterFieldHintsFor(Class<?> clazz, String... fieldNames) {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new JacksonRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();
|
||||
Stream.of(fieldNames)
|
||||
.map(name -> reflection.onField(clazz, name))
|
||||
.forEach(predicate -> assertThat(predicate).accepts(hints));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue