基于JAXB的Ant自定义Task

官方Manual链接: http://ant.apache.org/manual/index.html

Ant、XSD、JAXB、XML的基本概念这里就不介绍,网上随便搜搜都有一大把,本文主要讲解利用XSD生成JAXB类来自定义Ant Task,自动完成XML的解析工作,提高开发效率。

开发工具采用Eclipse。

第一步,在Eclipse中创建Java项目,这里取名为WritingAntTaskDemo。

第二步,创建xsd文件,这里我在项目中jet.demo.xsd的包下创建了名为MyTaskConfig.xsd文件。

下面是该xsd的Source配置信息(design中的图形界面,这里就不截图了):

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/patternConfig"
<span style="white-space:pre">	</span>xmlns:tns="http://www.example.org/patternConfig" elementFormDefault="qualified">

    <complexType name="MyTaskConfig">
    <span style="white-space:pre">	</span><sequence>
    <span style="white-space:pre">		</span><element name="message" type="tns:Message" maxOccurs="unbounded"
    <span style="white-space:pre">			</span>minOccurs="0">
    <span style="white-space:pre">		</span></element>
    <span style="white-space:pre">		</span><element name="description" type="tns:Description"
    <span style="white-space:pre">			</span>maxOccurs="1" minOccurs="0">
    <span style="white-space:pre">		</span></element>
    <span style="white-space:pre">	</span></sequence>
    <span style="white-space:pre">	</span><attribute name="id" type="string"></attribute>
    </complexType>

    <element name="myTaskConfig" type="tns:MyTaskConfig"></element>

    <complexType name="Message">
    <span style="white-space:pre">	</span><attribute name="id" type="string"></attribute>
    <span style="white-space:pre">	</span><attribute name="content" type="string"></attribute>
    </complexType>
    
    <complexType name="Description">
    <span style="white-space:pre">	</span><attribute name="id" type="string"></attribute>
    <span style="white-space:pre">	</span><attribute name="content" type="string"></attribute>
    </complexType>

</schema>

根元素是myTaskConfig,myTaskConfig中有个一个id属性,有若干个个message子元素,message子元素中有两个属性,分别是id和content。myTaskConfig还有0个或者1个的description子元素,里面的属性跟message一样。

第三步,利用xsd生成JAXB类,先在工程中创建名为jet.demo.model的包,这里会用来存放生成的JAXB类。右键点击MyTaskConfig.xsd文件,选择Generate->JAXB Classes...。

选择WritingAntTaskDemo项目,在Package中选择jet.demo.model包,然后一直Next,最后Finish就行了,这个时候弹出一个警告框,如下图:

这里是提醒我们,生成的类文件将会覆盖已经存在的文件,问我们确不确定这么干,这里我们选择Yes,不然没法生成的。或者直接把选择框Do not show this message again勾上,一了百了,但是我不建议这么干,因为有时候误操作,会坏事。

接着,在jet.demo.model包中会生成所有在xsd中配置好的类文件,以下是console控制台的输出信息:

parsing a schema...

compiling a schema...

jet\demo\model\Description.java

jet\demo\model\Message.java

jet\demo\model\MyTaskConfig.java

jet\demo\model\ObjectFactory.java

jet\demo\model\package-info.java

Messge.java就是前面XSD中的Message子元素,MyTaskConfig就是前面XSD中的MyTaskConfig根元素。这里ObjectFactory.java以及package-info.java我们都用不着,这里也不过多介绍,想要了解的网友自己去看好了。

Message.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2016.04.12 at 10:14:00 AM CST
//

package jet.demo.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for Message complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * <complexType name="Message">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="content" type="{http://www.w3.org/2001/XMLSchema}string" />
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Message")
public class Message {

    @XmlAttribute(name = "id")
    protected String id;
    @XmlAttribute(name = "content")
    protected String content;

