какие классы мне нужно скомпилировать, когда класс изменился? - PullRequest
1 голос
/ 25 декабря 2011

У меня есть инструмент, который мы написали для создания патчей для нашего приложения. Он проверяет в scm, какие классы были изменены, и компилирует их, используя javac.
Затем мы добавляем созданную банку в путь к классам. В прошлом мы обнаружили, что есть проблема с этим: Если я изменил тип возврата метода в классе A, и класс B использует этот метод, то сигнатура класса A изменилась, и мы получили NoSuchMethodError, когда класс B вызвал этот метод.
Тем не менее, теперь у меня есть другой случай, когда статические переменные класса были изменены, и я получаю: java.lang.NoClassDefFoundError: Could not initialize class.
Вы знаете, что вызывает это?
Есть ли способ сказать, какие классы мне нужно скомпилировать, когда класс был изменен?

Ответы [ 3 ]

4 голосов
/ 25 декабря 2011

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

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

Это лучше, потому что

  • вам не нужно понимать все последствия изменения константы, метода или класса.
  • если вы изменяете что-то непредвиденное, например, форматирование или комментарии, обновлять файл не нужно.
  • Вы можете быть уверены, что применение патча точно такое же и дает полный дистрибутив.
3 голосов
/ 25 декабря 2011

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

Допустим, у вас есть класс A с некоторыми public static final полями примитивного типа или String, значения которых можно определить во время компиляции.

public class A {
   public static final String GREETING = "Hello";
   ...
}

Тогда, если другой класс B обращается к этому полю, компилятор подставляет константу, т. Е. Заменяет ссылку A.GREETING ее значением "Hello". Информация о том, откуда взято постоянное значение, не сохраняется.

Теперь приходит проблема - если вы измените значение GREETING на допустимое "Hi" и перекомпилируете только класс A , встроенное значение в классе B останется без изменений, пока вы его не перекомпилируете. Поэтому обычно лучше перестроить все приложение с нуля , как уже отмечали другие.

Хорошая статья, обсуждающая эту проблему: http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html

Некоторые связанные вопросы SO:

Гарантируется ли Java встроенные строковые константы, если они могут быть определены во время компиляции

Все ли константы времени компиляции встроены?

1 голос
/ 25 декабря 2011

Если вы измените сигнатуру класса A, вам не нужно просто перекомпилировать все классы, которые вызывают этот класс.Вы должны изменить реализацию этих классов.

Например, если у вас в классе A был метод foo(), который был вызван классом B, а теперь вы изменили его имя на bar(), вы должны изменить исходный кодкласса B. В противном случае вы получите NoSuchMethodError.

Если, однако, вы не изменяете интерфейсы, а просто изменяете внутреннюю реализацию класса A, вам не нужно ничего перекомпилировать, кроме самого этого класса.Вам просто нужно создать соответствующий путь к классу при компиляции.Путь к классу должен включать прямые зависимости класса A и зависимости зависимостей.Он не должен содержать зависимости 3-го уровня (т.е. зависимости зависимостей зависимостей).Но ИМХО самый простой способ иметь дело с путем к классу при компиляции патча - просто предоставить полный путь к классу существующего приложения.

...