Serialize java objects to json

Сериализация в JSON

— Раз уж ты познакомился с JSON, давай поговорим о нем сегодня подробнее.

— Ок. А где обычно он используется?

— Обычно дело выглядит так. Кто-то (клиент) запрашивает у Java-программы (сервера) данные. Программа создает Java-объекты и заполняет их информацией из базы данных. Затем преобразовывает их в формат понятный запрашивающему (клиенту), например JSON, и отсылает их обратно.

Давай я тебе расскажу, как работать с ним из Java. Собственно, нам понадобятся только две вещи – сериализовать Java-объекты в JSON-формат и десериализовать Java-объекты из формата JSON.

Т.е. JSON – это стандарт транспортировки сообщений/данных от одной программы к другой. Таких стандартов довольно много. Но если программа написана на JavaScript, она обычно старается работать с JSON.

Сериализация в JSON - 1

Как ты уже знаешь, в Java есть встроенные стандартные средства сериализации. Но JSON к ним не относится. Поэтому если тебе надо использовать сериализацию объекта в JSON, ты можешь использовать один из популярных фреймворков(библиотек), которые это умеют.

— А чем отличаются различные фреймворки?

— Обычно они отличаются степенью сложности: есть фреймворки, которые умеют делать только самое необходимое, но они очень маленькие и простые. А есть и большие сложные фреймворки, которые могут делать гораздо больше.

Одним из популярных фреймворков считается Jackson. Мы рассмотрим работу с JSON на его примере.

Для начала тебе надо скачать этот фреймворк и добавить его себе в проект. Делать это надо в Intellij IDEA само собой. Загрузить фреймворк можно по ссылке.

Сконвертировать Java-объект в JSON примерно так же просто, как и сериализовать его. Для этого есть специальный класс ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper).

Давай я покажу тебе рабочий пример, а потом мы его разберем:

public static void main(String[] args) throws IOException < //создание объекта для сериализации в JSON Cat cat = new Cat(); cat.name = "Murka"; cat.age = 5; cat.weight = 4; //писать результат сериализации будем во Writer(StringWriter) StringWriter writer = new StringWriter(); //это объект Jackson, который выполняет сериализацию ObjectMapper mapper = new ObjectMapper(); // сама сериализация: 1-куда, 2-что mapper.writeValue(writer, cat); //преобразовываем все записанное во StringWriter в строку String result = writer.toString(); System.out.println(result); >

В строках 4-7 мы создаем объект класса Cat и заполняем его данными.

Строка 10 – создаем объект Writer, куда будем писать строку — JSON представление объекта.

Строка 13 – создаем объект ObjectMapper , который и выполняет всю сериализацию.

Строка 16 – пишем JSON-представление объекта cat в writer .

Читайте также:  Python self super init

Строки 19-20 – выводим результат на экран.

Все выглядит довольно просто. Не сложнее родной сериализации в Java.

— А как будет выглядеть десериализация?

— Да почти так же, только короче:

public static void main(String[] args) throws IOException < String jsonString text-viola">"; StringReader reader = new StringReader(jsonString); ObjectMapper mapper = new ObjectMapper(); Cat cat = mapper.readValue(reader, Cat.class); >

Тут еще проще. Берем ObjectMapper и передаем в него строку с JSON или StringReader, а также класс объекта, который надо десериализовать . Вызываем метод readValue, и на выходе получаем готовый Java-объект со всеми данными.

— Ну, точно, как десериализация в Java.

— Почти. К объектам, которые сериализуются/десериализуются в JSON есть несколько требований:

1) поля должны быть видимые: или public или иметь getter’ы и setter’ы;

2) должен быть конструктор по умолчанию (без параметров).

— Ясно. Ожидаемо, в общем. Хотя Java отлично сериализовала и private поля.

— Так то — Java. У нее есть доступ к скрытым данным. От себя не утаишь.

Тут есть еще третий аспект. Надеюсь, ты обратил внимание на аннотацию @JsonAutoDetect в классе Cat?

— Ага. Как раз хотел спросить – что это такое.

— Это аннотации – служебная информация для фреймворка Jackson. Можно очень гибко управлять результатом сериализации в JSON формат, расставляя правильные аннотации.

— Круто! А что за аннотации есть?

Аннотация Описание
@JsonAutoDetect Ставится перед классом.
Помечает класс как готовый к сериализациив JSON.
@JsonIgnore Ставится перед свойством.
Свойство игнорируется при сериализации.
@JsonProperty Ставится перед свойством или getter’ом или setter’ом. Позволяет задать другое имя поля при сериализации.
@JsonPropertyOrder Ставится перед классом.
Позволяет задать порядок полей для сериализации.

— Есть много. Но не сейчас. Сейчас давай немного переделаем наш первый пример:

public static void main(String[] args) throws IOException < Cat cat = new Cat(); cat.name = "Murka"; cat.age = 5; cat.weight = 4; StringWriter writer = new StringWriter(); ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(writer, cat); String result = writer.toString(); System.out.println(result); >

Код остался тот же, но я поменяла аннотации: указала другое имя полю name — имя alias. А также отметила поле weight как Ignore, в результате JSON объекта поменялся.

— Хорошо, что можно так всего настраивать – думаю, мне это обязательно пригодится.

А десериализация поймет, как с этим работать? При десериализации из JSON в Java-объект, значение поля alias будет занесено в name объекта Cat?

— Да, десериализация будет работать как надо. Она умная.

Спасибо за такую интересную лекцию, Элли.

Источник

Using Jackson for JSON Serialization and Deserialization

Jackson is one of the most common Java libraries for processing JSON. It is used for reading and writing JSON among other tasks. Using Jackson, you can easily handle automatic conversion from Java objects to JSON and back. In this article, we delve into some common Jackson usage patterns.

