web-dev-qa-db-fra.com

Spring @RequestBody et valeur Enum

J'ai cette enum

public enum Reos {

    VALUE1("A"),VALUE2("B"); 

    private String text;

    Reos(String text){this.text = text;}

    public String getText(){return this.text;}

    public static Reos fromText(String text){
        for(Reos r : Reos.values()){
            if(r.getText().equals(text)){
                return r;
            }
        }
        throw new IllegalArgumentException();
    }
}

Et une classe appelée Review, cette classe contient une propriété du type enum Reos .

public class Review implements Serializable{

    private Integer id;
    private Reos reos;

    public Integer getId() {return id;}

    public void setId(Integer id) {this.id = id;}

    public Reos getReos() {return reos;}

    public void setReos(Reos reos) {
        this.reos = reos;
    }
}

Enfin, j'ai un contrôleur qui reçoit une critique d'objet avec le @RequestBody .

@RestController
public class ReviewController {

    @RequestMapping(method = RequestMethod.POST, value = "/reviews")
    @ResponseStatus(HttpStatus.CREATED)
    public void saveReview(@RequestBody Review review) {
        reviewRepository.save(review);
    }
}

Si j'invoque le contrôleur avec 

{"reos":"VALUE1"}

Il n'y a pas de problème, mais quand j'invoque avec 

{"reos":"A"}

Je reçois cette erreur

Could not read document: Can not construct instance of com.microservices.Reos from String value 'A': value not one of declared Enum instance names: [VALUE1, VALUE2] at [Source: Java.io.PushbackInputStream@23ce847a; line: 1, column: 40] (through reference chain: com.microservices.Review["reos"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of com.microservices.Reos from String value 'A': value not one of declared Enum instance names: [VALUE1, VALUE2] at [Source: Java.io.PushbackInputStream@23ce847a; line: 1, column: 40] (through reference chain: com.microservices.Review["reos"])"

J'ai compris le problème, mais je voulais savoir comment indiquer à Spring que pour chaque objet avec Reos enum, utilisez Reos.fromText () au lieu de Reos.valueof ().

Est-ce possible?

14
reos

J'ai trouvé ce dont j'avais besoin. 

http://chrisjordan.ca/post/50865405944/custom-json-serialization-for-enums-using-jackson

C'était 2 marches.

  1. Ignorer la méthode toString de l'énumération Reos

    @ Override Public String toString () { retourne le texte; }

  2. Annotez avec @JsonCreator la méthode fromText de l'énumération Reos.

    @JsonCreator Public static Reos fromText (String text)

Et c'est tout.

J'espère que cela pourrait aider d'autres personnes confrontées au même problème.

17
reos

Personnellement, je préfère écrire ma propre classe de désérialiseur en utilisant JsonDeserializer fourni par jackson. Vous devez juste écrire une classe de désérialiseur pour votre enum. Dans cet exemple:

class ReosDeserializer extends JsonDeserializer<Reos> {

    @Override
    public Reos deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

        ObjectCodec oc = jsonParser.getCodec();
        JsonNode node = oc.readTree(jsonParser);

        if (node == null) {
            return null;
        }

        String text = node.textValue(); // gives "A" from the request

        if (text == null) {
            return null;
        }

        return Reos.fromText(text);
    }
}

Ensuite, nous devrions marquer la classe ci-dessus en tant que classe de désoseur de Reos comme suit:

@JsonDeserialize(using = ReosDeserializer.class)
public enum Reos {

   // your enum codes here
}

C'est tout. Nous sommes tous ensemble. 

Au cas où vous auriez besoin du sérialiseur pour la enum. Vous pouvez le faire de la même manière en créant une classe de sérialiseur étendant JsonSerializer et en utilisant l'annotation @JsonSerialize.

J'espère que ça aide.

2
Manoj Shrestha

Vous devez utiliser une MessageConverter personnalisée qui appelle votre méthode fromText() personnalisée. Il y a un article ici qui explique comment le faire.

Vous étendez AbstractHttpMessageConverter<Reos> et implémentez les méthodes requises, puis vous l'enregistrez.

1
Chris Thompson