防止使用 JAXB 从 XSD 生成空@XmlType注释



让我从我的问题归结为什么开始。我正在使用 maven-jaxb2-plugin 从 XSD 模式生成一个名为 MyServiceResponse 的类。生成的 MyServiceResponse 类包含具有空名称属性的@XmlType批注。

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

我想要么生成带有填充name属性的 MyServiceResponse,要么完全没有@XmlType注释。是否可以在 XJB 文件中使用自定义绑定或以其他方式执行此操作?无论如何,如果可能的话,我想在生成过程中解决这个问题,因为对 MyserviceResponse 的手动编辑将在每次运行 Maven 插件时被覆盖。

下面是一个演示我实际问题的 Java 类。该类使用 XmlStreamReader 和 JAXB 从消息中的任何元素开始解组 XML 消息。"xml"变量不会完全解组。"汽车"属性保持null。发生这种情况是因为xmlns="http://www.example.com/type"命名空间由 XmlStreamReader 复制到 Body 元素,而不是复制到 Car 子元素。不知何故,JAXB 无法看到我希望它继续解组 Car 元素。(这里打个大大的问号)

我已经知道一些修复程序,但它们涉及对XSD或MyServiceResponse类的手动更改。

首先,我可以在XSD上设置elementFormDefault="qualified",从中生成MyServiceResponse类,ObjectFactory和package-info.java。这有效,但它也会导致我的请求 XML 消息使用限定名称空间封送,并且我向其发送消息的服务不接受这。此外,它需要更改 XSD,如果可能的话,我宁愿避免。

其次,在车身和汽车@XmlType注释上设置名称有效:@XmlType(name = "Body", propOrder = {})@XmlType(name = "Car", propOrder = {})。但它涉及手动编辑 MyServiceResponse。

第三,删除@XmlType(name = "", propOrder = {})注释是可行的,但它也涉及手动编辑MyServiceResponse。

这是一个可复制粘贴的演示类:

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" +
"tt<response xmlns="http://www.example.com/type">n" +
"ttt<type:serviceResponse xmlns:type="http://www.example.com/type">n" +
"tttt<Body>n" +
"ttttt<Car>n" +
"tttttt<Brand>Mitsubishi</Brand>n" +
"tttttt<Color>Red</Color>n" +
"ttttt</Car>n" +
"tttt</Body>n" +
"ttt</type:serviceResponse>n" +
"tt</response>n" +
"t</soapenv:Body>n" +
"</soapenv:Envelope>";

private static String xmlStripped = "<type:serviceResponse xmlns:type="http://www.example.com/type">n" +
"tttt<Body>n" +
"ttttt<Car>n" +
"tttttt<Brand>Mitsubishi</Brand>n" +
"tttttt<Color>Red</Color>n" +
"ttttt</Car>n" +
"tttt</Body>n" +
"ttt</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:

<?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>

添加:

这是 XmlStreamReader 开始解组时位于其中的 XML。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>

@XmlType名称的属性为空,因为 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>

相关内容

  • 没有找到相关文章

最新更新