Лучший способ изменить константы в процессе сборки Java - PullRequest
5 голосов
/ 31 декабря 2008

Я унаследовал приложение Java (сервлеты), которое работает под управлением Tomcat. По историческим причинам в коде есть разные варианты «внешнего вида», основанные на том, где будет развернуто приложение (по сути, вопрос брендинга).

Существует несколько констант, управляющих этим процессом брендинга, которые имеют разные функции и не должны быть сжаты в одну константу (например, BRAND, MULTI-LANGUAGE, плюс расположение значков и таблиц стилей CSS и т. Д.).

В настоящее время команда разработчиков должна вручную изменить константы (они как минимум локализованы в одном классе данных и хорошо документированы), а затем перекомпилировать приложение с помощью ANT.

Как лучше всего автоматизировать этот процесс, если использовать хотя бы Ant 1.8 и Java 6.x?

Я знаю, что не было хороших решений с использованием аргументов компилятора (как можно было бы сделать в C или C ++), и я полагаюсь на какой-то «лучший способ» редактировать либо исходный файл, содержащий константы, либо помещать их в другой файл и обменять их с помощью процесса сборки муравья. Я хотел бы получить результат, который бы работал, используя что-то вроде "ant build brand-x", где изменение бренда изменило бы полученную сборку.

Спасибо

-Ричард

Ответы [ 6 ]

9 голосов
/ 31 декабря 2008

Поместите ваши значения в файл свойств, скажем «myapp.properties», а затем загрузите их в ваши константы из пути к классам при запуске (см. Ниже, как это вписывается в процесс сборки):

public class Constants
{
    private static final Properties props = new Properties();
    public static final String MY_CONSTANT;

    static
    {
        InputStream input = Constants.class.getResourceAsStream("/myapp.properties");
        if(input != null)
        {
           try
           {
              properties.load(input);
           }
           catch(IOException e)
           {
              // TODO log error
           }
        }

        // Initialize constants (dont' forget defaults)
        MY_CONSTANT = properties.getProperty("constant", "default");
        // .. other constants ...
    }
}

Теперь создайте отдельный файл свойств для каждого бренда. Передайте его имя в ANT через -D или build.properties и скопируйте файл в каталог сборки прямо перед тем, как его собрать (или обработать).

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

2 голосов
/ 31 декабря 2008

Используйте задачу замены в Ant, чтобы изменить значения.

1 голос
/ 02 января 2009

У меня есть решение, которое работает по мере необходимости для этой конкретной ситуации. Я использовал задачу замены Ant вместе с «сохраненной» версией константного класса:

<target name="one" description="constant substitution #1">
  <delete file="./tme3/MyConst.java" />
  <copy file="./save/MyConst.java" tofile="./tme3/MyConst.java" />
  <replace file="./tme3/MyConst.java" token="@BRANDING@" value="ONE_BRAND"/>
  <replace file="./tme3/MyConst.java" token="@STYLESHEET@"
           value="../stylesheet/onebrand.css"/>
  <replace file="./tme3/MyConst.java" token="@FAVICON@" value="../images/onebrand.ico"/>
  <replace file="./tme3/MyConst.java" token="@SHOW_LANGUAGES@" value="false"/>
</target>

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

Спасибо всем за отличные ответы.

1 голос
/ 31 декабря 2008

Я предпочитаю использовать муравьиный фильтр expandproperties вместо задачи замены. При выполнении задачи замены файл компоновки имеет тенденцию увеличиваться в основном для токенизации. Функция расширения свойств позволяет встраивать свойства муравья непосредственно в текст.

<copy file="from" tofile="to">
  <filterchain>
    <expandproperties />
  </filterchain>
</copy>
1 голос
/ 31 декабря 2008

Существует также «пружинный» способ, который заключается в использовании файла свойств, и бина, который извлекает значение из свойств и внедряет их в классы, которые в них нуждаются, например ::

<bean id="propertyPlaceholder"  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:configuration.properties" />
</bean>

и затем вы можете ввести свойства с "муравьиным" синтаксисом:

<bean id="connectionPool"  class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
    <property name="databaseName" value="mydb" />
    <property name="url" value="${db.url}" />
    ...

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

public class Foo {
 public static final int SOME_CONSTANT=1;
..
}

public class Bar {
  ...
   int x=5+Foo.SOME_CONSTANT;
  ...
}

Если вы затем измените SOME_CONSTANT в Foo на 2, но не перекомпилируете Bar, Bar сохранит значение 1 для SOME_CONSTANT, так как статические финалы скомпилированы (поскольку компилятор видит, что ему не нужно вычислять их снова).

0 голосов
/ 31 декабря 2008

Используйте Ant файлы свойств и создайте с "-Dbrand = X".

...