    /**
     * Gets the value of the id property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setId(String value) {
        this.id = value;
    }

    /**
     * Gets the value of the content property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getContent() {
        return content;
    }

    /**
     * Sets the value of the content property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setContent(String value) {
        this.content = value;
    }

}

在Ant  Manual中,Developing with Apache Ant章节里的Writing Tasks中有关于属性介绍:

It is very easy - for each attribute provide a public void set<attributename>(<type>newValue) method and Ant will do the rest via
reflection.

--------------------------------------------------------------------------------------------------------------------------------------------------------------

大概意思就是说,每个属性要提供一个set方法。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

Message子元素中只有两个属性,并且JAXB类中已经自动生成set和get方法,所以我们不需要任何修改,是不是很方便啊。

Description跟Message是一样的,这里就不复制了。

Writing Tasks中有关于子元素的介绍(http://ant.apache.org/manual/develop.html#nested-elements):

Now you have a class NestedElement that is supposed to be used for your nested <inner> elements, you have three options:

  1. public NestedElement createInner()
  2. public void addInner(NestedElement anInner)
  3. public void addConfiguredInner(NestedElement anInner)

What is the difference?

Option 1 makes the task create the instance of NestedElement, there are no restrictions on the type. For the options 2 and 3, Ant has to create an instance
of NestedInner before it can pass it to the task, this means, NestedInner must have a public no-arg constructor or a public one-arg constructor taking a Project class as a parameter. This is the only difference
between options 1 and 2.

The difference between 2 and 3 is what Ant has done to the object before it passes it to the method. addInner will receive an object directly after the
constructor has been called, while addConfiguredInner gets the object after the attributes and nested children for this new object have been handled.

What happens if you use more than one of the options? Only one of the methods will be called, but we don‘t know which, this depends on the implementation of your Java
virtual machine.

--------------------------------------------------------------------------------------------------------------------------------------------------------------

大概的意思就是说对于内嵌的元素,有三种选择方式,create方法,add方法,addConfigured方法。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

三种方法JAXB类中都没有,所以需要我们自己去添加,这里我选择add方法,这个方法最简单了....如下:

	// Added by hand, for the purpose of ant script running.
	public void addMessage(Message message) {
		List<Message> messageList = getMessage();
		messageList.add(message);
	}
	public void addDescription(Description description) {
		this.description = description;
	}
	// End of adding.

对于单个的子元素,直接赋值即可。对于List类型的子元素,要采用添加的方式。

修改完的MyTaskConfig.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2016.04.12 at 10:37:45 AM CST
//

package jet.demo.model;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for MyTaskConfig complex type.
 *
 * <p>The following schema fragment specifies the expected content contained within this class.
 *
 * <pre>
 * <complexType name="MyTaskConfig">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="message" type="{http://www.example.org/patternConfig}Message" maxOccurs="unbounded" minOccurs="0"/>
 *         <element name="description" type="{http://www.example.org/patternConfig}Description"/>
 *       </sequence>
 *       <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MyTaskConfig", propOrder = {
    "message",
    "description"
})
public class MyTaskConfig {

    protected List<Message> message;
    @XmlElement(required = true)
    protected Description description;
    @XmlAttribute(name = "id")
    protected String id;

	// Added by hand, for the purpose of ant script running.
	public void addMessage(Message message) {
		List<Message> messageList = getMessage();
		messageList.add(message);
	}
	public void addDescription(Description description) {
		this.description = description;
	}
	// End of adding.

    /**
     * Gets the value of the message property.
     *
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the message property.
     *
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getMessage().add(newItem);
     * </pre>
     *
     *
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Message }
     *
     *
     */
    public List<Message> getMessage() {
        if (message == null) {
            message = new ArrayList<Message>();
        }
        return this.message;
    }

    /**
     * Gets the value of the description property.
     *
     * @return
     *     possible object is
     *     {@link Description }
     *
     */
    public Description getDescription() {
        return description;
    }

    /**
     * Sets the value of the description property.
     *
     * @param value
     *     allowed object is
     *     {@link Description }
     *
     */
    public void setDescription(Description value) {
        this.description = value;
    }

