javaenumsdeserializationobjectmapper

Java - Parse enum from api by text description


I have a lib which i cannot change. This lib has api method which returns json like this {OrderStatus=PartiallyFilledCanceled} and also this lib has a enum

@AllArgsConstructor
public enum OrderStatus {
    PARTIALLY_FILLED_CANCELED("PartiallyFilledCanceled");
    private final String description;
}

and dto with OrderStatus field.

So I got an error

java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.api.client.domain.OrderStatus` from String "PartiallyFilledCanceled": not one of the values accepted for Enum class:[PARTIALLY_FILLED_CANCELED]

My ObjectMapper configs:

objectMapper.registerModule(new JavaTimeModule());
objectMapper.enable(JsonParser.Feature.IGNORE_UNDEFINED);
objectMapper.coercionConfigFor(LogicalType.Enum).setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);

How can I use some custom deserializer without changing dto?


Solution

  • You need to iterate the possible values and pick the one with matching description.

    public class OrderStatusDeserializer extends StdDeserializer<OrderStatus> {
    
      public OrderStatusDeserializer() {
        super(OrderStatus.class);
      }
    
      @Override
      public OrderStatus deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        JsonNode node = parser.readValueAsTree();
        String value = node.textValue();
        for (OrderStatus orderStatus : OrderStatus.values()) {
          if (orderStatus.getDescription().equals(value)) {
            return orderStatus;
          }
        }
        //description was not found, handle according to needs
        throw new InvalidFormatException(parser, "Description not found", value, _valueClass);
      }
    }
    

    Register the deserializer directly with ObjectMapper:

    ObjectMapper mapper = new ObjectMapper();
    SimpleModule myModule = new SimpleModule();
    myModule.addDeserializer(OrderStatus.class, new OrderStatusDeserializer());
    mapper.registerModule(myModule);