Читайте также:  METANIT.COM

2. Converting a POJO to JSON

Suppose we want to convert a sample POJO (Plain Old Java Object) to JSON. An example class is defined below.

public class User < private String firstName; private String lastName; private Date dateOfBirth; private ListemailAddrs; public User(String firstName,String lastName) < this.firstName = firstName; this.lastName = lastName; >// standard getters and setters here >

Converting such an object to JSON is just a couple of lines:

ObjectMapper mapper = new ObjectMapper(); User user = new User(«Harrison», «Ford»); user.setEmailAddrs(Arrays.asList(«harrison@example.com»)); mapper.writeValue(System.out, user); // prints:

3. Pretty Printing

Note that the default output is quite compact. Sometimes it is useful to be able to view indented output for debugging purposes. To produce properly indented output, enable the option SerializationFeature.INDENT_OUTPUT on the ObjectMapper instance before using it to serialize the object.

ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); User user = new User("Harrison", "Ford"); .

The output generated now is nicely indented:

4. Ignore NULL fields

How do we tell Jackson not to serialize null values (as for “ dateOfBirth ” above)? There are a couple of ways. You can tell the ObjectMapper to skip all NULL fields, or you can use annotations to specify per class or per field.

4.1. Configuring ObjectMapper

. mapper.setSerializationInclusion(Include.NON_NULL); User user = new User(«Harrison», «Ford»); . // prints:

4.2. With an Annotation

Use the annotation @JsonInclude(Include.NON_NULL) on the target object class to eliminate serialization of all NULL fields.

@JsonInclude(Include.NON_NULL) public class User

Or on a field (or property) to disable specific NULL fields from being serialized. In the code below, dateOfBirth will be ignored if null, but not heightInM .

. @JsonInclude(Include.NON_NULL) private Date dateOfBirth; private Float heightInM; .

5. Ignore Empty Arrays

When you have a class with an empty array initializer, the value is serialized as an empty JSON array.

class User < . private ListphoneNumbers = new ArrayList<>(); . > // serialized to:

When you want to skip empty array declarations being output, you can use the following.

mapper.setSerializationInclusion(Include.NON_EMPTY);

6. Generate JSON String

How can we generate a JSON string representation instead of writing it directly to a file or an OutputStream? Maybe you want to store the JSON string in a database. Use the writeValueAsString() method.

// set up user String jsonStr = mapper.writeValueAsString(user);

7. Formatting Dates

By default, Jackson prints Date fields as numeric timestamps as shown below:

Calendar c = Calendar.getInstance(); c.clear(); c.set(1942, 6, 13); user.setDateOfBirth(c.getTime()); // prints:

Turning off numeric timestamp results in serialization of a date in the ISO 8601 format as shown below:

. mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); . // prints:

Change the default date format by using SimpleDateFormat as shown:

. DateFormat fmt = new SimpleDateFormat(«dd-MMM-yyyy»); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); . // prints:

8. Converting JSON to POJO

Reading and converting JSON to a Java object is just as easy with Jackson. Accomplished in just a couple of lines:

ObjectMapper mapper = new ObjectMapper(); User user = mapper.readValue(new File(jsonFile), User.class);

The target class (User in this case) needs a no-arguments default constructor defined – failing which you get this exception:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of sample.User: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

The situation is easily address by adding a no-arguments default constructor.

public class User < private String firstName; private String lastName; private Date dateOfBirth; private ListemailAddrs; public User() <> . >

9. Adjusting Date Format

As before, the date format needs to be adjusted unless it is in ISO 8601 format. Parsing the following JSON fails:

Читайте также:  Typescript const in class

The following exception is reported:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "13-Jul-1942": not a valid representation (error: Failed to parse Date value '13-Jul-1942': Can not parse date "13-Jul-1942": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))

Specify the date format if you are using a non-standard format as shown:

DateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy"); mapper.setDateFormat(fmt);

10. Ignoring Unknown Properties

Sometimes the JSON you are trying to read might include some properties not defined in the Java class. Maybe the JSON was updated but the change is not yet reflected in the Java class. In such cases, you might end up with an exception like this:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "gender" (class sample.User), not marked as ignorable (6 known properties: . )

You can tell Jackson to ignore such properties on a global level by disabling a deserialization feature as follows:

mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

Alternatively, you can use the following annotation on the class to ignore unknown properties.

@JsonIgnoreProperties(ignoreUnknown=true) public class User

11. Serializing Array of Objects to JSON

Serializing an array of objects to JSON is straightforward.

ObjectMapper mapper = new ObjectMapper(); List users = new ArrayList<>(); users.add(new User(. )); users.add(new User(. )); System.out.println(mapper.writeValueAsString(users));

The array is properly serialized as shown:

12. Deserialize Array of Objects from JSON

Several methods are available to deserialize a JSON array to a collection of Java objects. Use whatever method suits you depending on your requirements.

Deserializing a JSON array to a Java array of objects of a particular class is as simple as:

User[] users = mapper.readValue(new File(jsonFile), User[].class); System.out.println(mapper.writeValueAsString(users));

Using a JavaType is useful when constructing collections or parametric types.

JavaType listType = mapper .getTypeFactory() .constructCollectionType(List.class, User.class); List users = mapper.readValue(new File(jsonFile), listType); System.out.println(mapper.writeValueAsString(users));

A third method is to create and use a TypeReference.

TypeReference ref = new TypeReference>()<>; List users = mapper.readValue(new File(jsonFile), ref); System.out.println(mapper.writeValueAsString(users));

Summary

This article showed you how to convert Java objects to JSON and back. We also covered a few common use cases.

Источник

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