drenda
drenda

Reputation: 6254

Accept empty String for Enum in REST calls in Spring Boot application

I made a Spring Boot 2 REST application. I'm consuming REST with Angular. I've a problem with enumeration.

A typical enum server side is:

public enum EngineType {
    DIESEL, METHANE, ELECTRIC;

    @Nullable
    public static EngineType valueOfNullable(String value) {
        try {
            return valueOf(value);
        } catch (Exception e) {
            return null;
        }
    }
}

Some entities use these enum as fields and of course they can be null. Unfortunately, when the client do a POST of an entity sending "" (empty string) for the enumeration (because it can be null), I've an error server side:

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `server.model.enums.EngineType` from String "": value not one of declared Enum instance names: [DIESEL, METHANE, ELECTRIC]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `server.model.enums.EngineType` from String "": value not one of declared Enum instance names: [DIESEL, METHANE, ELECTRIC]
 at [Source: (PushbackInputStream); line: 1, column: 153] (through reference chain: server.model.tickets.Ticket["engineType2"])

I understand the sense of the message and I can solve the problem creating a custom deserializer as this:

@Component
public class EngineTypeDeserializer extends JsonDeserializer<EngineType> {

    @Override
    public EngineType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        return EngineType.valueOfNullable(node.asText());
    }

}

but I should put this annotation @JsonDeserialize(using = EngineTypeDeserializer.class) in all EngineType fields in my beans.

I was looking for a better way to solve this problem. Do you have some advice?

Upvotes: 1

Views: 2558

Answers (1)

Mạnh Quyết Nguyễn
Mạnh Quyết Nguyễn

Reputation: 18235

You can register your custom serializer programmatically.

In your @Configuration class:

@Bean
@Primary // Use this to shadow other objectmappers, if anny
public ObjectMapper objectMapper(){
    ObjectMapper objMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addDeserializer(EngineType.class, new EngineTypeDeserializer());
    objMapper.registerModule(module);
}

Upvotes: 3

Related Questions