我重新发现了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;
}
@Override
public String toString() {
return "Contact{" + "lastName=" + lastName + ", firstName="
+ firstName + ", middleName=" + middleName
+ ", jobTitle=" + jobTitle + ", addresses="
+ addresses + ", numbers=" + numbers + '}';
}
@Override
public 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;
}
@Override
public 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;
}
@Override
public String toString() {
return "PhoneNumber{" + "type=" + type + ", number=" + number + '}';
}
@Override
public 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;
}
@Override
public 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 Contact
Marshaller 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 Contact
StringReader 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