Частные конструкторы Джексона, JDK 9+, Ломбок

Я ищу документацию о том, как Джексон работает с частными конструкторами неизменяемых типов. Использование Jackson 2.9.6 и средства сопоставления объектов по умолчанию, предоставленного весенней загрузкой, два работают с jdk-10.0.1

Учитывая JSON:

{"a":"test"} 

и задан класс вроде:

public class ExampleValue {

    private final String a;

    private ExampleValue() {
        this.a = null;
    }

    public String getA() {
        return this.a;
    }
}

Десериализация (на удивление, по крайней мере для меня) работает.

В то время как это не так:

public class ExampleValue {

    private final String a;

    private ExampleValue(final String  a) {
        this.a = a;
    }

    public String getA() {
        return this.a;
    }
}

И это делает:

public class ExampleValue {

    private final String a;

    @java.beans.ConstructorProperties({"a"})
    private ExampleValue(final String a) {
        this.a = a;
    }

    public String getA() {
        return this.a;
    }
}

Я предполагаю, что единственный способ, которым может работать первый пример, — это использовать отражение для установки значения конечного поля (что, я полагаю, он делает с помощью java.lang.reflect.AccessibleObject.setAccessible(true).

Вопрос 1: прав ли я, что в данном случае Джексон работает именно так? Я предполагаю, что это может привести к сбою под управлением менеджера безопасности, который не разрешает эту операцию?

Поэтому моим личным предпочтением был бы последний пример кода выше, так как он требует меньше «магии» и работает под управлением менеджера безопасности. Тем не менее, я был немного сбит с толку различными темами, которые я нашел о Lombok и генерации конструктора, которые раньше генерировали по умолчанию @java.beans.ConstructorProperties(...), но затем изменили значение по умолчанию, чтобы больше не делать этого, и теперь позволяют настроить его по желанию, используя lombok.anyConstructor.addConstructorProperties=true

Некоторые люди (в том числе в ломбокских примечаниях к выпуску для v1.16.20) предлагают следующее:

Oracle более или менее нарушила эту аннотацию с выпуском JDK9, что потребовало этого критического изменения.

но я не совсем понимаю, что под этим подразумевается, что сломал Oracle? Для меня, использующего JDK 10 с jackson 2.9.6, все работает нормально.

Вопрос 2: Кто-нибудь может пролить свет на то, как эта аннотация была нарушена в JDK 9 и почему ломбок теперь считает нежелательным генерировать эту аннотацию по умолчанию.


person David    schedule 26.07.2018    source источник


Ответы (1)


Ответ 1: именно так это и работает (к моему удивлению). Согласно документации Джексона по функциям Mapper, свойства INFER_PROPERTY_MUTATORS, ALLOW_FINAL_FIELDS_AS_MUTATORS, и CAN_OVERRIDE_ACCESS_MODIFIERS по умолчанию все равно true. Следовательно, в вашем первом примере Джексон

  • создает экземпляр с помощью приватного конструктора с помощью AccessibleObject#setAccessible (CAN_OVERRIDE_ACCESS_MODIFIERS),
  • обнаруживает полностью доступный метод получения для (закрытого) поля и рассматривает это поле как изменяемое свойство (INFER_PROPERTY_MUTATORS),
  • игнорирует final в поле из-за ALLOW_FINAL_FIELDS_AS_MUTATORS и
  • получает доступ к этому полю, используя AccessibleObject#setAccessible (CAN_OVERRIDE_ACCESS_MODIFIERS).

Однако я согласен с тем, что на это не следует полагаться, потому что, как вы сказали, менеджер по безопасности может запретить это, или значения по умолчанию Джексона могут измениться. Кроме того, мне это кажется «неправильным», так как я ожидаю, что этот класс будет неизменяемым, а поле - неустановленным.

Пример 2 не работает, потому что Джексон не находит пригодный для использования конструктор (поскольку он не может сопоставить имена полей с именами параметров единственного существующего конструктора, поскольку эти имена отсутствуют во время выполнения). @java.beans.ConstructorProperties в вашем третьем примере обходит эту проблему, поскольку Джексон явно ищет эту аннотацию во время выполнения.

Ответ 2: Моя интерпретация такова, что @java.beans.ConstructorProperties на самом деле не сломан, но просто нельзя предположить, что он больше присутствует в Java 9+. Это связано с его принадлежностью к модулю java.desktop (см., например, эту тему для обсуждения этой темы). Поскольку модульные Java-приложения могут иметь путь к модулю без этого модуля, ломбок нарушит работу таких приложений, если будет генерировать эту аннотацию по умолчанию. (Кроме того, эта аннотация обычно недоступна в Android SDK.)

Таким образом, если у вас есть немодульное приложение или модульное приложение с java.desktop в пути к модулю, совершенно нормально разрешить ломбоку генерировать аннотацию, установив lombok.anyConstructor.addConstructorProperties=true, или добавить аннотацию вручную, если вы не используете ломбок.

person Jan Rieke    schedule 29.07.2018