现在,XML文件中的数据本质上趋于分层。 例如,考虑以下XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<firstname>Barok</firstname>
<lastname>Obama</lastname>
<age>52</age>
<car>
<model>Green Ford Focus 1.4L</model>
</car>
</person>
在这种情况下,Barok Obama人拥有的汽车是Green Ford Focus。 在这里,我们看到了XML的层次结构特征。 车在人下。 在一个更复杂的示例中,一个人可以拥有一个汽车,该汽车具有一个汽车收音机,该汽车具有一个放大器,该汽车具有晶体管等。但是,让我们暂时坚持我们的简单情况。 假设我们要使用JAXB解组该XML文件。 我们需要所有人的详细信息(名字,姓氏等)以及属于该人的汽车的型号。 我们创建一个Person POJO和一个Car POJO并进行适当的注释。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "firstname", "lastname"})
public class Person {
private String firstname;
private String lastname;
private int age;
private Car car;
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String name) {
this.firstname = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car){
this.car= car;
}
}
public class Car {
private String model;
public String getModel() {
return model;
}
public void setModel(String model){
this.model = model;
}
}
要解组,我们只需做
public static void unmarshall() throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Person person = (Person)unmarshaller.unmarshal(new File("Person.xml"));
System.out.println("Perosn is=" +person.toString());
}
这一切看起来非常简单-特别是当您考虑到Car实体甚至不需要任何注释时! 但是,Car仅具有一个属性,对于我们只希望从中获得一个属性的东西拥有POJO类似乎有点过头了! 记住,这是一个简单的示例,想象一下层次结构是否更深。 类似于包含实体的外部实体,其中包含另一个实体,该实体甚至包含另一个实体,而我们所需的只是外部实体和来自最深层嵌套实体的一个属性。 本质上是相同的问题,但更多的是矫kill过正。 我们必须确保层次结构中的所有内容都有POJO类,甚至对于我们一无所求的实体也是如此。 没有人喜欢代码膨胀。 所以,我们能做些什么?
我们首先要记住的是,JAXB是一个规范,该规范有许多实现(例如JaxMeAPI,MOXy,Metro)。 如果我们要使用JAXB参考实现(随JDK一起提供,则无能为力)。 我们必须有一个汽车和人POJO。 但是,如果我们使用EclipseLink的MOXy实现,则可以使用其一些扩展来帮助我们。 更具体地说,我们可以使用受XPath启发的MOXy @XmlPath扩展。
让我们来看看它的作用。 这是更新的Person POJO。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "firstname", "lastname"})
public class Person {
private String firstname;
private String lastname;
private int age;
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String name) {
this.firstname = name;
}
@XmlPath("car/model/text()")
private String model;
public String getModel() {
return model;
}
}
那么,汽车POJO哪里去了? 好吧,它被删除了。 我们不再需要它了。 再见。
使用MOXy @XmlPath批注,我们不需要Car POJO。 该批注驻留在org.eclipse.persistence.oxm.annotations包中,将其放在类路径中非常简单。 如果您是maven用户,只需添加:
<dependency>
<groupid>org.eclipse.persistence</groupId>
<artifactid>eclipselink</artifactId>
<version>2.3.2</version>
</dependency>
为了告诉您的JDK在运行时将MOXy用于JAXB实现,您放置了一个名为
jaxb.properties与JAXB POJO位于同一目录中。 它包含一行:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
为了确保您正在使用MOXy实现,只需检查JAXB上下文:
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
System.out.println("jaxbContext is=" +jaxbContext.toString());
您应该看到类似以下内容:
jaxbContext is=org.eclipse.persistence.jaxb.JAXBContext@5e3974
之后,没有任何变化。 完全相同的数据编码都可以使用。
我之所以真正喜欢此扩展的原因之一是因为它意味着更少的代码。 这通常意味着更简洁的代码和更多可维护的代码。 这在更复杂的情况下变得更加明显,在这种情况下,实体的层次结构比该简单示例要深得多。 如果使用XJC之类的东西来生成POJO没关系,您仍然会感到代码膨胀。
请记住,JAXB被设置为比JAXP替代品(例如SAX和DOM)更简洁的编程模型,但是在具有深层次结构的场景中,使用JAXB对类进行概要分析并不能使它令人信服地更加简洁。 请记住,使用DOM和XPath甚至仅使用SAX来忽略不需要的类将非常容易。
MOXy通过提供对XML文件中的任何内容使用XPath表达式的功能,将清洁的战斗带回了JAXB。
注意:MOXy刚刚作为WebLogic 12c的JAXB实现包含在内。
参考文献:
- MOXy项目页面
- Blaise Doughan的博客
- 来自都柏林技术博客的 JCG合作伙伴 Alex Staveley 通过MOXy实现使JAXB清洁器
相关文章 :
翻译自: https://www.javacodegeeks.com/2012/01/make-your-jaxb-cleaner-with-moxy.html