如何使用Jackson从扁平的XML结构中读取复杂的POJO?

时间:2016-08-11 17:32:32

标签: java xml jackson

我有一些内存数据结构,我从XML文件加载,并希望公开简化的API,而不将XML或任何数据结构用户绑定到实现细节。我使用Jackson进行XML解组。

数据结构

正如您在代码中看到的那样,Profile类包含User的实例,但直接公开User字段的getter / setter。我不想拥有setUser(User)/ getUser(),因为我希望从公共API中隐藏该实现细节。

Profile.java:

package com.example.data;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "profile")
public class Profile {
    private User user;
    private String email;

    @XmlElement(name = "userID")
    public String getUserID() {
        return user.getUserID();
    }

    @XmlElement(name = "userID")
    public void setUserID(String userID) {
        user.setUserID(userID);
    }

    @XmlElement(name = "password")
    public String getPassword() {
        return user.getPassword();
    }

    @XmlElement(name = "password")
    public void setPassword(String password) {
        user.setPassword(password);
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

User.java:

package com.example.data;

public class User {
    public String userID;
    public String password;

    public String getUserID() {
        return userID;
    }

    public void setUserID(String userID) {
        this.userID = userID;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

正如您所看到的,我尝试在getter和setter上添加@XmlElement JAXB注释,但没有成功。我也试过@JacksonXmlProperty,但也没有运气。

数据

我也不想将<userID><password>包裹在<user>标记中;我希望XMl平坦,如下所示。

是profile.xml:

<?xml version="1.0" encoding="UTF-8"?>
<profile>
    <userID>bob</userID>
    <password>letmein</password>
    <email>bob@example.com</email>
</profile>

应用

JacksonXMLExample.java:

package com.example;

import java.io.File;
import java.io.IOException;

import com.example.data.Profile;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;

public class JacksonXMLExample {

    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        File file = new File("src/main/resources/profile.xml");

        ObjectMapper mapper = new XmlMapper();
        JaxbAnnotationModule module = new JaxbAnnotationModule();
        mapper.registerModule(module);
        Profile profile = mapper.readValue(file, Profile.class);

        System.out.println(profile);
    }

}

的Maven

的pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>JacksonXMLExample</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>javax.xml</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.7.4</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.4</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-xml-provider</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jaxb-annotations</artifactId>
            <version>2.7.4</version>
        </dependency>
    </dependencies>
</project>

问题

当我尝试执行上面的代码时,我得到以下异常:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: N/A
 at [Source: src\main\resources\profile.xml; line: 3, column: 13] (through reference chain: com.example.data.Profile["userID"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:262)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:537)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:518)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:260)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3807)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2691)
    at com.example.JacksonXMLExample.main(JacksonXMLExample.java:21)
Caused by: java.lang.NullPointerException
    at com.example.data.Profile.setUserID(Profile.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:97)
    ... 5 more

如何使用由其他POJO组成的复杂POJO而不必在相应的XML中镜像该结构或向该类用户公开实现细节?

1 个答案:

答案 0 :(得分:1)

当我准备发布我的问题时,当我意识到我需要的只是初始化Profile.java中的user字段时,我有一个facepalm时刻:

private User user = new User();

这是必要的,因为当然,您不能将方法调用委托给尚未初始化的成员。