Java中提供一套用于XML与Bean转换的工具javax.xml.bind.JAXBContext
先说结论:
在定义Bean时,要保证其默认无参的构造函数不能被覆盖(即当定义有参构造函数后默认无参构造函数需要显示声明定义)
JAXB实现对象与xml互转注解:
1.@XmlRootElement,用于类级别的注解,对应xml的跟元素。通过name属性定义这个根节点的名称。
2.@XmlAccessorType,定义映射这个类中的何种类型都需要映射到xml。(如果不存在@XmlAccessorType,默认使用XmlAccessType.PUBLIC_MEMBER注解)
参数:XmlAccessType.FIELD: java对象中的所有成员变量。
XmlAccessType.PROPERTY:java对象中所有通过getter/setter方式访问的成员变量。
XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量。
XmlAccessType.NONE: java对象的所有属性都不映射为xml的元素。
3.@XmlAttribute,用于把java对象的属性映射为xml的属性,并可通过name属性为生成的xml属性指定别名。
4.@XmlElement,指定一个字段或get/set方法映射到xml的节点。通过name属性定义这个根节点的名称。
5.@XmlElementWrapper,为数组或集合定义一个父节点。通过name属性定义这个父节点的名称
package com.zte.sunquan.jaxb;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
/**
* Created by xxx on 2017/10/20.
*/
@XmlRootElement(name = "person")
public class Person {
@XmlAttribute(name = "name")
public String name;
@XmlAttribute(name = "age")
public int age;
public Person() {
}
private List<String> hobby=new ArrayList<>();
public Person(String name) {
this.name = name;
}
@XmlElementWrapper(name = "hobbys")
@XmlElement(name = "hobby")
public List<String> getHobby() {
return hobby;
}
public void addHobby(String hobby) {
this.hobby.add(hobby);
}
}
上面的Bean,对于无参构造函数显示增加了定义
在源码com.sun.xml.bind.v2.model.impl.ClassInfoImpl.java构造函数中,会对类是否有默认构造函数进行校验
// the class must have the default constructor
if (!hasFactoryConstructor(t)){
if(!nav().hasDefaultConstructor(clazz)){
if(nav().isInnerClass(clazz)) {
builder.reportError(new IllegalAnnotationException(
Messages.CANT_HANDLE_INNER_CLASS.format(nav().getClassName(clazz)), this ));
} else if (elementName != null) {
builder.reportError(new IllegalAnnotationException(
Messages.NO_DEFAULT_CONSTRUCTOR.format(nav().getClassName(clazz)), this ));
}
}
}
测试脚本:
package com.zte.sunquan.jaxb;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.dom.DOMResult;
import java.io.StringReader;
import java.io.StringWriter;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
/**
* Created by xxx on 2017/10/20.
*/
public class PersonTest {
private Person person;
int age = 29;
String name = "Foo";
String hobby = "singing";
@Before
public void init() {
person = new Person("xy");
person.name = name;
person.age = age;
person.addHobby(hobby);
}
@Test
public void testMarshallerDocument() throws JAXBException {
JAXBContext context = JAXBContext.newInstance(person.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);//格式化xml输出
DOMResult res = new DOMResult();
marshaller.marshal(person, res);
Element doc = ((Document) res.getNode()).getDocumentElement();
assertEquals(name, doc.getAttribute("name"));
assertEquals(age, Integer.parseInt(doc.getAttribute("age")));
//((Document) res.getNode()).getDocumentElement()
NodeList hobbys = doc.getChildNodes();
assertEquals(hobby, hobbys.item(0).getTextContent());
}
@Test
public void testMarshallerString() throws JAXBException {
JAXBContext context = JAXBContext.newInstance(person.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);//格式化xml输出
StringWriter writer = new StringWriter();
marshaller.marshal(person, writer);
String outString = writer.toString();
System.out.println(outString);
assertTrue(outString.contains("</person"));
}
@Test
public void testUnMarshaller() throws JAXBException {
String outString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<person name=\"Foo\" age=\"29\">\n" +
" <hobbys>\n" +
" <hobby>singing</hobby>\n" +
" </hobbys>\n" +
"</person>";
JAXBContext context = JAXBContext.newInstance(Person.class, Person.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader reader = new StringReader(outString);
Person reciever = (Person) unmarshaller.unmarshal(reader);
assertEquals(name, reciever.name);
assertEquals(age, reciever.age);
assertEquals(hobby, reciever.getHobby().get(0));
}
}