Java ビルド プロセスで定数を変更する最良の方法
-
03-07-2019 - |
質問
Tomcat で実行される Java アプリケーション (サーブレット) を継承しました。歴史的な理由から、コードには、アプリケーションがデプロイされる場所 (本質的にはブランド化の問題) に基づいて、さまざまな「ルック アンド フィール」オプションがあります。
このブランド化プロセスを制御する定数がいくつかありますが、それらは異なる機能を持ち、単一の定数に圧縮すべきではありません (つまり、ブランド、多言語、さらにアイコンや CSS スタイル シートの位置など)。
現在、開発チームは定数を手動で変更し (少なくとも 1 つのデータ クラスにローカライズされ、十分に文書化されている)、ANT を使用してアプリケーションを再コンパイルする必要があります。
少なくとも Ant 1.8 と Java 6.x を前提として、このプロセスを自動化する最良の方法は何ですか?
(C や C++ でできるような) コンパイラ引数を使用した適切な解決策が存在しないことは承知しており、定数を含むソース ファイルを編集するか、定数を別のファイルに配置する「最良の方法」に傾いています。 Ant ビルド プロセスを使用してそれらを交換します。「ant build brand-x」のようなものを使用して、ブランドを変更すると結果のビルドが変わるような結果が得られるようにしたいと考えています。
ありがとう、
-リチャード
解決
Antのreplaceタスクを使用して値を変更します。
他のヒント
値をプロパティファイルに入力します(例:「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 ...
}
}
現在、ブランドごとに個別のプロパティファイルがあります。 -Dまたはbuild.propertiesを介してその名前をANTに渡し、jar(またはwar)する直前にファイルをビルドディレクトリにコピーします。
明らかに、上記のコードは機能しますが、クリーンアップして防弾にする方法はたくさんあります。
「春」もあります;方法、プロパティファイル、およびプロパティから値を取得し、それらを必要とするクラスにそれらを挿入するBeanを使用する方法です。例:
<bean id="propertyPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:configuration.properties" />
</bean>
その後、「ant-like」を使用してプロパティを注入できます。構文:
<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;
...
}
FooのSOME_CONSTANTを2に変更してもBarを再コンパイルしない場合、静的ファイナルがコンパイルされるため、BarはSOME_CONSTANTの値1を保持します(コンパイラーは計算する必要がないと判断するため)それらを再び)。
置換タスクではなく、antの expandproperties フィルターを使用することを好みます。置換タスクでは、ビルドファイルはほとんどトークン化される傾向があります。 expandpropertiesを使用すると、antプロパティをテキストに直接埋め込むことができます。
<copy file="from" tofile="to">
<filterchain>
<expandproperties />
</filterchain>
</copy>
この特定の状況で必要に応じて機能するソリューションがあります。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 つのセットがありますが、さらに多くのセットが予想されます。
素晴らしい返信をありがとうございました。
Ant プロパティファイルを使用し、&quot; -Dbrand =でビルドしますX&quot;。