Java json serialization jackson

Введение в Jackson ObjectMapper

В этом руководстве основное внимание уделяется пониманию класса Jackson ObjectMapper и тому, как сериализовать объекты Java в JSON и десериализовать строку JSON в объекты Java.

Чтобы узнать больше о библиотеке Джексона в целом, можно начать с учебника по Джексону .

2. Зависимости

Давайте сначала добавим в pom.xml следующие зависимости :

 dependency>   groupId>com.fasterxml.jackson.coregroupId>   artifactId>jackson-databindartifactId>   version>2.13.0version>   dependency> 

Эта зависимость также транзитивно добавит в путь к классам следующие библиотеки:

Всегда используйте последние версии из центрального репозитория Maven для jackson-databind .

3. Чтение и запись с помощью ObjectMapper

Начнем с основных операций чтения и записи.

Простой API readValue ObjectMapper — хорошая отправная точка. Мы можем использовать его для анализа или десериализации содержимого JSON в объект Java.

Кроме того, на стороне записи мы можем использовать API writeValue для сериализации любого объекта Java в виде вывода JSON.

В этой статье мы будем использовать следующий класс Car с двумя полями в качестве объекта для сериализации или десериализации:

 public class Car     private String color;   private String type;    // standard getters setters   > 

3.1. Объект Java в JSON

Давайте посмотрим на первый пример сериализации объекта Java в JSON с использованием метода writeValue класса ObjectMapper :

 ObjectMapper objectMapper = new ObjectMapper();   Car car = new Car("yellow", "renault");  objectMapper.writeValue(new File("target/car.json"), car); 

Вывод вышеуказанного в файле будет:

Методы writeValueAsString и writeValueAsBytes класса ObjectMapper генерируют JSON из объекта Java и возвращают сгенерированный JSON в виде строки или массива байтов:

 String carAsString = objectMapper.writeValueAsString(car); 

3.2. JSON в объект Java

Ниже приведен простой пример преобразования строки JSON в объект Java с использованием класса ObjectMapper :

 String json = "< \"color\" : \"Black\", \"type\" : \"BMW\" >";   Car car = objectMapper.readValue(json, Car.class); 

Функция readValue() также принимает другие формы ввода, например файл, содержащий строку JSON:

 Car car = objectMapper.readValue(new File("src/test/resources/json_car.json"), Car.class); 
 Car car =   objectMapper.readValue(new URL("file:src/test/resources/json_car.json"), Car.class); 

3.3. JSON в Джексон JsonNode

В качестве альтернативы JSON можно преобразовать в объект JsonNode и использовать для извлечения данных из определенного узла:

 String json = "< \"color\" : \"Black\", \"type\" : \"FIAT\" >";   JsonNode jsonNode = objectMapper.readTree(json);   String color = jsonNode.get("color").asText();   // Output: color -> Black 

3.4. Создание списка Java из строки массива JSON

Мы можем разобрать JSON в виде массива в список объектов Java, используя TypeReference :

 String jsonCarArray =   "[< \"color\" : \"Black\", \"type\" : \"BMW\" >, < \"color\" : \"Red\", \"type\" : \"FIAT\" >]";   ListCar> listCar = objectMapper.readValue(jsonCarArray, new TypeReferenceListCar>>()>); 

3.5. Создание карты Java из строки JSON

Точно так же мы можем разобрать JSON в карту Java :

 String json = "< \"color\" : \"Black\", \"type\" : \"BMW\" >";   MapString, Object> map   = objectMapper.readValue(json, new TypeReferenceMapString,Object>>()>); 

4. Расширенные функции

Одной из самых сильных сторон библиотеки Джексона является настраиваемый процесс сериализации и десериализации.

В этом разделе мы рассмотрим некоторые дополнительные функции, в которых входной или выходной ответ JSON может отличаться от объекта, который создает или использует ответ.

4.1. Настройка функции сериализации или десериализации

При преобразовании объектов JSON в классы Java, если в строке JSON есть новые поля, процесс по умолчанию приведет к исключению:

Строка JSON в приведенном выше примере в процессе синтаксического анализа по умолчанию для объекта Java для класса Car приведет к исключению UnrecognizedPropertyException .

С помощью метода configure мы можем расширить процесс по умолчанию, чтобы игнорировать новые поля :

 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);   Car car = objectMapper.readValue(jsonString, Car.class);    JsonNode jsonNodeRoot = objectMapper.readTree(jsonString);   JsonNode jsonNodeYear = jsonNodeRoot.get("year");   String year = jsonNodeYear.asText(); 

Еще один вариант основан на FAIL_ON_NULL_FOR_PRIMITIVES , который определяет, разрешены ли нулевые значения для примитивных значений:

 objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false); 

