2
votes

I have a spring-boot application which is exposing a Rest API. This API accepts a list of enums batchStatus as query parameter. This batchStatus is to be used to filter all the batches based on their status.

When trying to invoke this rest api, I'm getting the following error

{
  "timestamp": 1552587376808,
  "status": 400,
  "error": "Bad Request",
  "message": "Failed to convert value of type 'java.lang.String[]' to required type 'java.util.List'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.annotations.ApiParam @javax.validation.Valid @org.springframework.web.bind.annotation.RequestParam com.netshell.test.spring.conversion.rest.api.model.BatchStatus] for value 'active'; nested exception is java.lang.IllegalArgumentException: No enum constant com.netshell.test.spring.conversion.rest.api.model.BatchStatus.active",
  "path": "/batch/status"
}

Spring is looking for active in BatchStatus instead of ACTIVE.

Looking deep into the spring ConversionService I've discovered two converters
1. StringToEnumConverterFactory (from spring-core)
2. StringToEnumIgnoringCaseConverterFactory (from spring-boot)

Is there any mechanism in spring-boot to force use of second converter?

Further debugging showed that both the converters are registered with ConversionService, however there are multiple instances of conversionService each with different number of converters. In this case how does spring select which conversionService to use?

Enum BatchStatus is created as following

public enum BatchStatus {
    ACTIVE("active"),
    FAILED("failed"),
    HOLD("hold");

    private String value;
    BatchStatus(String value) {
        this.value = value;
    }

    @Override
    @JsonValue
    public String toString() {
        return String.valueOf(value);
    }

    @JsonCreator
    public static BatchStatus fromValue(String text) {
        for (BatchStatus b : BatchStatus.values()) {
            if (String.valueOf(b.value).equals(text)) {
                return b;
            }
        }
        return null;
    }
}
1

1 Answers

2
votes

Looking at the issue tracker of the Spring project you can find this issue, which basically asks for the StringToEnumIgnoringCaseConverterFactory class to be made public.
However it seems it won't happen anytime soon, as this is still in progress.

What you could try is configuring that Converter via WebMvcConfigurer#addFormatters

@Configuration
class CustomWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addFormatters(final FormatterRegistry registry) {
        ApplicationConversionService.configure(registry);
    }
}

ApplicationConversionService#configure will register StringToEnumIgnoringCaseConverterFactory for you, by calling the addApplicationConverters method

/** Spring Framework code */
public static void addApplicationConverters(ConverterRegistry registry) {
    ...
    registry.addConverterFactory(new StringToEnumIgnoringCaseConverterFactory());
}

And btw, that's the only reference to StringToEnumIgnoringCaseConverterFactory, so it's your only hope ; ) (don't use Reflection! Resist the urge)