Reputation: 267049
I have an interface Event
and multiple enums that implement this interface (UserEvent
, BusinessEvent
, etc).
I want to deserialize the following json data:
{
"event" : "SIGNUP"
}
To this bean:
public class Input
{
private Event event;
public Event getEvent() {..}
public void setEvent(Event event) {..}
}
public enum UserEvent implements Event
{
SIGNUP;
}
Here, i'd like event to be deserialized to UserEvent.SIGNUP
.
How can I accomplish this? Reading up on @JsonTypeInfo
seems to indicate that an additional type
attribute would be needed, but in this case, there's just one string which maps directly to an enum value.
Upvotes: 7
Views: 2642
Reputation: 3072
You are using Event
interface for field event
in Input
and jackson doesn't know anything about UserEvent
as implementation of this interface.
You can use custom JsonDeserializer
to get value:
public interface Event {
}
public static class Input
{
private Event event;
@JsonDeserialize(using = EventDeserializer.class)
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
}
public enum UserEvent implements Event
{
SIGNUP;
}
public static class EventDeserializer extends StdDeserializer<Event> {
protected EventDeserializer() {
super(Event.class);
}
@Override
public Event deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return UserEvent.valueOf(p.getText());
}
}
@Test
public void converEnum() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
Input input = objectMapper.readValue("{\n" +
" \"event\" : \"SIGNUP\"\n" +
"}", Input.class);
Assert.assertThat(input.getEvent(), Matchers.is(UserEvent.SIGNUP));
}
Upvotes: 4
Reputation: 543
Having a similar task I ended up creating a custom deserializer:
public class IFooDeserializer extends StdDeserializer<IFoo> {
public IFooDeserializer() {
this(null);
}
public IFooDeserializer(Class<?> vc) {
super(vc);
}
@Override
public IFoo deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String value = p.getCodec().readValue(p, String.class);
return Stream.of(GoodFoo.values(), BadFoo.values())
.flatMap(Stream::of)
.filter(el -> el.name().equals(value))
.findAny()
.orElseThrow(() -> new RuntimeException("Could not deserialize foo: " + value));
}
}
Upvotes: 2
Reputation: 38122
For a single enum the jsonschema2pojo-maven-plugin generates code like the following:
@JsonCreator
public static Foo fromValue(String value) {
Foo constant = CONSTANTS.get(value);
if (constant == null) {
throw new IllegalArgumentException(value);
} else {
return constant;
}
}
I guess you could write a factory method which is annotated with @JsonCreator and somehow decides which enum to choose. I'm not sure if it matters much where you put this method.
Upvotes: 2