0

I have enum like this:

public enum Display {

@JsonProperty("hidden")
HIDDEN,

@JsonProperty("visible")
VISIBLE,

@JsonProperty("soon")
SOON}

And @RestController method:

...
@GetMapping(value = "/someobjects", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
@Valid
public SomeObject get(@RequestParam(value = "display", required = false) Display display) { 
...

When I send GET HTTP request /someobjects?display=visible it fails, but /someobjects?display=VISIBLE are working. How can I use @JsonProperty value in @RequestParam serialization so /someobjects?display=visible display value can be mapped to Display.VISIBLE enum?

pera.coyote
  • 41
  • 1
  • 10

2 Answers2

2

For start I don't think you need the @JsonProperty annotations in your Display enum (they won't help you for this case, unless you have put them for another reason).

You need to create a String to Enum converter which converts the String taken from the request to uppercase and then it can resolve the corresponding Display enum:

public class StringToDisplayConverter implements Converter<String, Display> {
    @Override
    public Display convert(String source) {
        return Display.valueOf(source.toUpperCase());
    }
}

And register it to Spring configuration

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToDisplayConverter());
    }
}
pleft
  • 7,567
  • 2
  • 21
  • 45
  • I put `@JsonProperty` annotation for my request/response serialization to JSON, it works with it and I would love to use the same annotation for `@RequestParam` too if it's possible – pera.coyote Sep 02 '21 at 13:26
  • 2
    Since you use it as RequestParam there is no "JSON" there, it is just a param name and a param value i.e. `?display=visible` so those annotations have no effect at all for this specific case. – pleft Sep 02 '21 at 13:30
  • Just add @Component to your converter and spring will pick it up automatically. No need for WebConfig. – Ondřej Stašek Jan 25 '23 at 12:09
0

Firstly I would point out the your input the "visible" is just a String. So server cannot correctly parse it into the enum Display.

if you need a deserializer, I suggest to have a view of this link below: JsonMappingException: Can not deserialize instance of enum out of START_OBJECT token

If you choose to annotate this interface using getMapping. It cannot receive a requestBody to parse a complicated json input. Under current situation, you need to add a converter to parse the string into enum which precisely is the solution from @pleft to this problem.

I could provide another converter to this if you need:

final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
    StringToEnumConverterFactory() {
    }

    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnumConverterFactory.StringToEnum(ConversionUtils.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;
        }

        public T convert(String source) {
            return source.isEmpty() ? null : Enum.valueOf(this.enumType, source.trim());
        }
    }
}

Finally I would not suggest to use the jsonProperty to produce the result.

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@AllArgsConstructor
public enum Display {

    /**
     * test
     */

    HIDDEN("hiddenTest"),

    /**
     * test
     */
    VISIBLE("visibleTest"),

    /**
     * test
     */
    SOON("soon");

    public final String value;
}

add @JsonFormat(shape = JsonFormat.Shape.OBJECT) annotations to this enum could produce better json result from the server if you are using jackson as the string to json parser.

Eason Du
  • 71
  • 4