最近几天,我自己负责的应用这边引入了一个新的合作方,主要是我这边调用他们的接口,但是有个很坑的地方,他们传参居然不支持json格式,并且只支持xml格式进行交互,于是自己写了一个工具类去支持bean与xml互相转换,json与xml之间互相转换。

JAXBContext 接口

我在这里使用了rt.jar 下javax下的 JAXBContext 接口,它提供了 JAXB API 的客户端入口点。它提供了管理实现 JAXB 绑定框架操作所需的 XML/Java 绑定信息的抽象。

  • 获取 JAXBContext 接口实例
    JAXBContext 接口为我们提供了获取 JAXBContext 实例的 newInstance 方法。将需要转换为xml的bean的class传入即可。
JAXBContext context = JAXBContext.newInstance(zlass);
 

Marshaller 接口

  • 获取 Marshaller 接口实例
    JAXBContext 实例为我们提供了获取 Marshaller 实例的 createMarshaller方法。
Marshaller marshaller = context.createMarshaller();
 

Marshaller 接口主要是将java对象序列化成xml字符串,是通过 marshal 方法。

/**
* JAVA bean 转 xml
* @param obj
* @param zlass
* @return
* @throws JAXBException
*/
public static String beanToXml (Object obj, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
}
 

Marshaller 接口中还定义了5个属性,分别是:

  • JAXB_ENCODING
    这个属性是设置编码集,
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK"); 
  • JAXB_FORMATTED_OUTPUT
    这个属性是是否格式化生成的xml串 true-格式化,false-不格式化
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
  • JAXB_SCHEMA_LOCATION
    指定xsi:schemaLocation,它定义了XML Namespace和对应的XSD(Xml Schema Definition)文档的位置的关系。它的值由一个或多个URI引用对组成,两个URI之间以空白符分隔(空格和换行均可)。第一个URI是定义的XML Namespace的值,第二个URI给出Schema文档的位置,Schema处理器将从这个位置读取Schema文档,该文档的targetNamespace必须与第一个URI相匹配。
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "xxx.xxx.xxx"); 
  • JAXB_NO_NAMESPACE_SCHEMA_LOCATION
    如果没有Namespeace,但是需要使用Schema,就需要用到JAXB_NO_NAMESPACE_SCHEMA_LOCATION,它可以指定将放置在已编组 XML 输出中的 xsi:noNamespaceSchemaLocation 属性值
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "xxx.xxx.xxx"); 
  • JAXB_FRAGMENT
    是否省略xml头信息()true-省略,false-不省略
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false); 

Unmarshaller 接口

  • 获取 Unmarshaller 接口实例
    JAXBContext 实例为我们提供了获取 Unmarshaller 实例的 createUnmarshaller 方法,需要注意的是,反序列化时需要将转换的bean上加上无参构造器。
Unmarshaller unmarshaller = context.createUnmarshaller(); 

Marshaller 接口主要是将java对象序列化成xml字符串,是通过 unmarshal 方法。

/**
* xml 转 JAVA bean
* @param xml
* @param zlass
* @return
* @throws JAXBException
*/
public static Object xmlToBean (String xml, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(xml));
return object;

JAXB相关的重要Annotation

我在这定义3个类,来简单说一下下面几个常用的注解的作用,与用法。
首先是一个班级类

@XmlRootElement(name = "class")
public class ClassAndGrade { private ClassAndGradeMsg classAndGrade; private List<Student> students; @XmlElement(name="classAndGrade")
public ClassAndGradeMsg getClassAndGrade() {
return classAndGrade;
} public void setClassAndGrade(ClassAndGradeMsg classAndGrade) {
this.classAndGrade = classAndGrade;
} @XmlElementWrapper(name="students")
@XmlElement(name="student")
public List<Student> getStudents() {
return students;
} public void setStudents(List<Student> students) {
this.students = students;
} } 

然后再定义一个班级信息类

public class ClassAndGradeMsg {

    private Integer personNum;

    private String name;

    private String classTeacher;

