2017-03-29 58 views
1

讓我從我的問題歸結爲什麼開始。我使用maven-jaxb2插件從XSD模式生成名爲MyServiceResponse的類。生成的MyServiceResponse類包含具有空名稱屬性的@XmlType註釋。阻止使用JAXB從XSD生成空的@XmlType註釋

@XmlAccessorType(XmlAccessType.FIELD) 
    @XmlType(name = "", propOrder = { 

    }) 

我想要麼產生MyServiceResponse充滿name屬性或不@XmlType註釋完全。這可能使用XJB文件中的自定義綁定或其他方式?無論如何,如果可能的話,我想在代期間解決這個,因爲對Maven插件的每次運行都會覆蓋手動編輯MyserviceResponse。

下面是一個Java類,演示了我的實際問題。該類使用XmlStreamReader和JAXB解組消息,從消息中的任何元素開始解組XML消息。 'xml'變量沒有得到完全解組。 '汽車'財產保留null。發生這種情況是因爲xmlns="http://www.example.com/type"名稱空間被XmlStreamReader複製到Body元素,但不會複製到Car子元素。不知怎的,JAXB無法看到我希望它繼續解組Car元素。 (大問號在這裏)

我已經知道一些修復,但它們涉及對XSD或MyServiceResponse類的手動更改。

首先,我可以從我產生MyServiceResponse類的的ObjectFactory和package-info.java的XSD設置elementFormDefault="qualified"。這是有效的,但它也會導致我的請求XML消息被限定名稱空間編組,並且這不會被我發送消息的服務接受。此外,它需要改變XSD,如果可能,我寧願避免。

其次,Body和Car @XmlType註釋的設置名稱的工作原理如下:@XmlType(name = "Body", propOrder = {})@XmlType(name = "Car", propOrder = {})。但是它涉及到手動編輯MyServiceResponse。

第三,刪除@XmlType(name = "", propOrder = {})註釋的作品,但它也涉及手動編輯MyServiceResponse。

這是一個複製pastable演示類:

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBElement; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.annotation.*; 
import javax.xml.namespace.QName; 
import javax.xml.stream.XMLInputFactory; 
import javax.xml.stream.XMLStreamException; 
import javax.xml.stream.XMLStreamReader; 
import java.io.Reader; 
import java.io.StringReader; 

public class XmlStreamReaderUnmarshallingTest { 

    private static JAXBContext jaxbContext; 

    static { 
     try { 
      jaxbContext = JAXBContext.newInstance(ObjectFactory.class); 
     } catch (JAXBException e) { 
      e.printStackTrace(); 
     } 
    } 

    private static String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
      "<soapenv:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \n" + 
      "\txmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \n" + 
      "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + 
      "\t<soapenv:Body>\n" + 
      "\t\t<response xmlns=\"http://www.example.com/type\">\n" + 
      "\t\t\t<type:serviceResponse xmlns:type=\"http://www.example.com/type\">\n" + 
      "\t\t\t\t<Body>\n" + 
      "\t\t\t\t\t<Car>\n" + 
      "\t\t\t\t\t\t<Brand>Mitsubishi</Brand>\n" + 
      "\t\t\t\t\t\t<Color>Red</Color>\n" + 
      "\t\t\t\t\t</Car>\n" + 
      "\t\t\t\t</Body>\n" + 
      "\t\t\t</type:serviceResponse>\n" + 
      "\t\t</response>\n" + 
      "\t</soapenv:Body>\n" + 
      "</soapenv:Envelope>"; 


    private static String xmlStripped = "<type:serviceResponse xmlns:type=\"http://www.example.com/type\">\n" + 
      "\t\t\t\t<Body>\n" + 
      "\t\t\t\t\t<Car>\n" + 
      "\t\t\t\t\t\t<Brand>Mitsubishi</Brand>\n" + 
      "\t\t\t\t\t\t<Color>Red</Color>\n" + 
      "\t\t\t\t\t</Car>\n" + 
      "\t\t\t\t</Body>\n" + 
      "\t\t\t</type:serviceResponse>"; 


    public static void main(String[] args) throws JAXBException, XMLStreamException { 
     readXml(xml, "serviceResponse"); 
     readXml(xmlStripped, "serviceResponse"); 
    } 

    private static void readXml(String inputXml, String startFromElement) throws JAXBException, XMLStreamException { 

     final XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory(); 
     final Reader reader = new StringReader(inputXml); 
     final XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader); 
     final XMLStreamReader streamReader = skipToElement(xmlStreamReader, startFromElement); 
     final MyServiceResponse serviceResponse = (MyServiceResponse) unmarshal(streamReader); 

