How do I register a Spring converter for null values?

Viewed 471

My Spring Boot project has a handler with the following request parameter:

@RequestParam(value = "release", required = false) Release release

Release is an enum I have defined. I have a method, Release.parse(), which converts Strings to Releases. I register it in a @Configuration class that implements WebMvcConfigurer:

@Override
public void addFormatters(FormatterRegistry registry) {
    registry.addConverter(String.class, Release.class, Release::parse);
}

This works fine for non-null values, but I want this method to be called even when no query parameter is parsed (so I can map null to Release.DEVELOP).

The documentation for Spring type conversion says that "For each call to convert(S), the source argument is guaranteed to be NOT null."

So how do I set up a converter for when the argument IS null?

n.b. I can't do this using defaultValue in my @RequestParam annotation, as this requires a String (and doesn't allow static values, so I can't just read from my Release.DEVELOP enum).

1 Answers

The Converter-API has no way of doing this. The best solution is to execute some logic within your controller. The easiest way of doing so is by using the Optional API.

@GetMapping
public void handleRelease(@RequestParam Optional<Release> release) {
    Release actualRelease = release.orElse(Release.DEV);
}

The benefit of this is that it's clean and you no longer need to add the required = false parameter because that's implied since we use Optional. The drawback is that you would have to do so in very controller method.


Another option is to use a different conversion method. Spring MVC supports conversions for both the Converter-API and by the using PropertyEditor-API.

In stead of creating a converter, you have to define a PropertyEditor:

public class ReleasePropertyEditorSupport extends PropertyEditorSupport {
    @Override
    public void setValue(Object value) {
        super.setValue(value == null ? Release.DEV : value);
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        setValue(Release.parse(text));
    }
}

The setAsText() method does the conversion, but as with the converters, it isn't invoked when value is null. To handle custom null conversions, you can use a custom setValue() setter.

To register the property editor, you have to use a WebDataBinder. This can be done by adding the following method to a controller or a controller advice:

@InitBinder
public void initializeBinder(WebDataBinder dataBinder) {
    dataBinder.registerCustomEditor(Release.class, new ReleasePropertyEditorSupport());
}
Related