Jackson XmlMapper 读取 XML 文档但产生空值

问题描述

Java 1.8

Maven 代码段:

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

snipped.xml

<?xml version="1.0" standalone="no"?>
<ledesxml_snipped>
  <lede_name>Fitzhume</lede_name>
  <firm>
    <lf_tax_id>999999999</lf_tax_id>
    <lf_id>Cogswell Cogs</lf_id>
    <lf_name>Cogswell Cogs,Inc.</lf_name>
    <lf_address>
      <address_info>
        <address_1>404 Asteroid Drive</address_1>
        <address_3>Suite 2600</address_3>
        <city>Dallas</city>
        <state_province>TX</state_province>
        <zip_postal_code>75203</zip_postal_code>
        <country>USA</country>
      </address_info>
    </lf_address>
    <lf_billing_contact_phone>2145551212</lf_billing_contact_phone>
    <lf_billing_contact_fax>2148761234</lf_billing_contact_fax>
    <lf_billing_contact_email>bigcog@cogswellcogs.com</lf_billing_contact_email>
    <source_app>aimPoint</source_app>
    <app_version>
    </app_version>
  </firm>
</ledesxml_snipped>

LedesSnipped.java

package com.my.application.model;

import java.io.*;
import java.util.*;

import javax.xml.bind.annotation.*;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;

@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(name = "",propOrder = {
    "ledeName","firm"
})
@XmlRootElement(name = "ledesxml_snipped")
public class LedesxmlSnipped {
    @XmlElement(name = "lede_name",required = true)
    protected String ledeName;
    @XmlElement(required = true)
    @JacksonXmlElementWrapper( useWrapping = false)
    protected LedesxmlSnipped.Firm firm;
    
    public String getLedeName() {
        return ledeName;
    }
    
    public void setLedname( String ledeName) {
        this.ledeName = ledeName;
    }

    public LedesxmlSnipped.Firm getFirm() {
        return firm;
    }

    public void setFirm(LedesxmlSnipped.Firm value) {
        this.firm = value;
    }
    
    @XmlAccessorType(XmlAccesstype.FIELD)
    @XmlType(name = "",propOrder = {
        "lfTaxId","lfId","lfName","lfAddress","lfBillingContactPhone","lfBillingContactFax","lfBillingContactEmail","sourceApp","appVersion"
    })
    public static class Firm {

        @XmlElement(name = "lf_tax_id")
        protected int lfTaxId;
        @XmlElement(name = "lf_id",required = true)
        protected String lfId;
        @XmlElement(name = "lf_name",required = true)
        protected String lfName;
        @XmlElement(name = "lf_address",required = true)
        @JacksonXmlElementWrapper( useWrapping = false)
        protected Ledesxml.Firm.LfAddress lfAddress;
        @XmlElement(name = "lf_billing_contact_phone")
        protected long lfBillingContactPhone;
        @XmlElement(name = "lf_billing_contact_fax")
        protected long lfBillingContactFax;
        @XmlElement(name = "lf_billing_contact_email",required = true)
        protected String lfBillingContactEmail;
        @XmlElement(name = "source_app",required = true)
        protected String sourceApp;
        @XmlElement(name = "app_version",required = true)
        protected String appVersion;

        public int getLfTaxId() {
            return lfTaxId;
        }

        public void setLfTaxId(int value) {
            this.lfTaxId = value;
        }

        public String getLfId() {
            return lfId;
        }

        public void setLfId(String value) {
            this.lfId = value;
        }

        public String getLfName() {
            return lfName;
        }

        public void setLfName(String value) {
            this.lfName = value;
        }

        public Ledesxml.Firm.LfAddress getLfAddress() {
            return lfAddress;
        }

        public void setLfAddress(Ledesxml.Firm.LfAddress value) {
            this.lfAddress = value;
        }

        public long getLfBillingContactPhone() {
            return lfBillingContactPhone;
        }

        public void setLfBillingContactPhone(long value) {
            this.lfBillingContactPhone = value;
        }

        public long getLfBillingContactFax() {
            return lfBillingContactFax;
        }

        public void setLfBillingContactFax(long value) {
            this.lfBillingContactFax = value;
        }

