Библиотека Jackson является мощным инструментом для сериализации и десериализации данных в формат JSON в Java-приложениях. Она предоставляет гибкую и эффективную обработку данных, позволяя преобразовывать Java-объекты в JSON-строки (сериализация) и обратно (десериализация).

Но не всегда процесс десериализации данных в библиотеке Jackson происходит очевидным образом. В этой статье я хочу разобрать несколько примеров не очевидной десериализации Boolean в библиотеке Jackson.

Особенности реализации

В языке Java класс Boolean представляет собой обертку над примитивным типом данных, который может принимать значения: true (истина), false (ложь) или быть равно null. А вы знали, что при десериализации в класс Boolean в JSON можно передавать не только значения true, false и null, но и другие?

Довольно логичным является тот факт, что если передать значения true или false в кавычках, как строку, то оно интерпретируется Jackson как соответствующее значение. А если передать "null", возникнет ли ошибка десериализации?

Hidden text

Нет, ошибки не будет, переменная будет равна null

Jackson так же умеет десериализовать значения "True", "TRUE", "False", "FALSE". Другие варианты написания приведут к ошибке.

Предлагаю продолжить эксперименты, что будет, если передать пустую строку ("")?

Hidden text

Переменная так же будет равна null

Вторым довольно очевидным является то, что можно передавать значения 0 и 1 в JSON, и эти числовые значения успешно десериализуются в класс Boolean, соответственно, 0 преобразуется в false, а 1 - в true.

Но попробуйте предположить, что будет, если передать любое другое целое число?

Hidden text

Любое целое число при десериализации в класс Boolean интерпретируется Jackson как true, независимо от того, является ли оно положительным или отрицательным.

Фичи

Если вам недостаточно описанного выше, то Jackson может предложить вам еще кое-что для десериализации класса Boolean.

Внимание ⚠: Данная функциональность представлена для ознакомления, используйте ее, если точно понимаете, что она делает и к каким последствиям это приведет.

В Jackson есть много разных фич для десериализации, и для нашего Boolean может пригодиться несколько из них. Первая фичa UNWRAP_SINGLE_VALUE_ARRAYS, название говорит само за себя, если в качестве значения передан массив с одним значением, то он разворачивается в это значение. В таком случае, если передать значение:

{
  "bool": [-8788888888888888888888888888888]
}

то оно десериализуется в true. Здорово, правда? Будет работать во всех вышеописанных случаях.

Но что, если передать пустой массив, если хочется получить null? Работать не будет, будет ошибка десериализации. А если очень хочется, то можно включить фичу ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, которая, ожидаемо будет приводить пустой массив к null, и наша переменная будет равна именно ему.

Вот и все. Теперь, когда вы осознали эту магию, можете смело использовать это в своих проектах (за исключением последней части). Важно помнить, что при работе с десериализацией Boolean в JSON необходимо быть внимательными и учитывать спецификации и требования вашего проекта. Правильное понимание этих особенностей позволит вам избежать ошибок и создать более надежные и гибкие системы обработки данных.

Комментарии (12)


  1. dopusteam
    21.06.2023 13:54

    В языке Java тип Boolean представляет собой обертку над примитивным типом данных, который может принимать значения: true (истина), false (ложь) или быть равно null

    В Java тип boolean может хранить null?



    1. arionaRu Автор
      21.06.2023 13:54
      +2

      Есть тип boolean, который может быть только true или false, а есть Boolean, который является оберткой над примитивом и может быть null. При обмене данными с помощью json часто используют второй, т.к. при добавлении параметра в процессе разработки API десериализация в false при отсутствии параметра в запросе (например, не все потребители в курсе, что API изменилось, или им лень дорабатывать) не всегда будет являться корректной.

      Спасибо за замечание, исправила слово тип на слово класс, так более корректно.


    1. breninsul
      21.06.2023 13:54
      +1

      boolean это примитив и не может быть null, а Boolean это класс-враппер boolean, соответственно может быть null как другие обьекты


  1. breninsul
    21.06.2023 13:54

    Если про фичи - они же не относятся конкретно к Boolean, так можно поступить с любым классом (пустой массив как null и массив как значение).

    А вот то, что любое число кроме 0 сериализуется в true в поведении по умолчанию - это трындец. Падать должно, это же человек неправильно смапил поле.


    1. mmMike
      21.06.2023 13:54
      +2

      Вы не поверите в скольких БД и каком количестве кода используется boolean значение как 0/1. Это пошло еще с 70-х годов и корни глубокие.
      И сколько лично я видел спецификаций в которых json boolean как "0"/"1" определен.
      Так что "не судите и не судимы будете". :)


      1. breninsul
        21.06.2023 13:54
        -1

        0/1 понятно, а вот -8700 падать должно


        1. mmMike
          21.06.2023 13:54
          +1

          0/не 0 - стандартная логика переходов в ассемблере. Которая плавно переползла в C, потом в C++ и кое где навечно застряла.
          создатели парсера сталкиваются со всем многообразием. Возможно кто то попросил сделать еще и эту логику в ущерб "ой мы тут ошибку допустили и на нее должно ругаться".
          Я не знаю причин почему принцип "0/ не 0" перенесен на парсер json. Но явно были причины. Поскольку это не ошибка в коде парсера. А так сделано специально.


      1. TimReset
        21.06.2023 13:54

        Я как-то в jdbc дайвер Oracle залез - там ещё Y и N поддерживается. Помимо true, false, 1, 0. Вроде ещё что-то но тут уже не уверен.

        А сделал это когда удивился почему это метод getBoolean ( https://docs.oracle.com/javase/8/docs/api/java/sql/ResultSet.html#getBoolean-int- ) нормально работает хотя в базе у нас был varchar, char, number со значениями 1/0 (в виде числа и символов) и Y/N. И вот там внутри прям много эвристика - типа если в базе число то смотрим на 1 и 0. Если char (один символ) то Y, N, 1, 2. Если varchar ( несколько символов) - то ещё true и false.


        1. breninsul
          21.06.2023 13:54

          ну y/n это нормально.


  1. Kinski
    21.06.2023 13:54
    +2

    Собственно, первая часть статьи - обычное поведение слаботипизированного JavaScript (не зря же JSON это JavaScript Object Notation).

    Ну а фичи второй части статьи вытекают из первой) Иногда могут быть полезны, но я бы предпочел ловить ошибки, чем разбираться почему массив вдруг превратился в true)


    1. breninsul
      21.06.2023 13:54
      +1

      по поводу массивов это не поведение по умолчанию.

      Бывает полезно когда внешнее апи имеет кривой дизайн и поле приходит массивом