Best way to alter constants in Java build process

末鹿安然 提交于 2019-12-06 02:56:45

问题


I have inherited a Java application (servlets) that runs under Tomcat. For historical reasons, the code has different "look and feel" options based on where the application will be deployed (essentially a matter of branding).

There are several constants that control this branding process, which have different functions and should not be compacted into a single constant (i.e. BRAND, MULTI-LANGUAGE, plus the locations of icons and css style sheets, etc.).

Currently the development team must manually change the constants (they are at least localized in one data class and well documented), then recompile the application using ANT.

What is the best way to automate this process assuming at least Ant 1.8 and Java 6.x?

I know that there have not been any good solutions using compiler arguments (like one could do in C or C++), and am leaning to some "best way" to edit either the source file containing the constants, or putting them into another file and swapping them out using the ant build process. I'd like to have a result that would work using something like "ant build brand-x" where changing the brand would change the resulting build.

Thanks,

-Richard


回答1:


Use the replace task in Ant to change the values.

  • Ant Replace



回答2:


Put your values into a properties file, say "myapp.properties" and then load them into your constants from the classpath at startup (see below for how this fits into the build process):

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 ...
    }
}

Now, have a separate properties file for each branding. Pass its name to ANT via -D or build.properties and copy the file to your build directory right before you jar (or war) it up.

Obviously, the code above will work, but there are many ways you can clean it up and make it bullet proof.




回答3:


There's also a "spring" way, which is to use a properties file, and a bean that pulls the value from the properties and injects them into the classes that need them, e.g.:

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

and then, you can inject properties with an "ant-like" syntax:

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

which probably would entail more rewriting than you'd like. If you're going to be changing constants on each compile, I'd watch out for this gotcha (if you're using static finals, that is).

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

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

If you then change SOME_CONSTANT in Foo to 2 but don't recompile Bar, Bar will retain the value of 1 for SOME_CONSTANT, as the static finals are compiled in (since the compiler sees that it shouldn't need to ever figure them out again).




回答4:


I prefer using ant's expandproperties filter instead of the replace task. With the replace task, the build file tends to grow to be mostly tokenization. expandproperties lets you embed ant properties directly in your text.

<copy file="from" tofile="to">
  <filterchain>
    <expandproperties />
  </filterchain>
</copy>



回答5:


I have a solution that works as needed for this particular situation. I've used the Ant replace task in conjunction with a "saved" version of the constant class:

<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>

I just make copies of this block and change the substitutions for the cases I need - in my particular case there are 3 sets now, but more expected.

Thanks one and all for the great replies.




回答6:


Use Ant property files, and build with "-Dbrand=X".



来源:https://stackoverflow.com/questions/403902/best-way-to-alter-constants-in-java-build-process

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!