    /**
     * Gets the value of the id property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setId(String value) {
        this.id = value;
    }

}

第四步,编写自己的Task。

先在项目中导入Ant的jar包:ant.jar 和ant-launcher.jar。然后在jet.demo.task包下新建一个MyTask类,继承ant的torg.apache.tools.ant.Task类。

MyTask.java

package jet.demo.task;

import java.util.List;

import jet.demo.model.Description;
import jet.demo.model.Message;
import jet.demo.model.MyTaskConfig;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class MyTask  extends Task {

	private MyTaskConfig myTaskConfig;

	public void addMyTaskConfig(MyTaskConfig myTaskConfig) {
		this.myTaskConfig = myTaskConfig;
	}

	@Override
	public void execute() throws BuildException {
		// show Message List
		List<Message> messageList = myTaskConfig.getMessage();
		if (messageList != null) {
			for (Message message : messageList) {
				show("message", message.getId(), message.getContent());
			}
		}

		// show Description
		Description description = myTaskConfig.getDescription();
		if (description != null) {
			show("description", description.getId(), description.getContent());
		}
	}

	// show Information of Element
	private void show(String type, String id, String content) {
		System.out.println("type=" + type + ",id=" + id + ",content=" + content);
	}

}

其中myTaskConfig就是我们的根元素,同样需要添加add方法,execute就是ant的task所执行的方法,我们可以通过重载这个方法,实现自己的功能。这里仅仅是打印所有的message和description信息。

第五步,编写Ant脚本。在jet.demo.script包下创建Ant脚本,取名为MyTask.xml。

<?xml version="1.0" encoding="UTF-8"?>

<project name="WritingAntTaskDemo" default="theTarget">

	<target name="theTarget">

		<echo message="Begin to run the target..." />

		<taskdef name="myTask" classname="jet.demo.task.MyTask">
		</taskdef>

		<myTask>
			<myTaskConfig>
				<message id="Mesg1" content="this is message One." />
				<message id="Mesg2" content="this is message Two." />
				<message id="Mesg3" content="this is message Thress." />
				<description id="DescOne" content="this is my description." />
			</myTaskConfig>
		</myTask>

	</target>

</project>

这里project取名为“WritingAntTaskDemo”,默认执行的target是“theTarget”。在project中创建了一个名为“theTarget”的target,作为project的默认执行目标。

在target中先用echo输出一句话,说明targe开始执行。

然后就是配置我们自己定义的Task,采用taskdef标签,name取名为myTask,classname表示我们自定义Task的类名,这里是jet.demo.task.MyTask。

这就是定义我们的参数信息了,“myTask”是与taskdef中的name对应的。里面有一个myTaskConfig,myTaskConfig中有三个message和一个description。

好了,接下来就是执行这个Ant脚本了。

第六步,执行Ant脚本。

在Eclipse菜单栏中选择Run--> Run Configurations--> 创建一个Java Applicatio。

这里取名为MyTask,Project选择WritingAntTaskDeml,Main Class设置为org.apache.tools.ant.Main。

Arguments设置为-f "E:\workplace_smart_luna\WritingAntTaskDemo\src\jet\demo\script\MyTask.xml",-f里的是我们之前编写的Ant脚本的路径,这个大家要自己修改。

选择Apply,然后Run。这个时候可以控制台的输出:

Buildfile: E:\workplace_smart_luna\WritingAntTaskDemo\src\jet\demo\script\MyTask.xml

theTarget:
     [echo] Begin to run the target...
   [myTask] type=message,id=Mesg1,content=this is message One.
   [myTask] type=message,id=Mesg2,content=this is message Two.
   [myTask] type=message,id=Mesg3,content=this is message Thress.
   [myTask] type=description,id=DescOne,content=this is my description.

BUILD SUCCESSFUL
Total time: 0 seconds

大功告成。

总结

本文主要讲解如何利用JAXB类,采用自定义Ant Task的方式来读取自定义的XML格式,从而直接生成属性对象。

首先创建XSD,作为xml的schema,的好处是以后修改起来很方便,看起来也很直观。

然后是通过XSD生成JAXB类,以及针对Ant的特性,稍微修改JAXB类,添加add方法。

接着就是编写自己的Task类,需要继承Ant的org.apache.tools.ant.Task类,实现自己的execute方法。

再就是编写Ant的build脚本,配置XML信息。

最后便是运行Ant脚本。

源码下载地址:

https://github.com/siyueshiqi/JetDemos

时间: 2024-08-02 00:00:20

基于JAXB的Ant自定义Task的相关文章

java 调用ant的自定义task,默认不是build.xml 的一点问题

java  调用ant的自定义task, File buildFile = new File(".//ee-build.xml"); // 创建一个ANT项目 Project p = new Project(); // 创建一个默认的监听器,监听项目构建过程中的日志操作 DefaultLogger consoleLogger = new DefaultLogger(); consoleLogger.setErrorPrintStream(System.err); consoleLogg

Android Gradle 自定义Task 详解

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/76408024 本文出自[赵彦军的博客] 一:Gradle 是什么 Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具. 它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置.面向Java应用为主. 当前其支持的语言限于Java.Groovy.Kotlin和Scala,计划未来将支持更多的语言.基

团队项目利用Msbuild自定义Task实现增量发布

最近一直在做自动部署工具,主要利用到了Msbuild的自定义Task,通过Task我们可以自定义编译.部署过程减少人工直接干预.Msbuild的详细用法,可以去园子里搜一下,有很多的基础教程,这里就不赘述了,还是集中说一下增量发布的问题. 增量主要涉及到三部分内容,程序.配置和静态文件(例如CSS.JS等),程序的增量比较简单,通过版本对比或者TFS的修改记录便可以查询出被修改过的程序集.配置文件增量大致有两种,全增量和部分增量.全增量也很简单,直接把修改过的配置文件复制到发布包就OK了:部分增

Android开发:《Gradle Recipes for Android》阅读笔记(翻译)4.2——增加自定义task

问题: 你想要在整体的构建过程中加入自定义的task. 解决方案: 使用dependOn属性将你的任务插入 directed acyclic graph 讨论: 在初始化阶段,Gradle将任务根据依赖集合成一个序列.结果就是一个DAG.举例子,Gradle记录为java插件生成一个DAG,如下图: "directed"意味着每个依赖箭头只有一个方向."Acyclic"意味着在图表中没有循环. 在主进程中增加自定义task意味着,在图表的合适位置插入你的任务. 4.

对基于JUnit和Ant的测试用例执行过程使用Kieker(AspectJ)进行监控的方法

这篇日志的目的从标题里可以看出来.这也是我们实验需要,必须总结一下,方便其他师弟师妹在这个基础上做实验. 我已经介绍了很多基于Kieker的监控方法,这里以Prefuse这个开源可视化Java框架为例,总结怎么基于JUnit和Ant实现对开源软件自带测试用例执行过程的监控.在这个链接中,选择最新的版本下载(Prefuse已经有些年头没更新了,不过这个框架确实还不错). 解压之后用Eclipse打开其build.xml,发现这个项目的build.xml结构还比较奇葩.如果运行ant all,可以生

基于Activiti5.15.1 自定义用户、组(User,Group)实现

基于Activiti5.15.1 自定义用户.组(User,Group)实现 本人刚接触Activiti,最近工作中需要将Activiti中原有的用户,组(ACT_ID_USER,ACT_ID_GROUP,ACT_ID_MEMBERSHIP)表替换为公司已有的相关表.查看了咖啡兔及论坛相关文章.今天有空整理一下.以帮助后续有此需要的初学者. 自定义Group,User工厂类,实现SessionFactory接口 1)CustomGroupEntityManagerFactory @Service

基于JUnit和Ant测试程序正在运行使用Kieker(AspectJ)监测方法

这篇日志的目的从标题里能够看出来.这也是我们实验须要,必须总结一下,方便其它师弟师妹在这个基础上做实验. 我已经介绍了非常多基于Kieker的监控方法,这里以Prefuse这个开源可视化Java框架为例,总结怎么基于JUnit和Ant实现对开源软件自带測试用例运行过程的监控. 在这个链接中,选择最新的版本号下载(Prefuse已经有些年头没更新了.只是这个框架确实还不错). 解压之后用Eclipse打开其build.xml,发现这个项目的build.xml结构还比較奇葩.假设执行ant all,

Ant自定义任务开发

最近部门在搞持续集成提速,增量构建是个很重要的措施.但是实现增量构建需要识别代码库变化的代码.文件关联到的构建步骤,比如进程编译.后台出包还是其他步骤.当前我们使用的持续集成插件不支持该功能,因此针对我们产品情况,我自己写了一个自定义任务,来进行代码库变化与任务的识别. 我们使用的插件功能都是jar包,通过ant脚本来进行调用,因此实现自定义任务,也就是做一个Ant的自定义任务. Ant开发自定义任务,一般都是通过java开发,在eclipse中开发,步骤如下: 1.创建java工程: 2.配置

基于Entity Framework的自定义分页,增删改的通用实现

简介 之前写个一个基于Dapper的分页实现,现在再来写一个基于Entity Framework的分页实现,以及增删改的通用实现. 代码 还是先上代码:https://github.com/jinweijie/EF.GenericRepository 如何运行示例 还是像先前一样: 1. 先Clone下代码,在Database里面解压缩Database.7z 2. Attach到Sql Server LocalDB上.如果你用的不是Sql Server的LocalDB,你需要更改App.Conf