273 votes

Jackson enum Serializing et DeSerializer

J'utilise JAVA 1.6 et Jackson 1.9.9. J'ai un enum

public enum Event {
    FORGOT_PASSWORD("forgot password");

    private final String value;

    private Event(final String description) {
        this.value = description;
    }

    @JsonValue
    final String value() {
        return this.value;
    }
}

J'ai ajouté une @JsonValue, qui semble faire le travail en sérialisant l'objet :

{"event":"forgot password"}

mais quand j'essaie de désérialiser, j'obtiens une

Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.globalrelay.gas.appsjson.authportal.Event from String value 'forgot password': value not one of declared Enum instance names

Qu'est-ce que je rate ici ?

4 votes

Avez-vous essayé {"Event":"FORGOT_PASSWORD"} ? Notez les majuscules sur Event et FORGOT_PASSWORD.

0 votes

Ceux qui sont venus ici ont également vérifié la syntaxe des getter setter si vous suivez une convention de dénomination différente, c'est-à-dire qu'au lieu de getValue ce GetValue ne fonctionne pas

12voto

Durga Points 141

Essayez ça.

public enum Event {

    FORGOT_PASSWORD("forgot password");

    private final String value;

    private Event(final String description) {
        this.value = description;
    }

    private Event() {
        this.value = this.name();
    }

    @JsonValue
    final String value() {
        return this.value;
    }
}

9voto

Evgeniy Sokolov Points 56

J'aime le réponse acceptée . Toutefois, je l'améliorerais un peu (compte tenu du fait qu'il existe désormais des versions de Java supérieures à la version 6).

Ejemplo:

    public enum Operation {
        EQUAL("eq"),
        NOT_EQUAL("ne"),
        LESS_THAN("lt"),
        GREATER_THAN("gt");

        private final String value;

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

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

        @JsonCreator
        public static Operation forValue(String value) {
            return Arrays.stream(Operation.values())
                .filter(op -> op.getValue().equals(value))
                .findFirst()
                .orElseThrow(); // depending on requirements: can be .orElse(null);
        }
    }

7voto

Fernando Gomes Points 740

Vous pouvez personnaliser la désérialisation pour n'importe quel attribut.

Déclarez votre classe de désérialisation en utilisant l'annotationJsonDeserialize ( import com.fasterxml.jackson.databind.annotation.JsonDeserialize ) pour l'attribut qui sera traité. S'il s'agit d'une Enum :

@JsonDeserialize(using = MyEnumDeserialize.class)
private MyEnum myEnum;

De cette façon, votre classe sera utilisée pour désérialiser l'attribut. Voici un exemple complet :

public class MyEnumDeserialize extends JsonDeserializer<MyEnum> {

    @Override
    public MyEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        MyEnum type = null;
        try{
            if(node.get("attr") != null){
                type = MyEnum.get(Long.parseLong(node.get("attr").asText()));
                if (type != null) {
                    return type;
                }
            }
        }catch(Exception e){
            type = null;
        }
        return type;
    }
}

0 votes

Nathaniel Ford, ça va mieux ?

1 votes

Oui, c'est une bien meilleure réponse ; elle fournit un certain contexte. J'irais même plus loin, cependant, en expliquant pourquoi l'ajout de la désérialisation de cette manière résout l'obstacle spécifique du PO.

5voto

Gremash Points 3253

Voici un autre exemple qui utilise des valeurs de type chaîne au lieu d'une carte.

public enum Operator {
    EQUAL(new String[]{"=","==","==="}),
    NOT_EQUAL(new String[]{"!=","<>"}),
    LESS_THAN(new String[]{"<"}),
    LESS_THAN_EQUAL(new String[]{"<="}),
    GREATER_THAN(new String[]{">"}),
    GREATER_THAN_EQUAL(new String[]{">="}),
    EXISTS(new String[]{"not null", "exists"}),
    NOT_EXISTS(new String[]{"is null", "not exists"}),
    MATCH(new String[]{"match"});

    private String[] value;

    Operator(String[] value) {
        this.value = value;
    }

    @JsonValue
    public String toStringOperator(){
        return value[0];
    }

    @JsonCreator
    public static Operator fromStringOperator(String stringOperator) {
        if(stringOperator != null) {
            for(Operator operator : Operator.values()) {
                for(String operatorString : operator.value) {
                    if (stringOperator.equalsIgnoreCase(operatorString)) {
                        return operator;
                    }
                }
            }
        }
        return null;
    }
}

5voto

Sam Berry Points 3981

Il existe plusieurs approches pour réaliser la désérialisation d'un objet JSON vers un enum. Ma méthode préférée consiste à créer une classe interne :

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.fasterxml.jackson.annotation.JsonFormat.Shape.OBJECT;

@JsonFormat(shape = OBJECT)
public enum FinancialAccountSubAccountType {
  MAIN("Main"),
  MAIN_DISCOUNT("Main Discount");

  private final static Map<String, FinancialAccountSubAccountType> ENUM_NAME_MAP;
  static {
    ENUM_NAME_MAP = Arrays.stream(FinancialAccountSubAccountType.values())
      .collect(Collectors.toMap(
        Enum::name,
        Function.identity()));
  }

  private final String displayName;

  FinancialAccountSubAccountType(String displayName) {
    this.displayName = displayName;
  }

  @JsonCreator
  public static FinancialAccountSubAccountType fromJson(Request request) {
    return ENUM_NAME_MAP.get(request.getCode());
  }

  @JsonProperty("name")
  public String getDisplayName() {
    return displayName;
  }

  private static class Request {
    @NotEmpty(message = "Financial account sub-account type code is required")
    private final String code;
    private final String displayName;

    @JsonCreator
    private Request(@JsonProperty("code") String code,
                    @JsonProperty("name") String displayName) {
      this.code = code;
      this.displayName = displayName;
    }

    public String getCode() {
      return code;
    }

    @JsonProperty("name")
    public String getDisplayName() {
      return displayName;
    }
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X