    /**
* @Title:ClassAndGradeMsg
* @param:@param personNum
* @param:@param name
* @param:@param classTeacher
* @throws
*/
public ClassAndGradeMsg(Integer personNum, String name, String classTeacher) {
super();
this.personNum = personNum;
this.name = name;
this.classTeacher = classTeacher;
} @XmlElement(name="personNum")
public Integer getPersonNum() {
return personNum;
} public void setPersonNum(Integer personNum) {
this.personNum = personNum;
} @XmlElement(name="name")
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @XmlElement(name="classTeacher")
public String getClassTeacher() {
return classTeacher;
} public void setClassTeacher(String classTeacher) {
this.classTeacher = classTeacher;
}

再定义以后学生类

public class Student {

    private String name;

    private Integer age;

    private String sex;

    /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} @XmlElement(name="name")
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @XmlElement(name="age")
public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} @XmlElement(name="sex")
public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} } 

最后再写一个测试main方法

public static void main(String[] args) throws ClassNotFoundException {
ClassAndGrade classAndGrade = new ClassAndGrade();
ClassAndGradeMsg classAndGradeMsg = new ClassAndGradeMsg(, "三年二班", "张三");
classAndGrade.setClassAndGrade(classAndGradeMsg);
List<Student> list = new ArrayList<Student>();
Student s1 = new Student("李四", , "男");
Student s2 = new Student("王五", , "女");
list.add(s1);
list.add(s2);
classAndGrade.setStudents(list);
try {
String xml = XmlUtil.beanToXml(classAndGrade, ClassAndGrade.class);
System.out.println(xml);
} catch (Exception e) {
e.printStackTrace();
}
  • @XmlRootElement
    类级别的注解,这个注解为根节点的注解,加在类上面,而且为必要的注解,如果没有此注解,执行beanToXml方法时将会报异常。这个根节点默认名字为类名,但是可以设置name属性来修改根节点名字。namespace属性可以用于指定生成的元素所属的命名空间。
@XmlRootElement(name = "class")
public class ClassAndGrade { 

执行结果如下,ClassAndGrade 被修改为class:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<class>
<classAndGrade>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGrade>
<students>
<student>
<age></age>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<age></age>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</class> 
  • @XmlElement
    字段,方法级别的注解,将java类的属性映射为xml的一个结点。一般使用在属性上,或者get方法上,其中常用的属性有name、nillable、namespace、defaultValue。name可以设置结点的名称;nillable 指定文本是否可以为空,true-可以为空,false-不可以为空,默认为false,如果设置为true,则该字段为空是,这个结点也会生成,但是值为空,如果是指为false,则该结点不生成;namespace属性可以用于指定生成的元素所属的命名空间;defaultValue 可以设置该结点的默认文本。
@XmlElement(name="sex", nillable = false, defaultValue = "女")
public String getSex() {
return sex;
  • @XmlTransient
    类,字段,方法级别的注解。当添加这个注解后,这个属性或者类将不进行映射。需要注意的是该注解与所有其他JAXB注解相互排斥.
    
@XmlTransient
public Integer getAge() {
return age;

现在执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade> 

age结点被剔除

  • @XmlAccessorType
    类级别注解,其中有一个value属性,值为XmlAccessType的枚举类。
  1. XmlAccessType.PROPERTY 加这个value表示,会将所有拥有get方法和set方法的属性(必须2个方法都有,否则不映射)映射成xml,除非加入@XmlTransient则不会映射,如果没有get/set方法,则需要再属性上加上@XmlElement。
@XmlAccessorType(value = XmlAccessType.PROPERTY)
public class Student { private String name;
private Integer age;
@XmlElement(name="sex", nillable = false, defaultValue = "女")
private String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
}

我在Student类中加上@XmlAccessorType注解,并且在sex属性上加上@XmlElement注解,给name属性加上get/set方法,给age只加了get方法,执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade> 

上例可以看出只显示了name和sex结点,而没有显示age结点。
2.XmlAccessType.FIELD
这个属性是将类中非静态的属性都映射到xml中,并且不需要加get/set方法

@XmlAccessorType(value = XmlAccessType.FIELD)
public class Student { private String name;
private Integer age;
private static String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}

我在将sex属性写为静态,执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<age></age>
<name>李四</name>
</student>
<student>
<age></age>
<name>王五</name>
</student>
</students>
</classAndGrade> 

sex 确实没有被映射。
3.XmlAccessType.PUBLIC_MEMBER
这个属性值,是@XmlAccessorType的默认默认值,它会将属性为public的属性或者get/set方法同时为public的属性映射成xml。

@XmlAccessorType(value = XmlAccessType.PUBLIC_MEMBER)
public class Student { public String name;
private Integer age;
public String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} private String getName() {
return name;
} private void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
}

上例中 name 的属性为public的 get/set方法为private的,age的属性为private的且只有一个get方法,sex只有一个public的方法执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade> 

4.XmlAccessType.NONE
这个属性表示任何属性都不会被映射到xml中,除非使用其他注解,如@XmlElement

@XmlAccessorType(value = XmlAccessType.NONE)
public class Student { @XmlElement(name="name")
public String name;
private Integer age;
public String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}

执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
</student>
<student>
<name>王五</name>
</student>
</students>
</classAndGrade> 

只映射了name

  • @XmlAccessorOrder
    类级别的注解。控制生成属性映射xml结点的顺序。其中有一个value属性,可以设置排序方式,XmlAccessOrder.ALPHABETICAL 为按照字母顺序进行排序, XmlAccessOrder.UNDEFINED按照属性顺序进行排序,默认为XmlAccessOrder.UNDEFINED
@XmlAccessorOrder(value = XmlAccessOrder.ALPHABETICAL)
public class Student {

现在执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<age></age>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<age></age>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade>
 
  • @XmlJavaTypeAdapter
    这个注解主要是解决一些数据格式化问题的,比如时间格式化。
    我在我的Student类中加入time字段。
public Date time; 

但是直接执行的话这个xml映射的结果为:

<time>--04T17::38.158+:</time> 

但是,这不是我想要的结果,我需要格式化之后的数据。
创建时间格式化类Dateformatting

public class Dateformatting extends XmlAdapter<String, Date> {

    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
@Override
public Date unmarshal(String date) throws Exception {
return SDF.parse(date);
} @Override
public String marshal(Date date) throws Exception {
return SDF.format(date);
} } 

在时间属性上加上@XmlJavaTypeAdapter(Dateformatting.class)

@XmlJavaTypeAdapter(Dateformatting.class)
public Date time; 

执行结果:

<time>-- ::</time> 

此时时间已经被格式化成我们想要的格式。

  • @XmlElementWrapper
    这个注解是加载集合上面的,我在上面学生List上就是加了这个注解。
    
@XmlElementWrapper(name="students")
@XmlElement(name="student")
public List<Student> getStudents() {
return students;
  • @XmlAttribute
    这个注解会将属性变为上一个结点的属性
  
 @XmlAttribute(name="name")
public String name; 

执行结果为

        
<student name="李四">
<sex>男</sex>
<time>-- ::</time>
</student> 
  • @XmlType
    类级别的注解,这个注解可以自定义排序,使用propOrder 属性。
@XmlType(propOrder = {"time", "sex", "age", "name"})
public class Student {

执行结果为:        

<student>
<time>-- ::</time>
<sex>女</sex>
<age></age>
<name>王五</name>
</student>

上面就是我们在使用JAXB时常用的一些注解,以及用法。

最后附上我自己使用的xmlUtil的工具类。

/**
* xml util
* @author wuyouxin
*
*/
public class XmlUtil { /**
* JAVA bean 转 xml
* @param obj
* @param zlass
* @return
* @throws JAXBException
*/
public static String beanToXml (Object obj, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
} /**
* xml 转 JAVA bean
* @param xml
* @param zlass
* @return
* @throws JAXBException
*/
public static Object xmlToBean (String xml, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(xml));
return object;
} }

-------------------- END ---------------------


最后附上作者的微信公众号地址和博客地址


公众号:wuyouxin_gzh




Herrt灬凌夜:https://www.cnblogs.com/wuyx/

 

使用JAXB实现Bean与Xml相互转换的更多相关文章

  1. 启动服务报错:nested exception is java.lang.NoSuchMethodError: org.apache.cxf.common.jaxb.JAXBUtils.closeUnmarshaller(Ljavax/xml/bind/Unmarshaller;)V

    1.启动tomcat时报错:Error creating bean with name 'payInfService': Invocation of init method failed; neste ...

  2. JAXB—Java类与XML文件之间转换

    JAXB-Java类与XML文件之间转换 简介         JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生 ...

  3. JAVA bean与XML互转的利器---XStream

    最近在项目中遇到了JAVA bean 和XML互转的需求, 本来准备循规蹈矩使用dom4j忽然想起来之前曾接触过的XStream, 一番研究豁然开朗,利器啊利器, 下来就XStream的一些用法与大家 ...

  4. java对象与xml相互转换 ---- xstream

    XStream是一个Java对象和XML相互转换的工具,很好很强大.提供了所有的基础类型.数组.集合等类型直接转换的支持. XStream中的核心类就是XStream类,一般来说,熟悉这个类基本就够用 ...

  5. Excel与XML相互转换 - C# 简单实现方案

    Excel与XML相互转换 - C# 简单实现方案 在日常工作中,我需要将数据存储在Excel中进行数据分析和处理,然后再将数据转换为XML格式进行跨平台的数据交换.网上搜索Excel转换为XML的实 ...

  6. JAVA Bean和XML之间的相互转换 - XStream简单入门

    JAVA Bean和XML之间的相互转换 - XStream简单入门 背景介绍 XStream的简介 注解简介 应用实例 背景介绍 我们在工作中经常 遇到文件解析为数据或者数据转化为xml文件的情况, ...

  7. lientDataset的Delta与XML相互转换

    一个ClientDataset的Delta与XML相互转换的文章:大家都知道TClientDataSet的Delta属性保存数据集的变化,但是Delta是OleVariant类型的属性,这样如果用De ...

  8. Spring基础使用(一)--------IOC、Bean的XML方式装配

    基础 1.xml文件基础格式: <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns=&q ...

  9. JSON对象与XML相互转换工具类

    依赖jar <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId ...

随机推荐

  1. 安装【Jenkins】

    前言      jenkins的一款持续集成工具,      它可以做的事情很多,其中一个主要的功能就是简化部署流程          回想一下我们的发布流程:           1.本地把项目打包 ...

  2. Linux下使用cron让Python程序持久化运行

    正常情况下,一个python程序如果希望实现一直运行,不出错不奔溃是很难的,即使编译为可持续文件也是一样 幸运的是很多需求并不是需要24小时不间断运行,而是每隔一段时间运行一次即可 Linux系统自带 ...

  3. Java基础-SSM之mybatis多对多关联

    Java基础-SSM之mybatis多对多关联 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.准备测试环境(创建数据库表) 1>.创建teas,stus,links表 u ...

  4. 鸟哥的Linux私房菜——第十三章:Vim编译器

    视频链接: 土豆: B站:http://www.bilibili.com/video/av9891085/ 本章的细节还是挺多的,可是我懒啊~~

  5. 手机安全卫士-——Splash总结

    1.在AndroidManifest.xml文件的application中配置,应用的主题:不带标题的主题 android:theme="@android:style/Theme.Black ...

  6. ngx_lua_API 指令详解(三)怎样理解 cosocket指令

    参考:https://moonbingbing.gitbooks.io/openresty-best-practices/content/ngx_lua/whats_cosocket.html 春哥演 ...

  7. js调试系列: 调试基础与技巧

    js调试系列目录: - 昨天我们见识到了断点的强悍,在断点的配合下进行动态调试,让读代码变的轻松不少,特别是ajax之类的.在昨天的课后练习中,确实增加了不少难度,因为 提交评论 按钮是用 jQuer ...

  8. 【转载】RESTful API 设计指南

    作者: 阮一峰 日期: 2014年5月22日 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制 ...

  9. UI渲染回顾简单笔记

    UI渲染的简单过程: CPU,GPU,显示器协同工作,CPU 中计算显示内容,比如视图的创建.布局计算.图片解码.文本绘制等,然后将计算结果提交给GPU,由 GPU 进行变换.合成.渲染.随后 GPU ...

  10. tensorflow的卷积和池化层(二):记实践之cifar10

    在tensorflow中的卷积和池化层(一)和各种卷积类型Convolution这两篇博客中,主要讲解了卷积神经网络的核心层,同时也结合当下流行的Caffe和tf框架做了介绍,本篇博客将接着tenso ...