Spring Значение @RequestBody и 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();
    }
}

И класс под названием Review, этот класс содержит свойство типа 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;
    }
}

Наконец, у меня есть контроллер, который получает обзор объекта с @RequestBody.

@RestController
public class ReviewController {

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

Если я вызываю контроллер с помощью

{"reos":"VALUE1"}

Нет проблем, но когда я вызываю

{"reos":"A"}

Я получаю эту ошибку

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: [email protected]; 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: [email protected]; line: 1, column: 40] (through reference chain: com.microservices.Review["reos"])"

Я решил проблему, но мне хотелось узнать способ сказать Spring, что для каждого объекта с Reos enum используйте Reos.fromText() вместо Reos.valueof().

Возможно ли это?

Ответ 1

Я нашел то, что мне нужно.

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

Это было 2 шага.

  • Переопределить метод toString перечисления Reos

    @Override public String toString() {   возвратный текст; }

  • Аннотировать с помощью @JsonCreator метод fromText в перечислении Reos.

    @JsonCreator public static Reos fromText (текст строки)

И все.

Я надеюсь, что это может помочь другим, сталкивающимся с одной и той же проблемой.

Ответ 2

Я лично предпочитаю писать свой собственный класс десериализатора используя JsonDeserializer предоставленного jackson. Вам просто нужно написать класс десериализатора для вашего перечисления. В этом примере:

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);
    }
}

Затем мы должны отметить вышеприведенный класс как класс десериализатора Reos следующим образом:

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

   // your enum codes here
}

Все это. Мы все настроены.

Если вам нужен сериализатор для enum. Вы можете сделать это аналогичным образом, создав класс serializer, расширяющий JsonSerializer и используя аннотацию @JsonSerialize.

Надеюсь, это поможет.

Ответ 3

Вам нужно использовать пользовательский MessageConverter, который вызывает ваш собственный метод fromText(). Здесь описывается статья которая описывает, как это сделать.

Вы расширяете AbstractHttpMessageConverter<Reos> и реализуете необходимые методы, а затем регистрируете его.