介绍
我重新发现了Java提供给大众的库。 当我第一次阅读该规范时,我很困惑,以为我需要所有这些特殊工具来实现。 我最近发现,只需要一些注释和一个POJO。
杰克斯
JAXB代表XML绑定的Java体系结构。 这种体系结构允许开发人员将来自类的数据转换为XML表示形式。 这称为编组。 该体系结构还允许开发人员逆转将XML表示转换为类的过程。 这称为解组。 有一些工具可以从XML Schema文件创建Java类。 该工具称为xjc。 还有另一种使用schemagen创建xsd文件的工具。
编组
编组和解组在Java中发生了很多地方。 我首先接触到的是RMI。 对象被发送用作远程方法调用的参数,因此名称为“远程方法调用(RMI)”。 它发生的另一个地方是将对象写入流。 实现此功能的流是ObjectOutputStream和ObjectInputStream。 发生的另一个地方是ORM类。 当然,另一种方式是编写实例的XML表示。 想要编组的类需要实现Serializable,并且其所有成员属性也都需要实现Serializable,但通过JAXB的类除外。 可序列化是标记接口。 它没有实现的方法,但是它表明可以对类进行序列化或编组。 被编组的对象的数据已采用某种持久化方式。 未编组对象的数据已从持久状态读取并与类连接。 这使得类路径非常重要。 有趣的是,类路径中的有效条目是http:// ip:port / path / to / jar 。 我想有些组织可以通过集中化jar文件来使用此功能,而最新版本仅需下载即可。
例
我用maven和spring来做这个例子。 原因不是使它更加复杂,而是使代码更清晰地阅读和更专注于使用我所展示的技术。 pom.xml文件中的依赖项如下:
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.2.8-b01</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>3.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>3.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>3.2.3.RELEASE</version></dependency></dependencies>
JAXB的妙处在于它使用POJO。 Contact.java是三个集合中的中心POJO类。
package org.mathison.jaxb.beans;import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Contact {private String lastName;private String firstName;private String middleName;private String jobTitle;@XmlElementWrapper(name = "addresses")@XmlElement(name = "address")private List<Address> addresses;@XmlElementWrapper(name = "phone-numbers")@XmlElement(name = "phone-number")private List<PhoneNumber> numbers;public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getMiddleName() {return middleName;}public void setMiddleName(String middleName) {this.middleName = middleName;}public String getJobTitle() {return jobTitle;}public void setJobTitle(String jobTitle) {this.jobTitle = jobTitle;}public List<Address> getAddresses() {return addresses;}public void setAddresses(List<Address> addresses) {this.addresses = addresses;}public List<PhoneNumber> getNumbers() {return numbers;}public void setNumbers(List<PhoneNumber> numbers) {this.numbers = numbers;}@Overridepublic String toString() {return "Contact{" + "lastName=" + lastName + ", firstName=" + firstName + ", middleName=" + middleName + ", jobTitle=" + jobTitle + ", addresses=" + addresses + ", numbers=" + numbers + '}';}@Overridepublic int hashCode() {int hash = 3;hash = 23 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);hash = 23 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);hash = 23 * hash + (this.middleName != null ? this.middleName.hashCode() : 0);hash = 23 * hash + (this.jobTitle != null ? this.jobTitle.hashCode() : 0);hash = 23 * hash + (this.addresses != null ? this.addresses.hashCode() : 0);hash = 23 * hash + (this.numbers != null ?this.numbers.hashCode() : 0);return hash;}@Overridepublic boolean equals(Object obj) {if (obj == null) {return false;}if (getClass() != obj.getClass()) {return false;}final Contact other = (Contact) obj;if ((this.lastName == null) ? (other.lastName != null) :!this.lastName.equals(other.lastName)) {return false;}if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName)) {return false;}if ((this.middleName == null) ? (other.middleName != null) : !this.middleName.equals(other.middleName)) {return false;}if ((this.jobTitle == null) ? (other.jobTitle != null) : !this.jobTitle.equals(other.jobTitle)) {return false;}if(!listEquals(this.addresses, other.addresses)) {return false;}if(!listEquals(this.numbers, other.numbers)) {return false;}return true;}private boolean listEquals(List first, List second) {for(Object o: first) {if(!second.contains(o)) {return false;}}return true;}}
要看的主要部分是注释。 @XmlRootElement定义这是一个类的开始。 @XmlAccessorType(XmlAccessType.FIELD)告诉体系结构,这些字段将用于定义xml中的元素。 注释也可以放在吸气剂上。 如果未使用注释,则JAXB会混淆使用哪个注释。 对于存在列表的实例,@XmlElementWrapper用来告诉JAXB外部标签将是什么。 例如,有一个地址列表。 包装器采用名为“ name”的参数,并用“ addresss”填充。 呈现XML时,将在地址集合周围包裹标签“ addresses”。 如果要更改属性的标记,则使用@XmlElement批注。 回到我们的地址列表,注释将地址列表重新定义为“ address”。 这将导致每个地址对象都具有“地址”标签,而不是已经占用的“地址”标签。 数字使用相同的模式。 其余的属性将具有与它们的名称匹配的标签。 例如,lastName将变成标签“ lastName”。 其他两个POJO(电话号码.java和地址.java)具有公共枚举类。 这是PhoneNumber.java:
package org.mathison.jaxb.beans;import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;@XmlRootElement
public class PhoneNumber {@XmlType(name="phone-type")public enum Type {HOME,WORK,HOME_FAX,WORK_FAX;}private Type type;private String number;public Type getType() {return type;}public void setType(Type type) {this.type = type;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number;}@Overridepublic String toString() {return "PhoneNumber{" + "type=" + type + ", number=" + number + '}';}@Overridepublic int hashCode() {int hash = 7;hash = 37 * hash + (this.type != null ? this.type.hashCode() : 0);hash = 37 * hash + (this.number != null ? this.number.hashCode() : 0);return hash;}@Overridepublic boolean equals(Object obj) {if (obj == null) {return false;}if (getClass() != obj.getClass()) {return false;}final PhoneNumber other = (PhoneNumber) obj;if (this.type != other.type) {return false;}if ((this.number == null) ? (other.number != null) : !this.number.equals(other.number)) {return false;}return true;}}
注释的注释为@XmlType。 这告诉JAXB一类有限数量的值。 它带有一个名称参数。 最后一个POJO还使用@XmlType定义其公共枚举类。 可以在Address.java中找到它。
全部放在一起
有了所有这些注释和类定义,是时候将所有这些放到一个主类中了。 这是App.java,主要类:
package org.mathison.jaxb.app;import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.mathison.jaxb.beans.Contact;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;public class App
{public static void main( String[] args ){ApplicationContext cxt = new GenericXmlApplicationContext("jaxb.xml");Contact contact = cxt.getBean("contact", Contact.class);StringWriter writer = new StringWriter();try {JAXBContext context = JAXBContext.newInstance(Contact.class);//create xml from an instance from ContactMarshaller m = context.createMarshaller();m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);m.marshal(contact, writer);String xml = writer.getBuffer().toString();System.out.println(xml);//Take xml to ContactStringReader reader = new StringReader(xml);Unmarshaller u = context.createUnmarshaller();Contact fromXml = (Contact)u.unmarshal(reader);System.out.println("Are the instances equivalent: " + contact.equals(fromXml));} catch(Exception e){e.printStackTrace();}}
}
首先,从ApplicationContext检索联系人实例。 其次,以Contact类作为根类创建JAXBContext实例。 上下文将分析类结构,并创建可以封送或拆封Contact,Address和PhoneNumber类的上下文。 在下一部分中,从JAXBContext创建一个编组器。 Marshaller.JAXB_FORMATTED_OUTPUT属性设置为true。 这将创建一个格式化的XML输出。 如果未设置该属性,则XML将作为一行文本出现。 调用编组器进行编组联系并将其写入StringWriter。 然后将XML打印到System.out。 输出应如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact><lastName>Mathison</lastName><firstName>Daryl</firstName><middleName>Bob</middleName><jobTitle>Developer</jobTitle><addresses><address><addressLine>123 Willow View</addressLine><city>Cibolo</city><state>TX</state><type>HOME</type><zipCode>78228</zipCode></address><address><addressLine>411 Grieg</addressLine><city>San Antonio</city><state>TX</state><type>WORK</type><zipCode>78228</zipCode></address></addresses><phone-numbers><phone-number><number>210-123-4567</number><type>WORK</type></phone-number><phone-number><number>210-345-1111</number><type>HOME</type></phone-number></phone-numbers></contact>
在下一部分中,将xml与其数据一起解组到Contact实例中。 Unmarshaller由JAXBContext创建。 接下来,解组器将传递一个StringReader,其内容为刚刚创建的XML。 解组器返回一个对象,该对象被强制转换为联系人。 将针对新的Contact实例测试Contact的原始实例,以查看它们是否等效。 输出应显示:
Are the instances equivalent: true.
摘要
在此示例中,Contact的实例被转换为XML,并且在JAXB的帮助下,所得的XML被转换回Contact实例。 JAXB是一种将对象的状态映射到XML并将XML映射回对象的体系结构。
参考文献
- http://www.techrepublic.com/blog/programming-and-development/jaxb-20-offers-improved-xml-binding-in-java/498
- http://www.vogella.com/articles/JAXB/article.html
- http://en.wikipedia.org/wiki/JAXB
翻译自: https://www.javacodegeeks.com/2014/10/the-jaxb-well-known-secret.html