        public String getLfBillingContactEmail() {
            return lfBillingContactEmail;
        }

        public void setLfBillingContactEmail(String value) {
            this.lfBillingContactEmail = value;
        }

        public String getSourceApp() {
            return sourceApp;
        }

        public void setSourceApp(String value) {
            this.sourceApp = value;
        }

        public String getAppVersion() {
            return appVersion;
        }

        public void setAppVersion(String value) {
            this.appVersion = value;
        }

        @XmlAccessorType(XmlAccesstype.FIELD)
        @XmlType(name = "",propOrder = {
            "addressInfo"
        })
        public static class LfAddress {

            @XmlElement(name = "address_info",required = true)
            protected Ledesxml.Firm.LfAddress.AddressInfo addressInfo;

            public Ledesxml.Firm.LfAddress.AddressInfo getAddressInfo() {
                return addressInfo;
            }

            public void setAddressInfo(Ledesxml.Firm.LfAddress.AddressInfo value) {
                this.addressInfo = value;
            }
            
            @XmlAccessorType(XmlAccesstype.FIELD)
            @XmlType(name = "",propOrder = {
                "address1","address3","city","stateProvince","zipPostalCode","country"
            })
            public static class AddressInfo {

                @XmlElement(name = "address_1",required = true)
                protected String address1;
                @XmlElement(name = "address_3",required = true)
                protected String address3;
                @XmlElement(required = true)
                protected String city;
                @XmlElement(name = "state_province",required = true)
                protected String stateProvince;
                @XmlElement(name = "zip_postal_code")
                protected int zipPostalCode;
                @XmlElement(required = true)
                protected String country;

                public String getAddress1() {
                    return address1;
                }

                public void setAddress1(String value) {
                    this.address1 = value;
                }

                public String getAddress3() {
                    return address3;
                }

                public void setAddress3(String value) {
                    this.address3 = value;
                }

                public String getCity() {
                    return city;
                }

                public void setCity(String value) {
                    this.city = value;
                }

                public String getStateProvince() {
                    return stateProvince;
                }

                public void setStateProvince(String value) {
                    this.stateProvince = value;
                }

                public int getZipPostalCode() {
                    return zipPostalCode;
                }

                public void setZipPostalCode(int value) {
                    this.zipPostalCode = value;
                }

                public String getCountry() {
                    return country;
                }

                public void setCountry(String value) {
                    this.country = value;
                } 
            }
        }
    }
}

最后,TryThis.java

package com.my.application;

import java.util.*;
import java.io.*;

import java.time.*;
import java.time.format.*;

import javax.xml.stream.*;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.xml.*;

import com.my.application.model.*;

public class TryThis {

    public static void main(String[] args) {
        XmlMapper mapper = new XmlMapper();
        mapper.enable( SerializationFeature.INDENT_OUTPUT);
        mapper.disable( DeserializationFeature.FAIL_ON_UNKNowN_PROPERTIES);
    
        try {
            File innFile = new File("snipped.xml");
            LedesxmlSnipped asfda = mapper.readValue(innFile,LedesxmlSnipped.class);
            System.out.println( "ledeName=" + asfda.getFirm().getLedeName());
        } catch (JsonParseException e) {
            // Todo Auto-generated catch block
            e.printstacktrace();
        } catch (JsonMappingException e) {
            // Todo Auto-generated catch block
            e.printstacktrace();
        } catch (FileNotFoundException e1) {
            // Todo Auto-generated catch block
            e1.printstacktrace();
        } catch (IOException e) {
            // Todo Auto-generated catch block
            e.printstacktrace();
        }
    }
}

这一切的结果只是

ledeName=null

我希望看到的地方

ledeName=Fitzhume

没有错误。那么我错过了什么?一些极其微妙的配置?我是否在错误的地方定义了 XmlMapper?我看过的许多示例涵盖了 Jackson 的各种版本,有些还使用 javax.xml。

解决方法

简单添加

import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;

mapper.registerModule( new JaxbAnnotationModule());

TryThis.java 做到了。确实是非常微妙的配置问题!

感谢所有阅读问题的人。