Reputation: 93
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?
Upvotes: 1
Views: 6793
Reputation: 1660
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);
}
Upvotes: 4
Reputation: 2900
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());
}
}
Upvotes: 2
Reputation: 18480
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());
}
}
Upvotes: 1