     if(serviceResponse.getBody().getCar() == null) { 
      System.out.println("It didn't work :-("); 
     } else { 
      System.out.println("It worked"); 
     } 
    } 

    private static XMLStreamReader skipToElement(final XMLStreamReader xsr, final String startAtElement) throws XMLStreamException { 
     while (startAtElement != null && xsr.hasNext()) { 
      xsr.next(); 
      if (xsr.hasName()) { 
       final String name = xsr.getName().getLocalPart(); 
       if (name.equals(startAtElement)) { 
        return xsr; 
       } 
      } 
     } 

     throw new IllegalArgumentException(String.format("Could not find element %s in response", startAtElement)); 
    } 

    private static Object unmarshal(final XMLStreamReader xsr) throws JAXBException { 
     final Object entity = unmarshaller(jaxbContext).unmarshal(xsr); 
     return (entity instanceof JAXBElement ? ((JAXBElement) entity).getValue() : entity); 
    } 

    // Create unmarshaller every time 
    private static Unmarshaller unmarshaller(JAXBContext context) throws JAXBException { 

     return context.createUnmarshaller(); 

    } 
} 


@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "MyServiceResponse", propOrder = { 

}) 
class MyServiceResponse { 

    @XmlElement(name = "Body") 
    protected MyServiceResponse.Body body; 

    /** 
    * Gets the value of the body property. 
    * 
    * @return 
    *  possible object is 
    *  {@link MyServiceResponse.Body } 
    * 
    */ 
    public MyServiceResponse.Body getBody() { 
     return body; 
    } 

    /** 
    * Sets the value of the body property. 
    * 
    * @param value 
    *  allowed object is 
    *  {@link MyServiceResponse.Body } 
    * 
    */ 
    public void setBody(MyServiceResponse.Body value) { 
     this.body = value; 
    } 


    /** 
    * <p>Java class for anonymous complex type. 
    * 
    * <p>The following schema fragment specifies the expected content contained within this class. 
    * 
    * <pre> 
    * &lt;complexType&gt; 
    * &lt;complexContent&gt; 
    *  &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt; 
    *  &lt;all&gt; 
    *   &lt;element name="Car" minOccurs="0"&gt; 
    *   &lt;complexType&gt; 
    *    &lt;complexContent&gt; 
    *    &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt; 
    *     &lt;all&gt; 
    *     &lt;element name="Brand" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt; 
    *     &lt;element name="Color" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt; 
    *     &lt;/all&gt; 
    *    &lt;/restriction&gt; 
    *    &lt;/complexContent&gt; 
    *   &lt;/complexType&gt; 
    *   &lt;/element&gt; 
    *  &lt;/all&gt; 
    *  &lt;/restriction&gt; 
    * &lt;/complexContent&gt; 
    * &lt;/complexType&gt; 
    * </pre> 
    * 
    * 
    */ 
    @XmlAccessorType(XmlAccessType.FIELD) 
    @XmlType(name = "", propOrder = { 

    }) 
    public static class Body { 

     @XmlElement(name = "Car") 
     protected MyServiceResponse.Body.Car car; 

     /** 
     * Gets the value of the car property. 
     * 
     * @return 
     *  possible object is 
     *  {@link MyServiceResponse.Body.Car } 
     * 
     */ 
     public MyServiceResponse.Body.Car getCar() { 
      return car; 
     } 

     /** 
     * Sets the value of the car property. 
     * 
     * @param value 
     *  allowed object is 
     *  {@link MyServiceResponse.Body.Car } 
     * 
     */ 
     public void setCar(MyServiceResponse.Body.Car value) { 
      this.car = value; 
     } 


     /** 
     * <p>Java class for anonymous complex type. 
     * 
     * <p>The following schema fragment specifies the expected content contained within this class. 
     * 
     * <pre> 
     * &lt;complexType&gt; 
     * &lt;complexContent&gt; 
     *  &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt; 
     *  &lt;all&gt; 
     *   &lt;element name="Brand" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt; 
     *   &lt;element name="Color" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt; 
     *  &lt;/all&gt; 
     *  &lt;/restriction&gt; 
     * &lt;/complexContent&gt; 
     * &lt;/complexType&gt; 
     * </pre> 
     * 
     * 
     */ 
     @XmlAccessorType(XmlAccessType.FIELD) 
     @XmlType(name = "", propOrder = { 

     }) 
     public static class Car { 

