
ant 扩展官方文档:https://ant.apache.org/manual/develop.html
Writing Your Own Task
编写你自己的任务
1. 创建一个XXTask类
创建一个Java类继承org.apache.tools.ant.Task ,实际上不继承也可以,定义一个 execute() 方法就可以,例如下面的例子:
public class MyTask {
public void execute() {
System.out.println("MyTask");
}
}
配置到插件中测试:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<id>obfuscate</id>
<configuration>
<tasks>
<property name="runtime_classpath" refid="maven.runtime.classpath"/>
<taskdef name="my-task" classname="MyTask" classpath="${runtime_classpath}"/>
<my-task/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
后续示例只提供
<tasks>中的内容。
可以在示例的 module-yguard 中的 pom.xml 中测试。
执行 package 打包,部分输出日志如下:
[INFO] --- maven-antrun-plugin:1.8:run (obfuscate) @ module-yguard ---
[WARNING] Parameter tasks is deprecated, use target instead
[INFO] Executing tasks
main:
MyTask
[INFO] Executed tasks
接下来继承 org.apache.tools.ant.Task 试试:
public class MyTask extends org.apache.tools.ant.Task {
public void execute() {
System.out.println("MyTask, name: " + getTaskName());
}
}
执行输出的部分日志如下:
[INFO] --- maven-antrun-plugin:1.8:run (obfuscate) @ module-yguard ---
[WARNING] Parameter tasks is deprecated, use target instead
[INFO] Executing tasks
main:
MyTask, name: my-task
[INFO] Executed tasks
警告中建议将 tasks 改为 target,修改试试:
<target>
<property name="runtime_classpath" refid="maven.runtime.classpath"/>
<taskdef name="my-task" classname="MyTask" classpath="${runtime_classpath}"/>
<my-task/>
</target>
再次运行就没有警告信息了。
2. 给 <my-task> 添加属性
给 <my-task> 添加属性,例如:
<my-task path="${user.dir}"/>
为了能接收这个属性值,需要在 MyTask 添加对应的 setter 方法, setter 方法必须是采用单个参数的 public void 方法,修改如下:
import java.io.File;
public class MyTask extends org.apache.tools.ant.Task {
private File path;
public void setPath(File path)
{
this.path = path;
}
public void execute() {
System.out.println("MyTask, name: " + getTaskName() + ", path: " + path);
}
}
执行测试输出内容如下:
[INFO] --- maven-antrun-plugin:1.8:run (obfuscate) @ module-yguard ---
[INFO] Executing tasks
main:
MyTask, name: my-task, path: E:\GitHub\yguard-modules-parent
[INFO] Executed tasks
可以看到 Ant 自动把参数转换为 File 类型了,Ant 支持的转换规则如下:
- 最常见的
java.lang.String类型; boolean类型,支持设置为true,yes,on,其他值则为false。这部分的逻辑在Project类中,代码如下:public static boolean toBoolean(final String s) { return ("on".equalsIgnoreCase(s) || "true".equalsIgnoreCase(s) || "yes".equalsIgnoreCase(s)); }char或java.lang.Character,将传递指定值的第一个字符;- 其他基本类型(
int,short,long,float,double,byte); java.io.File,Ant首先会判断构建文件中给出的值是否代表绝对路径名。如果不是,Ant 会将该值解释为相对于项目的 basedir 的路径名;org.apache.tools.ant.types.Resource,Ant 会将字符串解析为上面的java.io.File,然后作为org.apache.tools.ant.types.resources.FileResource传入;org.apache.tools.ant.types.Path,Ant 将标记化构建文件中指定的值,接受 : 和 ;作为路径分隔符。相对路径名将被解释为相对于项目的 basedir;java.lang.Class,Ant 会将构建文件中给出的值解释为 Java 类名,并从系统类加载器加载指定的类;org.apache.tools.ant.types.EnumeratedAttribute的子类,会调用子类的setValue方法,设置的值必须是抽象方法String[] getValues()包含的值,通常用于指定固定选项。- 枚举值,会和枚举的
name进行匹配。
3. 给 <my-task> 添加文本数据
添加文本数据示例:
<my-task path="${user.dir}" enable="hello">中间的文本</my-task>
很显然这种方式和在<my-task>添加子元素是冲突的,这种情况下需要添加 public void addText(String) 方法,代码如下:
import java.io.File;
public class MyTask extends org.apache.tools.ant.Task {
private File path;
private boolean enable;
private String text;
public void setEnable(boolean enable)
{
this.enable = enable;
}
public void setPath(File path)
{
this.path = path;
}
public void addText(String text) {
this.text = text;
}
public void execute() {
System.out.println("MyTask, name: " + getTaskName() + ", path: " + path + ", enable: " + enable + ", text: " + text);
}
}
测试输出结果:
[INFO] --- maven-antrun-plugin:1.8:run (obfuscate) @ module-yguard ---
[INFO] Executing tasks
main:
MyTask, name: my-task, path: E:\GitHub\yguard-modules-parent, enable: false, text: 中间的文本
[INFO] Executed tasks
4. 给 <my-task> 添加嵌套元素
例如前面提到的 <patternset> 元素:
<my-task>
<patternset>
<include name="org.example.c."/>
<exclude name="org.example.c.util.FileUtil"/>
</patternset>
</my-task>
更新 MyTask 代码:
import org.apache.tools.ant.types.PatternSet;
import java.util.ArrayList;
import java.util.List;
public class MyTask extends org.apache.tools.ant.Task
{
/**
* The Pattern sets.
*/
private List<PatternSet> patternSets = new ArrayList(5);
public void addConfiguredPatternSet(PatternSet ps)
{
patternSets.add(ps);
}
public void execute()
{
patternSets.forEach(ps ->
{
String[] includes = ps.getIncludePatterns(getProject());
String[] excludes = ps.getExcludePatterns(getProject());
System.out.println("includes: " + String.join(", ", includes));
System.out.println("excludes: " + String.join(", ", excludes));
});
}
}
执行代码输出结果:
[INFO] --- maven-antrun-plugin:1.8:run (obfuscate) @ module-yguard ---
[INFO] Executing tasks
main:
includes: org.example.c.
excludes: org.example.c.util.FileUtil
[INFO] Executed tasks
对于每个嵌套元素,需要编写一个 create、add 或 addConfigured 方法。 create 方法必须是不带参数并返回 Object 类型的 public 方法。 create 方法的名称必须以 create 开头,后跟元素名称。 add(或 addConfigured)方法必须是一个 public void 方法,该方法采用带有无参数构造函数的 Object 类型的单个参数。 add (addConfigured) 方法的名称必须以 add ( addConfigured ) 开头,后跟元素名称。
也就是上面示例中,支持下面3种写法:
public PatternSet createPatternSet()
{
PatternSet ps = new PatternSet();
patternSets.add(ps);
return ps;
}
public void addPatternSet(PatternSet ps) {
patternSets.add(ps);
}
public void addConfiguredPatternSet(PatternSet ps)
{
patternSets.add(ps);
}
这3种写法不能同时存在,具体差异通过 debug 来查看。测试时注释另外两个方法。
4.1 createXxx 方法

这个方法会创建一个空的 PatternSet 对象,这个对象需要提前添加到 patternSets,否则后续无法获取该值。这里返回该对象后,这个对象会被赋值,在后续执行 execute 时是有值的。
当你嵌套的对象需要复杂的创建方式时,可以采用这种方式,这种方式适合初始化对象。
4.2 addXxx 方法

可以看到Ant自己实例化了一个PatternSet对象注入进来了,而且此时该对象是空的,还没有被赋值,这种情况下的参数(如这里的PatternSet)需要提供 public 无参数构造方法或将 Project 类作为参数的 public 单参数构造方法。
4.3 addConfiguredXxx

这个方法和上一个类似,但是这里会传入一个配置好的 PatternSet,如果你需要在配置好的对象上进行后续处理,可以使用这个方法,如果想在配置前处理,可以选择前两种方式。
4.4 不要同时使用这3种方法
同时存在时不一定会调用哪一个方法,当你方法中存在逻辑时,就无法保证处理一致。不会像你所想的,先调用 create 创建对象,再通过 add 初始化值,最后调用 addConfigured 方法进行后续处理。
了解这些内容后就可以扩展 Ant 任务了,下一节开始针对 yGuard 进行扩展。



















