Джексон десериализация расширенного класса Ломбок: почему это работает и почему не работает? - PullRequest
0 голосов
/ 08 октября 2018

Предыстория: я обнаружил «недействительный» код в проекте Spring-Admin: «Невозможно создать экземпляр регистрации (не существует создателей, таких как конструкция по умолчанию)».Поэтому я написал собственный десериализатор и доложил о проблеме.Но отчет был отклонен, так как он якобы работает.И после повторного тестирования это похоже на работу сейчас.Не имеет смысла.Поэтому я хотел бы знать, , почему этот код работает.

Но здесь есть одна загвоздка.Когда я написал аналогичный тестовый класс, он не работает в моем проекте.Даже когда я буквально беру код «ныне работающего» класса регистрации и пробую его в собственном проекте, это просто не десериализуется.И затем, с практически идентичным классом, это работает.Это не имеет никакого смысла.

https://github.com/codecentric/spring-boot-admin/blob/master/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/domain/values/Registration.java

Следующий пост объясняет, как работает комбо lombok-jackson, но здесь он не работает.Я совершенно сбит с толку, это невероятно нелепая ситуация, когда (ненужное) упрощение создает превосходную сложность.Но я хотел бы понять это, так как я могу снова учесть эту ситуацию в будущем.

Сбой десериализации Джексона из-за не стандартного конструктора, созданного lombok

Такчтобы иметь что-то простое в работе: здесь у нас есть хороший и работающий чистый Джексон:

public class TestTO_pureJackson {
    private final String a;
    private final String b;

    @JsonCreator
    private TestTO_pureJackson(@JsonProperty("a") String a, @JsonProperty("b") String b) {
        this.a = a;
        this.b = b;
    }
}

и здесь у нас нет рабочего эквивалента в ломбках (даже если я удаляю одно поле, так что это «то же самое» для последнего примера):

@lombok.Data
public class TestTO {
    private final String a;
    private final String b;

    @lombok.Builder(builderClassName = "Builder")
    private TestTO(String a, String b) {
        this.a = a;
        this.b = b;
    }

    public static TestTO.Builder create(String a) {
        return builder().a(a);
    }
}

и мы пытаемся десериализовать:

{"a": "a", "b": "b"}

Может кто-нибудь понять магию под капотом и помочь мне понять, что здесь не так?

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.2</version>
  <scope>provided</scope>
</dependency>

И чтобы сделать это еще более нелепым (вы действительно видите какую-либо существенную разницу с TestTO ???), работает следующий код:

@lombok.Data
public class Pair {
    private final String left;
    private final String right;

    @lombok.Builder(builderClassName = "Builder")
    private Pair(String pairId) {
        left = pairId.substring(0, 3).toUpperCase(Locale.US);
        right = pairId.substring(3).toUpperCase(Locale.US);
    }
}

и метод main:

public class PairTest {

    public static final String DATA = "[\"btcusd\",\"ltcusd\",\"ltcbtc\"]";

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Pair[] pairs = objectMapper.readValue(DATA, Pair[].class);

        for (Pair pair : pairs) {
            System.out.println(pair);
        }
    }
}

Кто-нибудь может понять, почему два почти одинаковых класса TO ведут себя по-разному?

1 Ответ

0 голосов
/ 09 октября 2018

TestTO не работает, потому что Джексон не может использовать конструктор.Он не может использовать конструктор с двумя аргументами, потому что он не знает, какое поле JSON должно использоваться для какого аргумента (поскольку имена аргументов удаляются во время компиляции).Для конструкторов, сгенерированных lombok, вы можете обойти это, посоветовав Lombok сгенерировать аннотацию @ConstructorProperties.Просто добавьте

lombok.anyConstructor.addConstructorProperties=true

к вашему lombok.config.В вашем случае с ручным конструктором вы также можете просто добавить @JsonProperty s.
(обратите внимание, что Джексон не использует автоматически компоновщики; вы должны явно указать Джексону, что с @JsonDeserialize и @JsonPOJOBuilder.)

TestTO_pureJackson работает, потому что @JsonProperty доступен во время выполнения и используется Джексоном для определения сопоставления.

Pair работает, потому что есть полезный конструктор: Джексону не нужноугадайте, какой параметр принадлежит какому полю, потому что есть только один.Обратите внимание, что это работает только для конструкторов с одним аргументом String, int, long или boolean.
Lombok не генерирует какой-либо дополнительный конструктор (здесь: конструктор two-args)) если он уже есть (см. документацию @Data), так что это единственный конструктор в классе.

...