Contents

Jackson中XML序列化

1. 概述

在本教程中,我们将学习如何使用 Jackson 2.x 将 Java 对象序列化为 XML 数据,并将它们反序列化回 POJO。 我们将专注于不需要大量复杂性或定制的基本操作。

2. XmlMapper对象

XmlMapper是 Jackson 2.x 中帮助我们进行序列化的主要类,因此我们需要创建它的一个实例:

XmlMapper mapper = new XmlMapper();

映射器jackson-dataformat-xml jar 中可用,因此我们必须将其作为依赖项添加到我们的pom.xml中:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.11.1</version>
</dependency>

请检查Maven 存储库中最新版本的jackson-dataformat-xml 依赖项。

3. 将Java序列化为XML

XmlMapperObjectMapper的子类,用于 JSON 序列化;但是,它向父类添加了一些特定于 XML 的调整。 让我们看看如何使用它来进行实际的序列化。我们先创建一个Java类:

class SimpleBean {
    private int x = 1;
    private int y = 2;
    
    //standard setters and getters
}

3.1. 序列化为 XML String

我们可以将我们的 Java 对象序列化为 XML String

@Test
public void whenJavaSerializedToXmlStr_thenCorrect() throws JsonProcessingException {
    XmlMapper xmlMapper = new XmlMapper();
    String xml = xmlMapper.writeValueAsString(new SimpleBean());
    assertNotNull(xml);
}

结果,我们将得到:

<SimpleBean>
    <x>1</x>
    <y>2</y>
</SimpleBean>

3.2. 序列化为 XML 文件

我们还可以将我们的 Java 对象序列化为 XML 文件:

@Test
public void whenJavaSerializedToXmlFile_thenCorrect() throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.writeValue(new File("simple_bean.xml"), new SimpleBean());
    File file = new File("simple_bean.xml");
    assertNotNull(file);
}

下面我们可以看到名为 simple_bean.xml的生成文件的内容:

<SimpleBean>
    <x>1</x>
    <y>2</y>
</SimpleBean>

4. 将 XML 反序列化为 Java

在本节中,我们将了解如何从 XML 中获取 Java 对象。

4.1. 从 XML 字符串反序列化

与序列化一样,我们也可以将 XML 字符串反序列化回 Java 对象:

@Test
public void whenJavaGotFromXmlStr_thenCorrect() throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    SimpleBean value
      = xmlMapper.readValue("<SimpleBean><x>1</x><y>2</y></SimpleBean>", SimpleBean.class);
    assertTrue(value.getX() == 1 && value.getY() == 2);
}

4.2. 从 XML 文件反序列化

同样,如果我们有一个 XML 文件,我们可以将它转换回 Java 对象。 在这里,我们首先将文件读入输入流,然后通过简单的实用方法将输入流转换为string

其余代码与第 4.1 节中的代码类似:

@Test
public void whenJavaGotFromXmlFile_thenCorrect() throws IOException {
    File file = new File("simple_bean.xml");
    XmlMapper xmlMapper = new XmlMapper();
    String xml = inputStreamToString(new FileInputStream(file));
    SimpleBean value = xmlMapper.readValue(xml, SimpleBean.class);
    assertTrue(value.getX() == 1 && value.getY() == 2);
}

这是实用方法:

public String inputStreamToString(InputStream is) throws IOException {
    StringBuilder sb = new StringBuilder();
    String line;
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    while ((line = br.readLine()) != null) {
        sb.append(line);
    }
    br.close();
    return sb.toString();
}

5. 处理大写的元素

在本节中,我们将讨论如何处理具有要反序列化的大写元素的 XML 或需要将 Java 对象序列化为具有一个或多个大写元素的 XML 的场景。

5.1. 从 XML string反序列化

假设我们有一个包含一个大写字段的 XML:

<SimpleBeanForCapitalizedFields>
    <X>1</X>
    <y>2</y>
</SimpleBeanForCapitalizedFields>

为了正确处理大写元素,我们需要使用 @JsonProperty注解来注释“x”字段:

class SimpleBeanForCapitalizedFields {
    @JsonProperty("X")
    private int x = 1;
    private int y = 2;
    // standard getters, setters
}

我们现在可以正确地将 XMLstring反序列化回 Java 对象:

@Test
public void whenJavaGotFromXmlStrWithCapitalElem_thenCorrect() throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    SimpleBeanForCapitalizedFields value
      = xmlMapper.readValue(
      "<SimpleBeanForCapitalizedFields><X>1</X><y>2</y></SimpleBeanForCapitalizedFields>",
      SimpleBeanForCapitalizedFields.class);
    assertTrue(value.getX() == 1 && value.getY() == 2);
}

5.2. 序列化为 XML 字符串

通过使用*@JsonProperty*注解所需的字段,我们可以正确地将 Java 对象序列化为具有一个或多个大写元素的 XML字符串:

@Test
public void whenJavaSerializedToXmlFileWithCapitalizedField_thenCorrect()
  throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.writeValue(new File("target/simple_bean_capitalized.xml"),
      new SimpleBeanForCapitalizedFields());
    File file = new File("target/simple_bean_capitalized.xml");
    assertNotNull(file);
}

6. 将List序列化为XML

XmlMapper能够将 整个Java bean 序列化为一个文档。要将 Java 对象转换为 XML,我们将举一个包含嵌套对象和数组的简单示例。

我们的目的是将Person对象及其组合的Address对象序列化为 XML。 我们最终的 XML 将类似于:

<Person>
    <firstName>Rohan</firstName>
    <lastName>Daye</lastName>
    <phoneNumbers>
        <phoneNumbers>9911034731</phoneNumbers>
        <phoneNumbers>9911033478</phoneNumbers>
    </phoneNumbers>
    <address>
        <streetName>Name1</streetName>
        <city>City1</city>
    </address>
    <address>
        <streetName>Name2</streetName>
        <city>City2</city>
    </address>
</Person>

请注意,我们的电话号码被封装在phoneNumbers包装器中,而我们的地址不是。 我们可以通过Person类中的*@JacksonXMLElementWrapper*注解来表达这种细微差别:

public final class Person {
    private String firstName;
    private String lastName;
    private List<String> phoneNumbers = new ArrayList<>();
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Address> address = new ArrayList<>();
    //standard setters and getters
}

事实上,我们可以使用*@JacksonXmlElementWrapper(localName = ‘phoneNumbers’)* 来更改包装元素的名称。或者,如果我们不想包装我们的元素,我们可以使用*@JacksonXmlElementWrapper(useWrapping = false)禁用映射。 然后我们将定义我们的Address*类型:

public class Address {
    String streetName;
    String city;
    //standard setters and getters
}

**Jackson会为我们处理剩下的事情。**和以前一样,我们可以简单地再次调用 writeValue

private static final String XML = "<Person>...</Person>";
@Test
public void whenJavaSerializedToXmlFile_thenSuccess() throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    Person person = testPerson(); // test data
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    xmlMapper.writeValue(byteArrayOutputStream, person); 
    assertEquals(XML, byteArrayOutputStream.toString()); 
}

7. 将 XML 反序列化为List

Jackson 也可以读取包含对象列表的 XML。 如果我们使用与以前相同的 XML,readValue方法就可以了:

@Test
public void whenJavaDeserializedFromXmlFile_thenCorrect() throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    Person value = xmlMapper.readValue(XML, Person.class);
    assertEquals("City1", value.getAddress().get(0).getCity());
    assertEquals("City2", value.getAddress().get(1).getCity());
}