Десериализация json, который содержит @JsonFormat(форма=JsonFormat.Форма.МАССИВ) и пользовательский объект с использованием jackson

#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;