      @XmlElement(name = "Brand") 
      protected String brand; 
      @XmlElement(name = "Color") 
      protected String color; 

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

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

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

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

     } 

    } 

} 


@XmlRegistry 
class ObjectFactory { 

    private final static QName _ServiceResponse_QNAME = new QName("http://www.example.com/type", "serviceResponse"); 

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

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

    /** 
    * Create an instance of {@link MyServiceResponse.Body } 
    * 
    */ 
    public MyServiceResponse.Body createMyServiceResponseBody() { 
     return new MyServiceResponse.Body(); 
    } 

    /** 
    * Create an instance of {@link MyServiceResponse.Body.Car } 
    * 
    */ 
    public MyServiceResponse.Body.Car createMyServiceResponseBodyCar() { 
     return new MyServiceResponse.Body.Car(); 
    } 

    /** 
    * Create an instance of {@link JAXBElement }{@code <}{@link MyServiceResponse }{@code >}} 
    * 
    */ 
    @XmlElementDecl(namespace = "http://www.example.com/type", name = "serviceResponse") 
    public JAXBElement<MyServiceResponse> createServiceResponse(MyServiceResponse value) { 
     return new JAXBElement<MyServiceResponse>(_ServiceResponse_QNAME, MyServiceResponse.class, null, value); 
    } 

} 

我的XSD:在啓動時

這是在XMLStreamReader的的XML:

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com/type" 
      targetNamespace="http://www.example.com/type" elementFormDefault="qualified" > 
    <xs:element name="serviceResponse" type="MyServiceResponse"/> 
    <xs:complexType name="MyServiceResponse"> 
     <xs:all> 
      <xs:element name="Body" minOccurs="0"> 
       <xs:complexType> 
        <xs:all> 
         <xs:element name="Car" minOccurs="0"> 
          <xs:complexType> 
           <xs:all> 
            <xs:element name="Brand" type="xs:string" minOccurs="0"/> 
            <xs:element name="Color" type="xs:string" minOccurs="0"/> 
           </xs:all> 
          </xs:complexType> 
         </xs:element> 
        </xs:all> 
       </xs:complexType> 
      </xs:element> 
     </xs:all> 
    </xs:complexType> 
</xs:schema> 

添加解組。 JAXB解組ServiceResponse元素,Body,但不是Car。

<type:serviceResponse xmlns:type="http://www.example.com/type"> 
    <Body xmlns="http://www.example.com/type"> 
     <Car> 
      <Brand>Mitsubishi</Brand> 
      <Color>Red</Color> 
     </Car> 
    </Body> 
</type:serviceResponse> 

回答

2

@XmlType name的屬性爲空,因爲Car和Body是匿名類型。 (http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlType.html

在全局命名空間中創建complexTypes並將它們用作elementtype。(小片段)

<xs:element name="Body" type="Body" minOccurs="0" /> 
<xs:complexType name="Body"> 

或者創建一個JAXB這樣的結合:https://www.ibm.com/developerworks/library/ws-avoid-anonymous-types/#N100BB

轉化XSD:

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com/type" 
    targetNamespace="http://www.example.com/type" elementFormDefault="unqualified" > 

    <xs:element name="serviceResponse" type="MyServiceResponse"/> 

    <xs:complexType name="MyServiceResponse"> 
     <xs:all> 
      <xs:element name="Body" type="Body" minOccurs="0" /> 
     </xs:all> 
    </xs:complexType> 
    <xs:complexType name="Body"> 
     <xs:all> 
      <xs:element name="Car" type="Car" minOccurs="0"/> 
     </xs:all> 
    </xs:complexType> 
    <xs:complexType name="Car"> 
     <xs:all> 
      <xs:element name="Brand" type="xs:string" minOccurs="0"/> 
      <xs:element name="Color" type="xs:string" minOccurs="0"/> 
     </xs:all> 
    </xs:complexType>  
</xs:schema> 
+0

後面這個問題真正的XSD非常複雜,有多重。雖然它可以工作,但爲每個XSD創建這種綁定文件是非常繁瑣的。你知道是否有不同的解決方案?問題的核心似乎是XmlStreamReader將'xlmns'命名空間複製到Body元素,但不復制到Car。將在解編的地方添加一個XSR內容的例子。 – Julius

+0

不幸的是,我還沒有看到任何不同的解決方案。 – mgyongyosi

相關問題