Подтвердить что ты не робот

Как избежать предупреждений об устаревании, когда @SuppressWarnings ( "deprecation" ) не работает?

У нас есть проект Java. Мы включаем флаги -Xlint (включить предупреждения) и -Werror (лечить предупреждение как ошибку) для javac, чтобы убедиться, что наш код не содержит предупреждений. Недавно мы решили отказаться от класса. Проблема в том, что в некоторых случаях @SuppressWarnings("deprecation") вообще не будет подавлять предупреждение об утомлении, что приведет к сбою сборки. Ниже приведен список вариантов использования, на которые я столкнулся:

  • Импортировано в другие классы, не устаревшие.
  • Импортировано в другие устаревшие классы.
  • Родительский класс.
  • Введите параметр. Например

    @SuppressWarnings("deprecation")
    public class Foo extends Bar<DeprecatedClass>
    { ... }
    

    Однако у этого нет предупреждения даже без подавления:

    @Deprecated
    public class DeprecatedClass extends Bar<DeprecatedClass>
    { ... }
    

AFAIK, нет синтаксиса для аннотирования импорта, поэтому для случаев 1 и 2 наше решение должно либо импортировать *, либо не импортировать. В случае 3 и 4, как Java 6, так и 7 не подавляют предупреждение. Java 8 будет корректно подавлять его (возможно, ошибка исправлена). Пока нет решения для этого.

К сожалению, на данный момент мы должны поддерживать Java 6, 7 и 8. Есть ли способ справиться с этой проблемой? Это дорожный блок для нашей эволюции Java API.

ДОПОЛНЕНИЕ

Многие спрашивают, почему мы все еще используем устаревший класс в нашей собственной базе кода. Причина в том, что проект представляет собой библиотеку, поддерживающую множество разных клиентов. При внедрении нового API замены мы должны сначала отказаться от нашего старого API, сохранить его в нашей базе кода, дождаться, пока все клиенты перейдут, а затем удалите его. Существует три распространенных случая использования:

  • Мы осуждаем класс Foo и Bar, где Foo продолжается Bar. Это вопрос 2 и 3 в моем вопросе.
  • Мы осуждаем класс Foo и Bar, где Foo продолжается Collection<Bar>. Это случай 2 и 4.
  • Мы должны сохранить все тестовые коды для классов Foo и Bar. Код теста импортирует эти классы. В этом случае 1.

Зачем держать тест? Не забывайте, что если обнаружена серьезная ошибка (например, утечка памяти, проблема безопасности), и клиенты не могут легко перейти на новую версию, нам все равно нужно предоставить исправление ошибок для старого API. И все изменения должны быть протестированы.

Я считаю, что наша ситуация должна быть довольно распространена в разработке программного обеспечения и разработке API. Удивительно, что для такого исправления Java потребовалось много времени (до Java 8).

4b9b3361

Ответ 1

Мне жаль, что у меня нет решения проблемы, с которой вы столкнулись, хотя, как вы заметили, прогресс был достигнут. Мы пытались избавиться от всех предупреждений компиляции Java в самом JDK, и это был долгий, сложный процесс. Во время разработки JDK 8 в 2011 году я помог начать работу по очистке предупреждений, а позже сопроводил беседу JavaOne (слайды и аудио) по этому вопросу.

Совсем недавно мой коллега Джо Дарси продолжил работу по очистке предупреждений и работал с различными категориями предупреждений и наконец-то получил предупреждения об отставке. Как вы отметили, в обработчике компилятора были поданы предупреждения о подавлении предупреждений об отставке, таких как JDK-6480588, который был исправлен в JDK 8. К сожалению, в JDK 8 все еще невозможно подавить предупреждения об импорте устаревших предметов. Эта ошибка, JDK-8032211, была исправлена ​​совсем недавно в нашей линии разработки JDK 9. Фактически, мы все еще настраиваем обработку аннотации @Deprecated. Например, ошибка JDK-6481080 поясняет, что попытка использовать @Deprecated в файле package-info.java фактически не обесценивает пакет; эта ошибка была исправлена ​​только на прошлой неделе. И есть больше работы, которая должна быть сделана, но она несколько спекулятивная на данный момент.

JDK сталкивается с аналогичными проблемами с вашими, поскольку мы должны поддерживать устаревшие API для клиентов, которые все еще используют их. Но поскольку мы используем и внедряем такие API внутри, у нас есть много предупреждений об устаревании для подавления. На момент написания этой статьи в нашей линии разработки JDK 9 мы все еще не смогли скомпилировать систему без предупреждений об устаревании. В результате опции javac для предупреждений lint остаются:

-Xlint:all,-deprecation

Вам, вероятно, придется отключить предупреждения об устаревании и в вашей компиляции, особенно если вы все еще строите JDK 6. На данный момент я не вижу пути вокруг.

Последнее замечание в одном из ваших случаев устаревания:

@Deprecated
public class DeprecatedClass extends Bar<DeprecatedClass> { ... }

Это не выводит предупреждение об устаревании и не должно. Спецификация языка Java, раздел 9.6.4.6, указывает, что предупреждения об устаревании не выдаются, если использование устаревшего объекта находится внутри объекта, который сам по себе осуждается.

Ответ 2

Рассмотрите возможность использования -Xmaxwarns, вы можете контролировать, сколько предупреждений перед остановкой.

Или попробуйте собрать количество предупреждений и не выполнить процесс интеграции, а не компилировать.

Например: https://issues.apache.org/jira/browse/HADOOP-11252. Каждый код, переданный в проект hadoop, должен передать автоматическое CI и дать -1 для увеличения количества предупреждений.

Ответ 3

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

Если вам нужно использовать свой класс MySuperDeprecatedUtil в каком-то другом классе, вы должны пометить класс, в котором вы его используете, как @Deprecated - каждый класс, который использует устаревший код, должен быть либо устаревшим, либо выдавать предупреждения компиляции, либо должен быть удален, или должен прекратить использование устаревшего кода.

Если вы не можете перестать использовать свой класс - может быть, слишком рано его осуждать?

В моей практике, когда я хочу отказаться от некоторого класса, я создаю класс замены, например. MySuperFreshUtil. Переключайте все классы с помощью MySuperDeprecatedUtil на MySuperFresh, используя, где это возможно, интерфейсы (если это невозможно), используйте FQCN и метод меток как устаревший). Отметьте MySuperDeprecatedUtil как @Deprecated и добавьте комментарий, какой класс и как следует использовать вместо этого. Затем я фиксирую эти изменения в одном списке изменений.