使用JAXB对XML元素进行绑定会返回NullPointerException

时间:2017-06-01 05:52:28

标签: java soap jaxb unmarshalling

我遇到的问题是类与XML元素的绑定不成功。相反,它返回NullPointerException。下面是示例XML

    <?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sh="http://www.w3.org/2001/XMLSchema-instance">
    <SOAP-ENV:Body>
        <ns:getNumberResponse
            xmlns="http://ccm.intra.bt.com/manageServiceFault/2006/06" xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:cds="http://capabilities.nat.bt.com/xsd/manageServiceFault/2010/06/Contact/Details"
            xmlns:sh="http://wsi.nat.bt.com/2005/06/StandardHeader/"
            xsi:schemaLocation="http://ccm.intra.bt.com/manageServiceFault/2006/06 MSF_5.0.xsd">
            <sh:standardHeader>
                <sh:e2e>
                    <sh:E2EDATA>E2E.graphID=2.1,E2E.from=ORESB,E2E.to=ORautofix,E2E.compTxnName=FaultProcessing,E2E.compTxnID=385h6g8lbh,E2E.busTxnStage=REQ,E2E.busProcID=1-CKMT1EEV,E2E.busProcType=ManageFaultRequests,E2E.busTxnSeq=385h5smgod,E2E.threadID=385h6g8koz,E2E.busTxnSys=AddFault,tradingPartnerId=735380615,E2E.busTxnHdr=PCK002069,E2E.busTxnType=AddFault,E2E.busProcOriginator=ORESB-default,E2E.busTxnUsr=siebel,E2E.busTxnLoc=UNKNOWN,E2E.threadID.4=APP10639:385h6g75io:385h6g8koz,E2E.threadID.3=:385h6fq4wv,E2E.threadID.2=ORSiebel:385h5smh48:385h6fq4wv,E2E.threadID.1=:
                    </sh:E2EDATA>
                </sh:e2e>
                <sh:serviceState>
                    <sh:stateCode>OK</sh:stateCode>
                    <sh:errorCode />
                    <sh:errorDesc />
                    <sh:errorText />
                    <sh:errorTrace />
                </sh:serviceState>
            </sh:standardHeader>
            <actionRequestId />
            <appointment>
                <apptRequired>Y</apptRequired>
                <apptSlot>0</apptSlot>
                <apptType>Type</apptType>
                <apptReference>Reference001</apptReference>
                <earliestApptSlot>1</earliestApptSlot>
                <earliestDate>2015-05-25T01:00:00</earliestDate>
            </appointment>
            <endUserDetails>
                <firstName>Chris</firstName>
                <lastName>Wong</lastName>
                <priTelephone>+60123333333</priTelephone>
                <secTelephone>+60123333334</secTelephone>
                <cssDBID>1234</cssDBID>
            </endUserDetails>
            <serviceAffectingFlag>N</serviceAffectingFlag>
            <number>123456789</number>
            <service>
                <serviceId xsi:nil="false">ONEA20160721_0067</serviceId>
            </service>
            <service>
                <serviceId xsi:nil="false">ONEA20160721_0068</serviceId>
            </service>
        </ns:getNumberResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

以下是我的域类:UserDetail

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "endUserDetails")
@XmlAccessorType(XmlAccessType.FIELD)
public class UserDetail {

    private String firstName;
    private String lastName;
    private String priTelephone;
    private String secTelephone;
    private String cssDBID;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPriTelephone() {
        return priTelephone;
    }

    public void setPriTelephone(String priTelephone) {
        this.priTelephone = priTelephone;
    }

    public String getSecTelephone() {
        return secTelephone;
    }

    public void setSecTelephone(String secTelephone) {
        this.secTelephone = secTelephone;
    }

    public String getCssDBID() {
        return cssDBID;
    }

    public void setCssDBID(String cssDBID) {
        this.cssDBID = cssDBID;
    }

}

这是预约

package com.bt.automation.domain;

import java.util.Date;

public class Appointment {

    private String apptRequired;
    private String apptSlot;
    private String apptType;
    private String apptReference;
    private String earliestApptSlot;

    private Date earliestDate;

    public String getApptRequired() {
        return apptRequired;
    }

    public void setApptRequired(String apptRequired) {
        this.apptRequired = apptRequired;
    }

    public String getApptSlot() {
        return apptSlot;
    }

    public void setApptSlot(String apptSlot) {
        this.apptSlot = apptSlot;
    }

    public String getApptType() {
        return apptType;
    }

    public void setApptType(String apptType) {
        this.apptType = apptType;
    }

    public String getApptReference() {
        return apptReference;
    }

    public void setApptReference(String apptReference) {
        this.apptReference = apptReference;
    }

    public String getEarliestApptSlot() {
        return earliestApptSlot;
    }

    public void setEarliestApptSlot(String earliestApptSlot) {
        this.earliestApptSlot = earliestApptSlot;
    }

    public Date getEarliestDate() {
        return earliestDate;
    }

    public void setEarliestDate(Date earliestDate) {
        this.earliestDate = earliestDate;
    }

}

最后是另一个域类响应

package com.bt.automation.domain;

import java.util.List;

import javax.xml.bind.annotation.*;

import com.bt.automation.domain.autofix.UserDetail;

@XmlRootElement(name = "Envelope")
@XmlAccessorType(XmlAccessType.FIELD)
public class Response {

    private long number;
    private String actionRequestId;
    private String serviceAffectingFlag;

    private Appointment appointment;
    private UserDetail userDetail;

    private List<MyService> service;

    public long getNumber() {
        return number;
    }

    public void setNumber(long number) {
        this.number = number;
    }

