最近在学习《netty权威指南》,在第十章搭建http+xml服务器中,使用到了Jibx绑定对象和ant配置。书中对这一部分描述太少,同时我的为maven项目,在代码过程中遇到一些坑。在此记录总结一下。
本文源码已经上传到github,如果对你有用,欢迎star : https://github.com/icecrea/Netty
官方参考文档:http://jibx.sourceforge.net/bindcomp.html
先简单看下jibx相关的介绍:
使用JiBX绑定XML文档与Java对象需要分两步走:第一步是绑定XML文件,也就是映射XML文件与Java对象之间的对应关系;第二步是在运行时,实现XML文件与Java实例之间的互相转换。这时,它已经与绑定文件无关了,可以说是完全脱耦了。
在运行程序之前,需要先配置绑定文件并进行绑定,在绑定过程中它将会动态地修改程序中相应的class文件,主要是生成对应对象实例的方法和添加被绑定标记的属性JiBX_bindingList等。它使用的技术是BCEL(Byte Code Engineering Library),BCEL是Apache Software Foundation的Jakarta项目的一部分,也是目前Java classworking最广泛使用的一种框架,它可以让你深入JVM汇编语言进行类操作。在JiBX运行时,它使用了目前比较流行的一个技术XPP(Xml Pull Parsing),这也正是JiBX如此高效的原因。
JiBx有两个比较重要的概念:Unmarshal(数据分解)和Marshal(数据编排)。从字面意思也很容易理解,Unmarshal是将XML文件转换成Java对象,而Marshal则是将Java对象编排成规范的XML文件。JiBX在Unmarshal/Marshal上如此高效,这要归功于使用了XPP技术,而不是使用基于树型(tree-based)方式,将整个文档写入内存,然后进行操作的DOM(Document Object Model),也不是使用基于事件流(event stream)的SAX(Simple API for Xml)。XPP使用的是不断增加的数据流处理方式,同时允许在解析XML文件时中断。
我们可以概括一下:
JiBX 是一个绑定 XML 数据到 Java 对象的框架。JiBX 用一个绑定定义文挡(binding definition document)来定义 XML 数据与 Java 对象转换的规则,这个文挡就是联系 XML 数据与 Java 对象之间的桥梁。用到了两个数据绑定术语 marshal 和 unmarshal,marshal 是由 Java 对象生成 XML 文挡,unmarshal 是根据 XML 文挡建立 Java 对象。
使用 JiBX 的过程分成两个过程,一个是 binding compiler,另一个是 binding runtime。binding compiler 是一个前期准备过程,包括定义绑定定义文挡,定义与 XML 绑定在一起的 Java 对象,然后编译。binding runtime 是使用 binding compiler 编译好的 Java class 处理 XML 数据。
Step1:使用Jibx工具类,生成binding.xml与pojo.xsd文件
引入jibx-bind 与util包
<groupId>org.jibx</groupId>
<artifactId>jibx-bind</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.jibx</groupId>
<artifactId>jibx-tools</artifactId>
<version>1.3.1</version>
</dependency>
-
此处注意:书中是1.2.5版本,但是Jdk1.8与该版本有bug,在1.3.1已经修复。所以此处需要用高版本
相关issue https://github.com/jibx/jibx/issues/3
自动生成有 两种方式
一、命令行生成
可以通过命令行生成bing.xml和pojo.xsd
注意:要使用官网下载的包,不能用maven仓库中的,该格式会少包。
以下命令会生成 binding.xml和pojo.xsd 文件
进入classes文件目录 cd F:\IdeaProj\Netty\target\classes\
java -cp E:\jibx\jibx_1_3_1\jibx\lib\jibx-tools.jar org.jibx.binding.generator.BindGen -b binding.xml com.example.cp10http.xml.pojo.Order
二、编写测试类代码生成
使用org.jibx.binding.generator.BindGen
import org.jibx.binding.Compile;
import org.jibx.binding.generator.BindGen;
import org.jibx.runtime.JiBXException;
import java.io.IOException;
public class GenerateBindXmlUtil {
public static void main(String[] args) throws JiBXException, IOException {
genBindFiles();
}
private static void genBindFiles() throws JiBXException, IOException {
String[] args = new String[9];
// 指定pojo源码路径(指定父包也是可以的)。必须
args[0] = "-s";
args[1] = "src";
// 自定义生成的binding文件名,默认文件名binding.xml。可选
args[2] = "-b";
args[3] = "binding.xml";
// 打印生成过程的一些信息。可选
args[4] = "-v";
// 如果目录已经存在,就删除目录。可选
args[5] = "-w";
//- t 指定xml和xsd输出路径 路径。默认路径 .(当前目录,即根目录)。
args[6] = "-t";
args[7] = "./src/main/java/com/example/cp10http/xml/pojo/order";
// 告诉 BindGen 使用下面的类作为 root 生成 binding 和 schema。必须
args[8] = "com.example.cp10http.xml.pojo.Order";
BindGen.main(args);
}
}
生成后位置如下,可以再移动到项目目录下
Step2:根据binding.xml文件,生成class文件
此处我们可以使用maven的jibx插件,将Bind绑定到编译时期
<build>
<plugins>
<plugin><!-- 生成jibx class信息 -->
<groupId>org.jibx</groupId>
<artifactId>jibx-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<schemaBindingDirectory>${basedir}/</schemaBindingDirectory>
<includeSchemaBindings>
<includeSchemaBindings>*binding.xml</includeSchemaBindings>
</includeSchemaBindings>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<id>jibx-bind</id>
<phase>compile</phase><!--把jibx绑定到了comile编译阶段 -->
<goals>
<goal>bind</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
通过mvn jibx:bind命令来运行插件 或者直接mvn clean install 均可以生产所需要Class文件,如下图所示:
同样也可以直接代码编译生成
public class GenerateBindXmlUtil {
public static void main(String[] args) throws JiBXException, IOException {
compile();
}
private static void compile() {
String[] args = new String[2];
// 打印生成过程的详细信息。可选
args[0] = "-v";
// 指定 binding 和 schema 文件的路径。必须
args[1] = "./binding.xml";
Compile.main(args);
}
}
Step3:运行测试类验证
上面两步正确,最后一步就是验证测试类了,在控制台成功输出。
public class TestOrder {
private IBindingFactory factory = null;
private StringWriter writer = null;
private StringReader reader = null;
private final static String CHARSET_NAME = "UTF-8";
private String encode2Xml(Order order) throws JiBXException, IOException {
factory = BindingDirectory.getFactory(Order.class);
writer = new StringWriter();
IMarshallingContext mctx = factory.createMarshallingContext();
mctx.setIndent(2);
mctx.marshalDocument(order, CHARSET_NAME, null, writer);
String xmlStr = writer.toString();
writer.close();
System.out.println(xmlStr.toString());
return xmlStr;
}
private Order decode2Order(String xmlBody) throws JiBXException {
reader = new StringReader(xmlBody);
IUnmarshallingContext uctx = factory.createUnmarshallingContext();
Order order = (Order) uctx.unmarshalDocument(reader);
return order;
}
public static void main(String[] args) throws JiBXException, IOException {
TestOrder test = new TestOrder();
Order order = OrderFactory.create(123);
String body = test.encode2Xml(order);
Order order2 = test.decode2Order(body);
System.out.println(order2);
}
}