#java #jackson #jackson-databind
#java #json #джексон
Вопрос:
У меня есть пользовательский объект :
public class Response
{
@JsonProperty("values")
private List<Value> values;
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
public static class Value {
public Value(long timestamp, float val)
{
this.timestamp = timestamp;
this.val = val;
}
}
}
Но когда это анализируется, я получаю «Не удается десериализовать экземпляр ответа $Value из токена START_ARRAY».
JSON является :
{
"values":[[1552215648,18]]
}
Есть идеи, если я чего-то здесь не хватает? Или у меня должен быть пользовательский десериализатор для выполнения этого?
Ответ №1:
JsonFormat
делает трюк, но вам также нужно объявить конструктор с JsonCreator
аннотацией. Взгляните на приведенный ниже пример:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
Response myPojo = mapper.readValue(jsonFile, Response.class);
System.out.println(myPojo);
}
}
class Response {
private List<Value> values;
public List<Value> getValues() {
return values;
}
public void setValues(List<Value> values) {
this.values = values;
}
@Override
public String toString() {
return "Response{"
"values=" values
'}';
}
}
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
class Value {
private long timestamp;
private float val;
@JsonCreator
public Value(@JsonProperty("timestamp") long timestamp, @JsonProperty("val") float val) {
this.timestamp = timestamp;
this.val = val;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public float getVal() {
return val;
}
public void setVal(float val) {
this.val = val;
}
@Override
public String toString() {
return "Value{"
"timestamp=" timestamp
", val=" val
'}';
}
}
Приведенный выше код для JSON
полезной нагрузки ниже:
{
"values": [
[
1552215648,
18
],
[
123,
12.24
]
]
}
С принтами:
Response{values=[Value{timestamp=1552215648, val=18.0}, Value{timestamp=123, val=12.24}]}
Комментарии:
1. Спасибо Михал. Это, казалось, сделало свое дело. Кроме того, оказывается, я использовал objectmapper jackson.map, а не jackson.databind. Это также приводило к ненужной ошибке.
Ответ №2:
Вы должны JsonFormat
изменить переменную values
. Также, поскольку у вас есть переменная типа List
, вам не нужно добавлять JsonFormat
.
public class Response
{
@JsonProperty("values")
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
private List<Value> values;
public static class Value {
private long timestamp;
private float val;
// Getters and Setters
public Value(long timestamp, float val)
{
this.timestamp = timestamp;
this.val = val;
}
}
}
Ваш формат ввода JSON будет:
{
values: [
{
"timestamp": 589988,
"val": 56.0,
}
]
}
Надеюсь, это поможет!! Я не тестировал код, поэтому, пожалуйста, игнорируйте проблемы с синтаксисом, если таковые имеются.
Комментарии:
1. Ах, JsonFormat для значений переменных также не помогает. :/ Переменная — это список списка, верно? Итак, для внутреннего списка мне понадобится JsonFormat.
2. Нет, формат ввода будет отличаться. Добавит это к ответу
3. Да, к сожалению, у меня нет контроля над ответом. Это массив long и float. Не карта. Массив будет иметь вид [[1573820208,45.5]]
Ответ №3:
Я знаю, что прошло некоторое время, но поскольку я имел дело с той же проблемой (десериализация части ответа Prometheus REST API?), и предоставленные ответы не помогли, я хотел бы поделиться своим решением, которое должно работать для каждого подобного случая.
Кроме того, @JsonFormat(shape=JsonFormat.Shape.ARRAY)
мне было необходимо добавить также @JsonPropertyOrder
аннотацию, чтобы отразить порядок, в котором значения отображаются в массиве. Мне также нужна была @JsonCreator
аннотация к конструктору и @JsonProperty
перед аргументом каждого конструктора. Используя ваш класс в качестве примера, он должен выглядеть следующим образом:
public class Response
{
private List<Value> values;
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
@JsonPropertyOrder({"timestamp", "val"})
public static class Value {
private long timestamp;
private float val;
@JsonCreator
public Value(@JsonProperty("timestamp") long timestamp,
@JsonProperty("val") float val)
{
this.timestamp = timestamp;
this.val = val;
}
// Getters and Setters
}
}
Только после того, как я использовал этот конкретный набор аннотаций, мой ответ был десериализован без каких-либо ошибок.
Надеюсь, это кому-то поможет! 😉
РЕДАКТИРОВАТЬ: Одно примечание: в ответе Prometheus, который я получил, был вызван массив значений разных типов value
, а не values
, следовательно, может потребоваться добавить поле @JsonProperty("value")
on private List<Value> values;
или изменить его имя на value
, если это имеет место для кого-либо 😉
@JsonProperty("value")
private List<Value> values;