NOTE: This is not a duplicate. That other question is not about auto-marshalling of Spring request params. It has a solution where you manually marshall objects with jackson.
I want to allow devs to create request objects with enums that can match with case-insensitivity. Other fields/properties may need case-sensitive matching, but the enums should be case-insensitive.
The only way I've found so far (initBinding
) requires you to specify the exact enum class at compile time. I am looking for a more generic way to marshall the strings in the JSON request into enums.
The only current way I've found:
@RestController
public class TestController
{
//...elided...
@InitBinder
public void initBinder(final WebDataBinder webdataBinder)
{
webdataBinder.registerCustomEditor( MyEnum.class, new CaseInsensitiveEnumConverter() );
}
}
But this requires compiling with the enums pre-known.
By default, Jackson will use the Enum name to deserialize from JSON. If we want Jackson to case-insensitively deserialize from JSON by the Enum name, we need to customize the ObjectMapper to enable the ACCEPT_CASE_INSENSITIVE_ENUMS feature.
Jackson is a well-known library for JSON utilities. It has a wide area of features. One of them is case insensitive deserialization for field names. It's available since 2.5.
Enum 's valueOf(String) Method The valueOf(String) method returns an enumeration constant whose value corresponds to the string passed to it or throws an IllegalArgumentException if no constant with the specified name was found. Careful, the strings passed to valueOf are case sensitive!
Enum labels are case sensitive, so 'happy' is not the same as 'HAPPY' . White space in the labels is significant too.
you can see the class org.springframework.core.convert.support.StringToEnumConverterFactory, so you can customize yourself converterFactory like this.
public class MyStringToEnumConverterFactory implements ConverterFactory<String, Enum> {
@Override
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnum(getEnumType(targetType));
}
private class StringToEnum<T extends Enum> implements Converter<String, T> {
private final Class<T> enumType;
public StringToEnum(Class<T> enumType) {
this.enumType = enumType;
}
@Override
public T convert(String source) {
if (source.isEmpty()) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
return (T) Enum.valueOf(this.enumType, source.trim().toUpperCase());
}
}
private static Class<?> getEnumType(Class targetType) {
Class<?> enumType = targetType;
while (enumType != null && !enumType.isEnum()) {
enumType = enumType.getSuperclass();
}
if (enumType == null) {
throw new IllegalArgumentException(
"The target type " + targetType.getName() + " does not refer to an enum");
}
return enumType;
}
}
and add to ConverterRegistry .
@Configuration
public class MyConfiguration {
@Bean
public ConverterRegistry initConverter(ConverterRegistry registry) {
registry.addConverterFactory(new MyStringToEnumConverterFactory());
return registry;
}
}
Hope to help you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With