Аналогично, FAIL_ON_NUMBERS_FOR_ENUM определяет, разрешено ли сериализовать/десериализовать значения перечисления как числа:

 objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false); 

Вы можете найти полный список функций сериализации и десериализации на официальном сайте .

4.2. Создание пользовательского сериализатора или десериализатора

Еще одной важной функцией класса ObjectMapper является возможность регистрации собственного сериализатора и десериализатора .

Пользовательские сериализаторы и десериализаторы очень полезны в ситуациях, когда входной или выходной ответ JSON отличается по структуре от класса Java, в который он должен быть сериализован или десериализован.

Ниже приведен пример пользовательского сериализатора JSON :

 public class CustomCarSerializer extends StdSerializerCar>     public CustomCarSerializer()    this(null);   >    public CustomCarSerializer(ClassCar> t)    super(t);   >    @Override   public void serialize(   Car car, JsonGenerator jsonGenerator, SerializerProvider serializer)    jsonGenerator.writeStartObject();   jsonGenerator.writeStringField("car_brand", car.getType());   jsonGenerator.writeEndObject();   >   > 

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

 ObjectMapper mapper = new ObjectMapper();   SimpleModule module =   new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));   module.addSerializer(Car.class, new CustomCarSerializer());  mapper.registerModule(module);   Car car = new Car("yellow", "renault");   String carJson = mapper.writeValueAsString(car); 

Вот как выглядит Car (как вывод JSON) на стороне клиента:

 var carJson = "car_brand":"renault"> 

А вот пример пользовательского десериализатора JSON :

 public class CustomCarDeserializer extends StdDeserializerCar>     public CustomCarDeserializer()    this(null);   >    public CustomCarDeserializer(Class?> vc)    super(vc);   >    @Override   public Car deserialize(JsonParser parser, DeserializationContext deserializer)    Car car = new Car();   ObjectCodec codec = parser.getCodec();   JsonNode node = codec.readTree(parser);    // try catch block   JsonNode colorNode = node.get("color");   String color = colorNode.asText();   car.setColor(color);   return car;   >   > 

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

 String json = "< \"color\" : \"Black\", \"type\" : \"BMW\" >";   ObjectMapper mapper = new ObjectMapper();   SimpleModule module =   new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));   module.addDeserializer(Car.class, new CustomCarDeserializer());  mapper.registerModule(module);   Car car = mapper.readValue(json, Car.class); 

4.3. Обработка форматов даты

Сериализация java.util.Date по умолчанию создает число, т. е. отметку времени эпохи (количество миллисекунд с 1 января 1970 года, UTC). Но это не очень удобочитаемо для человека и требует дальнейшего преобразования для отображения в удобочитаемом формате.

Давайте обернем экземпляр Car , который мы использовали до сих пор, внутри класса Request со свойством datePurchased :

 public class Request      private Car car;   private Date datePurchased;    // standard getters setters   > 

Чтобы управлять строковым форматом даты и установить его, например, yyyy-MM-dd HH:mm az , рассмотрите следующий фрагмент:

 ObjectMapper objectMapper = new ObjectMapper();   DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");  objectMapper.setDateFormat(df);   String carAsString = objectMapper.writeValueAsString(request);   // output: ,"datePurchased":"2016-07-03 11:43 AM CEST"> 

Чтобы узнать больше о сериализации дат с Джексоном, прочитайте нашу более подробную статью .

4.4. Обработка коллекций

Еще одна небольшая, но полезная функция, доступная через класс DeserializationFeature , — это возможность генерировать нужный тип коллекции из ответа массива JSON.

Например, мы можем сгенерировать результат в виде массива:

 String jsonCarArray =   "[< \"color\" : \"Black\", \"type\" : \"BMW\" >, < \"color\" : \"Red\", \"type\" : \"FIAT\" >]";   ObjectMapper objectMapper = new ObjectMapper();  objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);   Car[] cars = objectMapper.readValue(jsonCarArray, Car[].class);   // print cars 
 String jsonCarArray =   "[< \"color\" : \"Black\", \"type\" : \"BMW\" >, < \"color\" : \"Red\", \"type\" : \"FIAT\" >]";   ObjectMapper objectMapper = new ObjectMapper();   ListCar> listCar = objectMapper.readValue(jsonCarArray, new TypeReferenceListCar>>()>);   // print cars 

Более подробная информация об обработке коллекций с помощью Jackson доступна здесь .

5. Вывод

Jackson — это надежная и зрелая библиотека сериализации/десериализации JSON для Java. API ObjectMapper предоставляет простой и гибкий способ анализа и создания объектов ответа JSON. В этой статье были рассмотрены основные особенности, которые делают библиотеку такой популярной.

Исходный код, прилагаемый к статье, можно найти на GitHub.

Оцените статью