    public String getActionRequestId() {
        return actionRequestId;
    }

    public void setActionRequestId(String actionRequestId) {
        this.actionRequestId = actionRequestId;
    }

    public String getServiceAffectingFlag() {
        return serviceAffectingFlag;
    }

    public void setServiceAffectingFlag(String serviceAffectingFlag) {
        this.serviceAffectingFlag = serviceAffectingFlag;
    }

    public List<MyService> getService() {
        return service;
    }

    public void setService(List<MyService> service) {
        this.service = service;
    }

    public Appointment getAppointment() {
        return appointment;
    }

    public void setAppointment(Appointment appointment) {
        this.appointment = appointment;
    }

    public UserDetail getUserDetail() {
        return userDetail;
    }

    public void setUserDetail(UserDetail userDetail) {
        this.userDetail = userDetail;
    }

}

在代码中,我想将类UserDetail绑定到XML元素endUserDetails。以下是我的代码

 package com.bt.automation.xml;

import java.io.FileReader;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import com.bt.automation.domain.Appointment;
import com.bt.automation.domain.MyService;
import com.bt.automation.domain.Response;
import com.bt.automation.domain.autofix.UserDetail;

public class UnmarshalResponse {

    public static void main(String[] args) throws Exception {

        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("response.xml"));
        xsr.nextTag(); // Advance to Envelope tag

        int i = 0;
        while (!xsr.getLocalName().equals("getNumberResponse")) {
            System.out.println(i + xsr.getLocalName());
            xsr.nextTag();

            i = i + 1;
        }

        System.out.println("Current element: " + xsr.getLocalName());
        System.out.println("Namespace: " + xsr.getNamespaceContext().getNamespaceURI("ns"));

        JAXBContext jc = JAXBContext.newInstance(Response.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBElement<Response> je = unmarshaller.unmarshal(xsr, Response.class);
        xsr.close();

        Response response = je.getValue();
        System.out.println("Object: " + response);
        System.out.println("Number: " + response.getNumber());
        System.out.println("Request ID: " + response.getActionRequestId());
        System.out.println("Flag: " + response.getServiceAffectingFlag());

        Appointment app = response.getAppointment();
        System.out.println("Appointment.apptRequired: " + app.getApptRequired());
        System.out.println("Appointment.apptReference: " + app.getApptReference());
        System.out.println("Appointment.apptType: " + app.getApptType());
        System.out.println("Appointment.earliestApptSlot: " + app.getEarliestApptSlot());
        System.out.println("Appointment.apptSlot: " + app.getApptSlot());
        System.out.println("Appointment.earliestDate: " + app.getEarliestDate());

        UserDetail userDetail = response.getUserDetail();
        System.out.println("UserDetail.getFirstName: " + userDetail.getFirstName());
        System.out.println("UserDetail.getLastName: " + userDetail.getLastName());
        System.out.println("UserDetail.getPriTelephone: " + userDetail.getPriTelephone());
        System.out.println("UserDetail.getSecTelephone: " + userDetail.getSecTelephone());
        System.out.println("UserDetail.getCssDBID: " + userDetail.getCssDBID());

        List<MyService> list = response.getService();
        for (i = 0; i < list.size(); i++) {
            System.out.println("Service " + i + ": " + response.getService().get(i).getServiceId());
        }
    }

}

但是,当我运行代码时,它返回NullPointerException。这里的一个问题是,域类必须与绑定的XML元素具有相同的名称吗?

1 个答案:

答案 0 :(得分:0)

您有一个NullPointerException,因为response.getAnnotation()null。实际上response的所有属性都是null,因为没有相应的XML内容被成功解组。

原因是:您的Java类完全忽略XML命名空间。 ns:getNumberResponse XML元素中的命名空间和所有 没有名称空间前缀的子元素(appointmentendUserDetailsservice,...) 不要匹配Java类中的命名空间。

要了解有关JAXB注释的更多信息,我建议您阅读this tutorial以及包javax.xml.bind.annotation的javadoc,特别是XmlElementXmlRootElement

为了解决您的问题,您有两种选择:

  1. 更改XML内容以匹配现有的Java类
  2. 或更改Java类以匹配您现有的XML内容。
  3. 以下解决方案假设您更喜欢更改Java类并且不更改XML内容。

    班级Response
    @XmlRootElement中,您需要设置正确的namenamespace 对于所有属性,您需要设置正确的namespace 对于属性userDetail,您需要设置name = "endUserDetails"

    @XmlRootElement(name = "getNumberResponse", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Response {
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private long number;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String actionRequestId;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String serviceAffectingFlag;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private Appointment appointment;
    
        @XmlElement(name = "endUserDetails", namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private UserDetail userDetail;
    
        @XmlElement(name = "service", namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private List<MyService> service;
    
        // ... getters/setters
    }
    

    班级Appointment
    对于所有属性,您需要设置正确的namespace

    @XmlAccessorType(XmlAccessType.FIELD)
    public class Appointment {
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String apptRequired;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String apptSlot;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String apptType;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String apptReference;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String earliestApptSlot;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private Date earliestDate;
    
        // ... getters/setters
    }
    

    班级UserDetail
    对于所有属性,您需要设置正确的namespace 您可以省略@XmlRootElement,因为它对非根元素没有影响。

    @XmlAccessorType(XmlAccessType.FIELD)
    public class UserDetail {
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String firstName;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String lastName;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String priTelephone;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String secTelephone;
    
        @XmlElement(namespace = "http://ccm.intra.bt.com/manageServiceFault/2006/06")
        private String cssDBID;
    
        // ... getters/setters
    }
    

    您没有发布课程MyService。我想你也需要在那里做类似的修正。