Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How allow case-insensitive mapping of enums in jackson/Spring boot?

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.

like image 522
Don Rhummy Avatar asked Mar 08 '18 14:03

Don Rhummy


People also ask

How does Jackson handle enums?

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.

Is Jackson ObjectMapper case sensitive?

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.

Is Java enum case sensitive?

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!

Should enums be case sensitive?

Enum labels are case sensitive, so 'happy' is not the same as 'HAPPY' . White space in the labels is significant too.


1 Answers

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!

like image 195
Tonney Bing Avatar answered Nov 05 '22 10:11

Tonney Bing