JAXB:java对象和xml之间转换
JAXB(Java Architecture for XML Binding)是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。
常用注解:
@XmlRootElement:将类映射为根元素
该注解含有name和namespace两个属性。namespace属性用于指定生成的元素所属的命名空间。name属性用于指定生成元素的名字,若不指定则默认使用类名小写作为元素名。
@XmlElement:将被注解的字段映射为子元素。
name属性可以指定生成元素的名字
@XmlAttribute:将字段映射成本类对应元素(标签)的属性
@XmlTransient:在映射xml元素时忽略被注解的字段
@XmlAccessorType:决定哪些字段会被映射为xml元素。
XmlAccessType.FIELD:java对象中的所有成员变量
XmlAccessType.PROPERTY:java对象中所有通过getter/setter方式访问的成员变量(属性)
XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量
XmlAccessType.NONE:java对象的所有属性都不映射为xml的元素
@XmlElementWrapper:用在集合对象上,映射后包装同一个元素。此时@XmlElement可以没有。
@XmlJavaTypeAdapter:指定自定义适配器,解决java日期(Date),数字(Number)格式化问题。
实例:
实体类
@XmlRootElement@XmlAccessorType(XmlAccessType.FIELD) # 表示成员变量就可以被转换成xml中的标签
public class Boy {
public String name = "CY";
}
测试类
public class JAXBTest {public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Boy.class);
Marshaller marshaller = context.createMarshaller();
Unmarshaller unmarshaller = context.createUnmarshaller();
// marshall将java对象转成xml
Boy boy = new Boy();
marshaller.marshal(boy, System.out);
System.out.println();
// unmarshall将xml转成java对象
String xml = "<boy><name>David</name></boy>";
Boy boy2 = (Boy) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(boy2.name);
}
}
结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><name>CY</name></boy>David
改造一:
将XmlAccessType.FIELD改为XmlAccessType.PROPERTY
@XmlRootElement@XmlAccessorType(XmlAccessType.PROPERTY) # 只有属性才能转换成xml中的标签
public class Boy {
public String name = "CY";
}
再次运行,结果为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy/>CY
发现Marshall和unMarshall都失败。由于name没有getter/setter方法,故不是属性,所以java对象转成xml时,name不转为标签
该造二:
给name属性添加 get set 方法。
@XmlRootElement@XmlAccessorType(XmlAccessType.PROPERTY)
public class Boy {
public String name = "CY";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
再次执行,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><name>CY</name></boy>David
结果正常
改造三:
给Boy 再添加一个field, int age=10
再次运行,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><name>CY</name></boy>David
显然,这个age 是不会被 转化 到xml 文件中的。解决办法是:给age添加@XmlElement注解
@XmlRootElement@XmlAccessorType(XmlAccessType.PROPERTY)
public class Boy {
public String name = "CY";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElement
int age=10;
}
再次运行,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><age>10</age><name>CY</name></boy>David
发现多了一个age标签
使用@XmlElement注解,成员变量可以映射为标签,
@XmlRootElement@XmlAccessorType(XmlAccessType.PROPERTY)
public class Boy {
@XmlElement
public String name = "CY";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElement
int age=10;
}
但是属性不能加@XmlElement注解,否则报错如下:
Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions类的两个属性具有相同名称 "name"
this problem is related to the following location:
at public java.lang.String com.ljxx.entity.business.Boy.getName()
at com.ljxx.entity.business.Boy
this problem is related to the following location:
at public java.lang.String com.ljxx.entity.business.Boy.name
at com.ljxx.entity.business.Boy
at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:106)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:460)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:292)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:139)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1138)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:162)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:441)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at com.ljxx.JAXBTest.main(JAXBTest.java:18)
改造四:
将@XmlRootElement改为@XmlRootElement(name="b" nameSpace="http://test"),
@XmlRootElement(name="b",namespace ="http://test")@XmlAccessorType(XmlAccessType.PROPERTY)
public class Boy {
public String name = "CY";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElement
int age=10;
}
测试类
public class JAXBTest {public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Boy.class);
Marshaller marshaller = context.createMarshaller();
Unmarshaller unmarshaller = context.createUnmarshaller();
Boy boy = new Boy();
marshaller.marshal(boy, System.out);
System.out.println();
}
}
再次运行,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:b xmlns:ns2="http://test"><age>10</age><name>CY</name></ns2:b>
在生成的xml文件中,<boy> 标签 就会变为 <b> 标签。并且加上一个命名空间。
如果不加名称空间:@XmlRootElement(name="b"),结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b><age>10</age><name>CY</name></b>
发现<boy> 标签 就会变为 <b> 标签
改造五:
如果不使用@XmlAccessorType指定,@XmlAccessorType的默认访问级别是XmlAccessType.PUBLIC_MEMBER,
@XmlRootElement(name="b")public class Boy {
public String name = "CY"; # public访问权限的成员变量
@XmlElement
int age=10;
}
或
@XmlRootElement(name="b")public class Boy {
private String name = "CY";
// 由于name被private修饰,故只能通过getter/setter方式访问的成员变量
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElement
int age=10;
}
结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b><name>CY</name><age>10</age></b>
当为XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量都可以转为标签。
改造六:
XmlAccessType.PROPERTY:表明只能是属性才能被转为xml中的元素,而@XmlAttribute注解将成员变量映射为属性
@XmlRootElement(name="b")@XmlAccessorType(XmlAccessType.PROPERTY)
public class Boy {
@XmlAttribute
private String name = "CY";
@XmlElement
int age=10;
}
结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b name="CY"><age>10</age></b>
发现name成员变量变为了标签的属性
改造七:
@XmlTransient注解忽略被注解的字段
@XmlRootElement(name="b")@XmlAccessorType(XmlAccessType.PROPERTY)
public class Boy {
@XmlAttribute
private String name = "CY";
@XmlTransient
int age=10;
}
结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b name="CY"/>
改造八:
添加一个Key类
@XmlRootElementpublic class Key {
@XmlElement
private String roomNo;
public Key() {
}
public Key(String roomNo) {
this.roomNo = roomNo;
}
}
修改Boy类如下:
@XmlRootElement(name="b")public class Boy {
@XmlElement
private String name;
@XmlElement
int age;
public Boy() {
}
@XmlElement
private Set<Key> key = new HashSet<>();
public Boy(String name, int age) {
this.name = name;
this.age = age;
key.add(new Key("001")); //向集合中添加两个Key对象
key.add(new Key("002"));
}
}
修改测试类如下:
public class JAXBTest {public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Boy.class);
Marshaller marshaller = context.createMarshaller();
Unmarshaller unmarshaller = context.createUnmarshaller();
Boy boy = new Boy("CY",10);
marshaller.marshal(boy, System.out);
System.out.println();
}
}
当不加@XmlElementWrapper(name="keys")注解时,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b>
<name>CY</name>
<age>10</age>
<key>
<roomNo>001</roomNo>
</key>
<key>
<roomNo>002</roomNo>
</key>
</b>
当加上@XmlElementWrapper(name="keys")后代码如下:
@XmlRootElement(name="b")public class Boy {
@XmlElement
private String name;
@XmlElement
int age;
public Boy() {
}
@XmlElementWrapper(name="keys")
@XmlElement
private Set<Key> key = new HashSet<>();
public Boy(String name, int age) {
this.name = name;
this.age = age;
key.add(new Key("001")); //向集合中添加两个Key对象
key.add(new Key("002"));
}
}
结果为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b>
<name>CY</name>
<age>10</age>
<keys>
<key>
<roomNo>001</roomNo>
</key>
<key>
<roomNo>002</roomNo>
</key>
</keys>
</b>
改造九:
在Boy类中添加一个Date类型字段
@XmlRootElement(name="b")public class Boy {
@XmlElement
private String name;
@XmlElement
int age;
@XmlElement
private Date date = new Date();
public Boy() {
}
@XmlElementWrapper(name="keys")
// @XmlElement
private Set<Key> key = new HashSet<>();
public Boy(String name, int age) {
this.name = name;
this.age = age;
key.add(new Key("001")); //向集合中添加两个Key对象
key.add(new Key("002"));
}
}
结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b>
<name>CY</name>
<age>10</age>
<date>2021-09-27T17:26:41.525+08:00</date>
<keys>
<key>
<roomNo>001</roomNo>
</key>
<key>
<roomNo>002</roomNo>
</key>
</keys>
</b>
我们需要yyyy-MM-dd格式的日期,这就需要@XmlJavaTypeAdapter注解,自定义一个适配器来解决这个问题。
自定义适配器继承XmlAdapter类,实现里面的marshal和unmarshal方法
public class DateAdapter extends XmlAdapter<String, Date> {private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
@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(DateAdapter.class)
@XmlRootElement(name="b")public class Boy {
@XmlElement
private String name;
@XmlElement
int age;
@XmlElement
@XmlJavaTypeAdapter(DateAdapter.class)
private Date date = new Date();
public Boy() {
}
@XmlElementWrapper(name="keys")
// @XmlElement
private Set<Key> key = new HashSet<>(); // key即为被keys标签包装的标签的名字
public Boy(String name, int age) {
this.name = name;
this.age = age;
key.add(new Key("001")); //向集合中添加两个Key对象
key.add(new Key("002"));
}
}
结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b>
<name>CY</name>
<age>10</age>
<date>2021-09-27</date>
<keys>
<key>
<roomNo>001</roomNo>
</key>
<key>
<roomNo>002</roomNo>
</key>
</keys>
</b>
改造十:
设置输出的格式:换行和缩进 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
public class JAXBTest {public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Boy.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Boy boy = new Boy("CY",10);
marshaller.marshal(boy, System.out);
System.out.println();
}
}
结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><b>
<name>CY</name>
<age>10</age>
<date>2021-09-27</date>
<keys>
<key1>
<roomNo>001</roomNo>
</key1>
<key1>
<roomNo>002</roomNo>
</key1>
</keys>
</b>
改造十一:
去掉生成xml时的默认报文头:marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
public class JAXBTest {public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Boy.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
Boy boy = new Boy("CY",10);
marshaller.marshal(boy, System.out);
System.out.println();
}
}
结果如下:
<b><name>CY</name>
<age>10</age>
<date>2021-09-27</date>
<keys>
<key1>
<roomNo>001</roomNo>
</key1>
<key1>
<roomNo>002</roomNo>
</key1>
</keys>
</b>
以上是 JAXB:java对象和xml之间转换 的全部内容, 来源链接: utcz.com/z/389689.html