使用Ant模拟Maven2过滤机制

5
我有一个属性文件,假设它叫做my-file.properties。 除此之外,我还有几个应用程序的配置文件,其中一些信息必须根据my-file.properties文件的内容填写。
my-file.properties:
application.version=1.0
application.build=42
user.name=foo
user.password=bar

因此,在我的配置文件中,我会找到一些${application.version}${user.name}等,它们将被替换为在属性文件中获取的值...
当我使用Maven2构建我的应用程序时,我只需要指定属性文件并说我的资源文件已被过滤(如这个答案中回答另一个问题)。然而,我需要仅使用Ant实现相同的功能。
我看到Ant提供了一个过滤任务。但是,它强制我在我的配置文件中使用模式@property.key@(即@user.name@而不是#{user.name}),这在我的情况下是不可接受的。
我该如何解决我的问题?
4个回答

20

我认为expandproperties是你正在寻找的东西。它的作用与Maven2的资源过滤器类似。


输入

例如,如果您有一个src目录(其中包含许多文件):

<link href="${css.files.remote}/css1.css"/>

src/test.txt


处理过程

在我的 ANT 构建文件中,我们有这个:

<project default="default">
   <!-- The remote location of any CSS files -->
   <property name="css.files.remote" value="/css/theCSSFiles" />     
   ...
   <target name="ExpandPropertiesTest">

      <mkdir dir="./filtered"/>

      <copy todir="./filtered">
         <filterchain>
            <expandproperties/>
         </filterchain>     

         <fileset dir="./src" />
      </copy>
   </target>
</project>

build.xml


输出

*当您运行 ExpandPropertiesTest 目标时,您将在 filtered 目录中获得以下内容:*

    <link href="/css/theCSSFiles/css1.css"/>

filtered/test.txt


@romaintaz 当然没问题!希望这样能简化构建文件。我知道它确实简化了我的构建过程。 - leeand00

3
您可以定义一个自定义FilterReader。因此,您有几个选择:
  1. 扩展/复制org.apache.tools.ant.filters.ReplaceTokens类,并定义一个Map属性,该属性引用另一个包含所有替换内容的属性文件。这仍然有点繁琐,因为您必须定义所有替换内容。
  2. 扩展/复制org.apache.tools.ant.filters.ReplaceTokens类,使用额外的处理来仅将匹配的标记替换为带有正确装饰的版本。当然,您必须非常小心地使用此类型,因为它将匹配任何具有开始和结束标记的内容。
因此,在ReplaceTokens的read()方法中,替换:
final String replaceWith = (String) hash.get(key.toString());

通过调用getReplacement()方法:
...
final String replaceWith = getReplacement(key.toString);
...

private String getReplacement(String key) {
    //first check if we have a replacement defined
    if(has.containsKey(key)) {
        return (String)hash.get(key);
    }

    //now use our built in rule, use a StringBuilder if you want to be tidy
    return "$" + key + "}";
}

要使用这个功能,您需要确保您的类已经打包,并且在Ant路径中,然后修改您的过滤器:

<filterreader classname="my.custom.filters.ReplaceTokens">
    <!-- Define the begin and end tokens -->
    <param type="tokenchar" name="begintoken" value="$"/>
    <param type="tokenchar" name="endtoken" value="}"/>
    <!--Can still define explicit tokens, any not
    defined explicitly will be replaced by the generic rule -->
</filterreader>

2

通过Mnementh的解决方案得到灵感,一种可怕的方法使这个工作起来的代码如下:

    <!-- Read the property file -->
    <property file="my-file.properties"/>
    <copy todir="${dist-files}" overwrite="true">
        <fileset dir="${src-files}">
            <include name="*.properties"/>
        </fileset>
        <filterchain>
            <filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
                <!-- Define the begin and end tokens -->
                <param type="tokenchar" name="begintoken" value="$"/>
                <param type="tokenchar" name="endtoken" value="}"/>
                <!-- Define one token per entry in the my-file.properties. Arggh -->
                <param type="token" name="{application.version" value="${application.version}"/>
                <param type="token" name="{user.name" value="${user.name}"/>
                ...
            </filterreader>
        </filterchain>
    </copy>

解释:

我正在使用ReplaceTokens读取器查找所有$...}模式。我无法搜索${...}模式,因为begintoken是一个字符而不是字符串。然后,我设置了以{开头的令牌列表(即我看到{user.name而不是user.name)。希望我只有大约20行在my-file.properties文件中,所以我需要在我的Ant文件中定义“仅”20个令牌...

是否有任何简单而愚蠢的解决方案来解决这个简单而愚蠢的问题?


2

Ant知道一个名为Filterchains的概念,在这里非常有用。使用ReplaceTokens-filter,并将begintoken和endtoken指定为空(通常是“@”)。那应该就可以了。


1
这个解决方案似乎不起作用,至少在我的尝试中是如此。begintoken和endtoken不能为空。我也不能将begintoken设置为"${",因为它被视为语法错误... - Romain Linsolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接