stefan.stt
stefan.stt

Reputation: 2627

Converter works for RequestParameter but not for RequestBody field

I have the following converter:

@Component
public class CountryEnumConverter implements Converter<String, CountryEnum> {

    @Override
    public CountryEnum convert(String country) {
        CountryEnum countryEnum = CountryEnum.getBySign(country);

        if (countryEnum == null) {
            throw new IllegalArgumentException(country + " - Country is not supported!");
        }

        return countryEnum;
    }
}

Registered it is invoked when used for RequestParam

@GetMapping(value = RestApiEndpoints.RESULTS, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResultDto> getResults(
        Principal principal,
        @RequestParam CountryEnum country) {
    ....
}

But this converter is never invoked when used for field in the RequstBody:

@GetMapping(value = RestApiEndpoints.RESULTS, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResultDto> getResults(
        Principal principal,
        @RequestBody MyBody myBody) {
    ....
}

public class MyBody {

    @NotNull
    private CountryEnum country;


    public MyBody() {
    }

    public CountryEnum getCountry() {
        return country;
    }

    public void setCountry(CountryEnum country) {
        this.country = country;
    }

}

Upvotes: 0

Views: 441

Answers (2)

stefan.stt
stefan.stt

Reputation: 2627

I found out that if I add the following code to my CountryEnum will do the trick.

@JsonCreator
public static CountryEnum fromString(String value) {
    CountryEnumConverter converter = new CountryEnumConverter();
    return converter.convert(value);
}

Upvotes: 0

Alan Hay
Alan Hay

Reputation: 23246

Your existing org.springframework.core.convert.converter.Converter instance will only work with data submitted as form encoded data. With @RequestBody you are sending JSON data which will be deserialized using using the Jackson library.

You can then create an instance of com.fasterxml.jackson.databind.util.StdConverter<IN, OUT>

public class StringToCountryTypeConverter extends StdConverter<String, CountryType> {

  @Override
  public CountryType convert(String value) {
      //convert and return
  }
}

and then apply this on the target property:

public class MyBody {

    @NotNull
    @JsonDeserialize(converter = StringToCountryTypeConverter.class)
    private CountryEnum country;
}

Given the similarity of the 2 interfaces I would expect that you could create one class to handle both scenarios:

public class StringToCountryTypeConverter extends StdConverter<String, CountryType> 
           implements org.springframework.core.convert.converter.Converter<String, CountryType> {
  @Override
  public CountryType convert(String value) {
      //convert and return
  }
}

Upvotes: 2

Related Questions