Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson - Deserialize Interface to enum

Tags:

java

json

jackson

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.

like image 568
Ali Avatar asked Jan 20 '17 14:01

Ali


People also ask

How does Jackson deserialize enum?

By default, Jackson will use the Enum name to deserialize from JSON. If we want Jackson to case-insensitively deserialize from JSON by the Enum name, we need to customize the ObjectMapper to enable the ACCEPT_CASE_INSENSITIVE_ENUMS feature.

Can you make a interface for an enum?

Yes, Enum implements an interface in Java, it can be useful when we need to implement some business logic that is tightly coupled with a discriminatory property of a given object or class. An Enum is a special datatype which is added in Java 1.5 version.

Can enum be defined inside interface?

It's perfectly legal to have an enum declared inside an interface . In your situation the interface is just used as a namespace for the enum and nothing more. The interface is used normally wherever you use it.

Can you serialize an enum?

Because enums are automatically Serializable (see Javadoc API documentation for Enum), there is no need to explicitly add the "implements Serializable" clause following the enum declaration. Once this is removed, the import statement for the java. io. Serializable interface can also be removed.


2 Answers

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));
}
like image 137
Vlad Bochenin Avatar answered Sep 25 '22 01:09

Vlad Bochenin


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.

like image 34
Puce Avatar answered Sep 25 '22 01:09

Puce