Несовместимые изменения в дженериках в Java 21

Кто-нибудь еще заметил изменения в дженериках Java в Java 21?

Мы используем Jdbi для доступа к базе данных, и при обновлении до Java 21 что-то идет не так, потому что универсальный тип больше не может быть определен.

Во время отладки я заметил, что условие

      java.lang.reflect.Type type = ...
if (type instanceof Class) {..}

гдеtypeэто интерфейс, который оценивается какfalseв Java 17, но естьtrueв Яве 21.

Некоторые из дженериков Jdbi зависят от библиотеки Geantyref.Статический метод GenericTypeReflector.getTypeParameter(..) возвращает универсальный тип в Java 17, но возвращаетnullв Яве 21.

Нигде в примечаниях к выпуску или других объявлениях я не могу найти ничего о том, что в Java 21 что-то изменилось в дженериках. И о том, что есть обратно совместимые критические изменения.

Я предполагаю, что некоторые внутренние компоненты могли измениться из-за отражения записи (JEP-440) или сопоставления шаблонов для переключателя (JEP-441), но эти функции я уже использую в качестве функций 17-предварительного просмотра без каких-либо проблем.

Кто-нибудь знает, что вызвало эти изменения и почему?

Обновление от 17 ноября 2023 г.

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

      record Person(Optional<String> name, Optional<Integer> age) {}

общие типыStringиIntegerтеряются в конструкторе Person по умолчанию. Конструктор по умолчанию, созданный Java, можно изменить, явно добавив канонический конструктор со всеми свойствами записи:

      record Person(Optional<String> name, Optional<Integer> age) {
  @JdbiConstructor
  public Person(Optional<String> aName, Integer anAge) {
    this(aName, anAge);
  }
}

Добавив@JdbiConstructorаннотация (которую Jdbi всегда требует для записи) Jdbi указывает, какой конструктор использовать. Поскольку этот конструктор теперь явно определяет типы аргументов, включая общий тип, утилита отражения может определить тип, и я заставил ее работать с Java 21.

Последние два часа я пытался создать минимальный тестовый пример, чтобы убедиться, что универсальный тип потерян в аргументах конструктора записи по умолчанию, но мне не удалось воспроизвести его в тесте. Несмотря на то, что в нашем приложении он постоянно терпит неудачу. Я сравнивал аргументы типов при одновременной отладке приложения и теста. Значения и типы аргументов выглядят одинаково, но тест в Java 21 по-прежнему проходит успешно.

Я пока оставляю тест, так как мне нужно продолжить работу, и теперь у меня есть рабочий обходной путь, добавив дополнительный конструктор. Я постараюсь вернуться к этому позже. Оно должно быть воспроизводимым в простом тесте.

Обновление от 20 ноября 2023 г.

Спасибо Хольгеру за создание небольшого тестового примера, доказывающего проблему.

В обновлении от 17 ноября у меня было две ошибки:

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

Я соответствующим образом обновил обновление от 17 ноября. Спасибо, что указали на эти ошибки.

Я отправил отчет об ошибке с идентификатором9076247который сейчас находится на рассмотрении.

Обновление от 22 ноября 2023 г.

Сообщенная ошибка была оценена, ей присвоен идентификатор ошибки: JDK-8320575, и теперь она доступна по URL-адресу JDK-8320575.

0 ответов

Другие вопросы по тегам