简体   繁体   中英

JSON deserialization to Enum with Java 8, Spring Boot Starter 2.1.9 and Lombok 1.18.10

I'm trying to deserialize to a enumeration but the JSON values (lowercase) differs from the enumeration constants (uppercase).

This is the enumeration:

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ContractTypes {

  @JsonProperty("product")
  PRODUCT("product"), 
  @JsonProperty("service")
  SERVICE("service");

  private String value;
}

As you can see, I have annotated the elements with the @JsonProperty annotation to try to map the provided value to the suitable constant.

I've also tryied to annotated the attribute value with a @JsonValue annotation. In both cases I obtain the same result:

Field error in object 'createContractRequestDto' on field 'contractType': rejected value [product]; codes [typeMismatch.createContractRequestDto.contractType,typeMismatch.contractType,typeMismatch.enm.ContractTypes,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [createContractRequestDto.contractType,contractType]; arguments []; default message [contractType]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'enm.ContractTypes' for property 'contractType'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [enm.ContractTypes] for value 'product'; nested exception is java.lang.IllegalArgumentException: No enum constant enm.ContractTypes.product]]

Why is not working the @JsonProperty and @JsonValue annotations? How must I code the solution to map the JSON value to the suitable enumeration element?

We can also create a custom converter.

public class ContractTypesConverter implements Converter<String, ContractTypes> {

   @Override
   public ContractTypes convert(String source) {
     return ContractTypes.valueOf(source.toUpperCase());
   }
}

this can be further written as like this (Thanks to lambda )

Converter<String, ContractTypes> converter = source -> ContractTypes.valueOf(source.toUpperCase());

And Register it with WebMvcConfigurer like this

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

   // ... other configurations

   @Override
   public void addFormatters(FormatterRegistry registry) {
      registry.addConverter(new ContractTypesConverter());
   }

}

This worked for me. Not sure what you have missed in your code.

@Getter
public enum ContractTypes {

    PRODUCT("product"),
    SERVICE("service");

    private String value;

    ContractTypes(String value){
        this.value = value;
    }

    @JsonValue
    public String getValue() {
        return value;
    }
}

@NoArgsConstructor
@Setter
@Getter
static class Holder {
    private ContractTypes contractTypes;
}

@Test
public void test() throws IOException {
    Holder holder = new ObjectMapper().readValue("{\"contractTypes\":\"product\"}", Holder.class);
    assertEquals(ContractTypes.PRODUCT, holder.contractTypes);
}

Those annotations work on the property not on enum type. You can use enum directly using like PRODUCT or write a Custom Deserializer and use that for deserialization annotating on property.

@JsonDeserialize(using = ContractTypesDeserializer.class)
ContractTypes contractTypes;

Customer Deserializer implementation

public class ContractTypesDeserializer extends StdDeserializer<ContractTypes> {
  private static final long serialVersionUID = -4714891596189L;

  public ContractTypesDeserializer() {
    super ContractTypes.class);
  }

  protected ContractTypesDeserializer(Class ContractTypes> type) {super(type);}

  @Override
  public ContractTypes deserialize(JsonParser parser, DeserializationContext context)
      throws IOException, JsonProcessingException {
      return ContractTypes.valueOf(parser.getText().toUpperCase());
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM