2012-02-16 2 views
0

Я использую JAXB для приложения Java, которое я пишу. Я скомпилировал схему OCI в классы успешно, и я могу объединить тип AuthenticationRequest в XML (внутри OCIMessage), отправить его и получить ответ. Однако, когда я пытаюсь отменить ответ в OCIMessage, он терпит неудачу. Вот содержимое моего тестового класса:Ошибка JAXB unmarshalling

package com.some.domain.ignore; 

import java.io.IOException; 
import java.io.OutputStream; 
import java.net.Socket; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBElement; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.helpers.DefaultValidationEventHandler; 
import javax.xml.stream.FactoryConfigurationError; 
import javax.xml.stream.XMLStreamException; 
import javax.xml.transform.stream.StreamSource; 

import com.some.domain.oci.OCIMessage; 
import com.some.domain.oci.ObjectFactory; 
import com.some.domain.schema.AuthenticationRequest; 
import com.some.domain.schema.AuthenticationResponse; 

public class JavaTest { 
    private final static String HOST = "some.host.com"; 
    private final static int PORT = 2208; 
    private final static String USER = "SOME_USER"; 

    private final static String SESSION = Long.toString(System.currentTimeMillis()); 
    private static Socket sock; 
    private static OutputStream out; 
    private static Marshaller marshaller; 
    private static Unmarshaller unmarshaller; 
    private static JAXBContext context; 
    private static ObjectFactory factory; 

    public static void main(String[] args) { 
     try { 
      runIt(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private static void runIt() throws XMLStreamException, FactoryConfigurationError, IOException, JAXBException { 
     sock = new Socket(HOST, PORT); 
     out = sock.getOutputStream(); 

     AuthenticationRequest request = new AuthenticationRequest(); 
     request.setUserId(USER); 

     factory = new ObjectFactory(); 
     OCIMessage message = new OCIMessage(); 
     message.setSessionId(SESSION); 
     message.setProtocol("OCI"); 
     message.getCommand().add(request); 
     JAXBElement<OCIMessage> element = factory.createBroadsoftDocument(message); 

     context = JAXBContext.newInstance(ObjectFactory.class); 
     marshaller = context.createMarshaller(); 
     unmarshaller = context.createUnmarshaller(); 
     marshaller.marshal(element, out); 

     unmarshaller.setEventHandler(new DefaultValidationEventHandler()); 
     StreamSource s = new StreamSource(sock.getInputStream()); 
     JAXBElement<OCIMessage> doc = unmarshaller.unmarshal(s, OCIMessage.class); 
     OCIMessage response = doc.getValue(); 
    } 
} 

Реальный ответ XML заключается в следующем:

<BroadsoftDocument protocol="OCI" xmlns="C" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<sessionId xmlns="">1329428955041</sessionId> 
<command echo="" xsi:type="AuthenticationResponse" xmlns=""> 
<userId>SOME_USER</userId> 
<nonce>1329428959587</nonce> 
<passwordAlgorithm>MD5</passwordAlgorithm></command> 
</BroadsoftDocument> 

демаршаллинга попытка терпит неудачу без ошибок вообще, что чрезвычайно бесполезен. Это похоже на то, что что-то внутри Unmarshalling кода JAXB проглатывает исключение, хотя я явно указываю unmarshalling ValidationEventHandler.

Любые идеи относительно того, почему это происходит? При необходимости я могу предоставить больше кода или информации.

Для дальнейшей ссылки, здесь есть класс OCIMessage:

// 
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2012.02.13 at 03:15:18 PM EST 
// 


package com.some.domain.oci.schema; 

import java.util.ArrayList; 
import java.util.List; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlSchemaType; 
import javax.xml.bind.annotation.XmlType; 
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; 
import javax.xml.bind.annotation.adapters.NormalizedStringAdapter; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 


/** 
* 
*   A message contains a list of requests or responses. The server processes all the requests 
*   and returns a message with a corresponding list of responses. 
*  
* 
* <p>Java class for OCIMessage complex type. 
* 
* <p>The following schema fragment specifies the expected content contained within this class. 
* 
* <pre> 
* &lt;complexType name="OCIMessage"> 
* &lt;complexContent> 
*  &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> 
*  &lt;sequence> 
*   &lt;choice> 
*   &lt;element name="sessionId" type="{http://www.w3.org/2001/XMLSchema}normalizedString"/> 
*   &lt;element name="userId" type="{http://www.w3.org/2001/XMLSchema}token"/> 
*   &lt;element name="phoneNumber" type="{http://www.w3.org/2001/XMLSchema}token"/> 
*   &lt;/choice> 
*   &lt;element name="command" type="{C}OCICommand" maxOccurs="15"/> 
*  &lt;/sequence> 
*  &lt;attribute name="protocol" use="required"> 
*   &lt;simpleType> 
*   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}NMTOKEN"> 
*    &lt;enumeration value="OCI"/> 
*    &lt;enumeration value="NSOCI"/> 
*   &lt;/restriction> 
*   &lt;/simpleType> 
*  &lt;/attribute> 
*  &lt;/restriction> 
* &lt;/complexContent> 
* &lt;/complexType> 
* </pre> 
* 
* 
*/ 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "OCIMessage", propOrder = { 
    "sessionId", 
    "userId", 
    "phoneNumber", 
    "command" 
}) 
public class OCIMessage { 

    @XmlJavaTypeAdapter(NormalizedStringAdapter.class) 
    @XmlSchemaType(name = "normalizedString") 
    protected String sessionId; 
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class) 
    @XmlSchemaType(name = "token") 
    protected String userId; 
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class) 
    @XmlSchemaType(name = "token") 
    protected String phoneNumber; 
    @XmlElement(required = true) 
    protected List<OCICommand> command; 
    @XmlAttribute(name = "protocol", required = true) 
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class) 
    protected String protocol; 

    /** 
    * Gets the value of the sessionId property. 
    * 
    * @return 
    *  possible object is 
    *  {@link String } 
    *  
    */ 
    public String getSessionId() { 
     return sessionId; 
    } 

    /** 
    * Sets the value of the sessionId property. 
    * 
    * @param value 
    *  allowed object is 
    *  {@link String } 
    *  
    */ 
    public void setSessionId(String value) { 
     this.sessionId = value; 
    } 

    /** 
    * Gets the value of the userId property. 
    * 
    * @return 
    *  possible object is 
    *  {@link String } 
    *  
    */ 
    public String getUserId() { 
     return userId; 
    } 

    /** 
    * Sets the value of the userId property. 
    * 
    * @param value 
    *  allowed object is 
    *  {@link String } 
    *  
    */ 
    public void setUserId(String value) { 
     this.userId = value; 
    } 

    /** 
    * Gets the value of the phoneNumber property. 
    * 
    * @return 
    *  possible object is 
    *  {@link String } 
    *  
    */ 
    public String getPhoneNumber() { 
     return phoneNumber; 
    } 

    /** 
    * Sets the value of the phoneNumber property. 
    * 
    * @param value 
    *  allowed object is 
    *  {@link String } 
    *  
    */ 
    public void setPhoneNumber(String value) { 
     this.phoneNumber = value; 
    } 

    /** 
    * Gets the value of the command property. 
    * 
    * <p> 
    * This accessor method returns a reference to the live list, 
    * not a snapshot. Therefore any modification you make to the 
    * returned list will be present inside the JAXB object. 
    * This is why there is not a <CODE>set</CODE> method for the command property. 
    * 
    * <p> 
    * For example, to add a new item, do as follows: 
    * <pre> 
    * getCommand().add(newItem); 
    * </pre> 
    * 
    * 
    * <p> 
    * Objects of the following type(s) are allowed in the list 
    * {@link OCICommand } 
    * 
    * 
    */ 
    public List<OCICommand> getCommand() { 
     if (command == null) { 
      command = new ArrayList<OCICommand>(); 
     } 
     return this.command; 
    } 

    /** 
    * Gets the value of the protocol property. 
    * 
    * @return 
    *  possible object is 
    *  {@link String } 
    *  
    */ 
    public String getProtocol() { 
     return protocol; 
    } 

    /** 
    * Sets the value of the protocol property. 
    * 
    * @param value 
    *  allowed object is 
    *  {@link String } 
    *  
    */ 
    public void setProtocol(String value) { 
     this.protocol = value; 
    } 

} 

Наконец, вот содержимое ObjectFactory, который отвечает за создание BroadsoftDocument, с помощью метода createBroadsoftDocument:

// 
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2012.02.13 at 03:15:18 PM EST 
// 


package com.some.domain.oci; 

import javax.xml.bind.JAXBElement; 
import javax.xml.bind.annotation.XmlElementDecl; 
import javax.xml.bind.annotation.XmlRegistry; 
import javax.xml.namespace.QName; 


/** 
* This object contains factory methods for each 
* Java content interface and Java element interface 
* generated in the c package. 
* <p>An ObjectFactory allows you to programatically 
* construct new instances of the Java representation 
* for XML content. The Java representation of XML 
* content can consist of schema derived interfaces 
* and classes representing the binding of schema 
* type definitions, element declarations and model 
* groups. Factory methods for each of these are 
* provided in this class. 
* 
*/ 
@XmlRegistry 
public class ObjectFactory { 

    private final static QName _BroadsoftDocument_QNAME = new QName("C", "BroadsoftDocument"); 

    /** 
    * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: c 
    * 
    */ 
    public ObjectFactory() { 
    } 

    /** 
    * Create an instance of {@link OCIMessage } 
    * 
    */ 
    public OCIMessage createOCIMessage() { 
     return new OCIMessage(); 
    } 

    /** 
    * Create an instance of {@link SuccessResponse } 
    * 
    */ 
    public SuccessResponse createSuccessResponse() { 
     return new SuccessResponse(); 
    } 

    /** 
    * Create an instance of {@link OCITableRow } 
    * 
    */ 
    public OCITableRow createOCITableRow() { 
     return new OCITableRow(); 
    } 

    /** 
    * Create an instance of {@link ErrorResponse } 
    * 
    */ 
    public ErrorResponse createErrorResponse() { 
     return new ErrorResponse(); 
    } 

    /** 
    * Create an instance of {@link OCITable } 
    * 
    */ 
    public OCITable createOCITable() { 
     return new OCITable(); 
    } 

    /** 
    * Create an instance of {@link JAXBElement }{@code <}{@link OCIMessage }{@code >}} 
    * 
    */ 
    @XmlElementDecl(namespace = "C", name = "BroadsoftDocument") 
    public JAXBElement<OCIMessage> createBroadsoftDocument(OCIMessage value) { 
     return new JAXBElement<OCIMessage>(_BroadsoftDocument_QNAME, OCIMessage.class, null, value); 
    } 

} 
+0

Можете ли вы также опубликовать 'AuthenticationResponse' (с отображением)? Я ожидаю, что он будет сопоставлен с ''. –

+0

Я обновил, чтобы включить тип аутентификацииResponse, а также некоторые подробности. – tangent

+0

Я должен определенно быть unmarshalling как OCIMessage вместо AuthenticationResponse. OCIMessage - это тип, соответствующий BroadsoftDocument. Единственная проблема заключается в том, что когда я делаю это, он терпит неудачу. – tangent

ответ

0

ВЫГЛЯДИТ как ошибка сопоставления: XML-документ ответа содержит элемент sessionId, и сопоставление типа AuthenticationResponse для него не подготовлено. Если вы опубликуете класс (включая аннотации отображения), мы можем помочь вам больше.

+0

Спасибо, что ответили. Я добавил запрошенную вами информацию. – tangent

+0

JAXB Mapping вы отправили для OCIMessage. Можете ли вы опубликовать класс сопоставления JAXB документа с корневым элементом «BroadsoftDocument»? –

+0

Я опубликовал ObjectFactory. Компиляция схемы не создавала аннотации XMLRootElement, но OCIMessage - это тип, соответствующий BroadsoftDocument. Это можно увидеть в методе ObjectFactory.createBroadsoftDocument. Я использую версию с двумя аргументами без маршала, потому что нет аннотаций XMLRootElement. – tangent

0

Я получал такое исключение несколько недель назад.

вещь, которая меня спасла, добавляла пространство имен в моем xml.

<topRootLevel xmlns="http://blabla.com/"> ... </topRootLevel> 

где «blabla.com» это имя пространства имен, которое точно соответствует имени пакета, порожденную JAXB инструментов из XSD. (tool = xjc)

+0

Я не могу изменить XML, отправляемый с сервера, но он правильно указывает его как: xmlns = "C". Я действительно изменил пакет всех сгенерированных классов, хотя, из просто «C» и «сгенерирован» в другие места в моем проекте. Интересно, могло ли это быть причиной этого. – tangent

+0

Я оглянулся в своих вещах, вместо 'context = JAXBContext.newInstance (ObjectFactory.class);' У меня есть JAXBContext.newInstance ("blabla.com ")' надеюсь, что это поможет – Overnuts

+0

Да, я пробовал настроить свой контекст несколькими способами. Я проверил, что context.toString(). содержит («OCIMessage») возвращает true. Кстати, XML, который JAXB генерирует и отправляет серверу с использованием префикса пространства имен: xmlns: ns2 = «C». Я понял, что с момента получения ответа это не должно быть проблемой, но, возможно, это часть причины. – tangent