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>
и реализуете необходимые методы, а затем регистрируете его.