Generate java file from XSD, missing @XMLRootElement annotation.

Generate java file from XSD, missing @XMLRootElement annotation. 

An java file without an @XMLRootElement annotation, is has problem to marshaling and unmarshaling xml file. For example, if the class set as an query parameter of a rest webservice, you will get null point exception, for the marshaling problem.


The problem is the java classes are generated from xsd file. So we should find a solution to resolve @XMLRootElement annotation missing problem.


Here is my to solutions, and assume you are using maven as project build tool.

Solution 1:

It's really easy, but may not suitable for all situation, for example, bug fix. But it's really suitable for a new project.

First, let's go to pom.xml file, (maven-jaxb2-plugin)

<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<configuration>
<removeOldOutput>false</removeOldOutput>
<clearOutputDir>false</clearOutputDir>
<forceRegenerate>false</forceRegenerate>
<bindingDirectory>src/main/xsd/</bindingDirectory>
<bindingIncludes>
<bindingInclude>bindings.xml</bindingInclude>
</bindingIncludes>
<extension>true</extension>
<strict>false</strict>
<verbose>true</verbose>
<args>
<arg>-XtoString</arg>
<arg>-Xequals</arg>
<arg>-XhashCode</arg>
<!-- thisarg is required to support adding implements to one of the 
gen'd classes -->
<arg>-Xinheritance</arg>
<arg>-Xdefault-value</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.9.1</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-default-value</artifactId>
<version>1.1</version>
</plugin>
</plugins>
</configuration>
<executions>
<execution>
<id>schema-device-generate</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>src/main/xsd/</schemaDirectory>
<schemaIncludes>
<include>**/*.xsd</include>
</schemaIncludes>
<catalogs>
<catalog>
<dependencyResource>
<groupId>net.charter.aesd</groupId>
<artifactId>common-core-lib</artifactId>
<!-- Version is not required if the artifact is configured as dependency -->
<resource>catalog.xml</resource>
</dependencyResource>
</catalog>
</catalogs>
<episodes>
<episode>
<groupId>net.charter.aesd</groupId>
<artifactId>common-core-lib</artifactId>
<!-- Version is not required if the artifact is configured as dependency -->
</episode>
</episodes>
</configuration>
</execution>
</executions>
</plugin>


Find the bindings.xml file, declared i the pom file (<bindingInclude>bindings.xml</bindingInclude>)

<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" version="2.1">


    <jxb:globalBindings fixedAttributeAsConstantProperty="true">
        <jxb:javaType name="java.time.LocalDate" xmlType="xs:date"
            parseMethod="com.charter.aesd.account.core.util.DateTimeUtils.parseDate" printMethod="com.charter.aesd.account.core.util.DateTimeUtils.printDate" />
        <jxb:javaType name="java.time.OffsetDateTime" xmlType="xs:dateTime"
            parseMethod="com.charter.aesd.account.core.util.DateTimeUtils.parseDateTime" printMethod="com.charter.aesd.account.core.util.DateTimeUtils.printDateTime" />
    
    <xjc:serializable />
<xjc:simple />
    </jxb:globalBindings>
    
    <jxb:bindings schemaLocation="account/device/Obfuscation.xsd" node="/xs:schema">
        <jxb:bindings node="//xs:simpleType[@name='ObfuscatedMacAddress']">
            <jxb:javaType name="String"
                parseMethod="com.charter.aesd.account.core.obfuscation.MacAddress.parse"
                printMethod="com.charter.aesd.account.core.obfuscation.MacAddress.print"/>
        </jxb:bindings>
    


        <jxb:bindings node="//xs:simpleType[@name='ObfuscatedSerialNumber']">
            <jxb:javaType name="String"
                parseMethod="com.charter.aesd.account.core.obfuscation.SerialNumber.parse"
                printMethod="com.charter.aesd.account.core.obfuscation.SerialNumber.print"/>
        </jxb:bindings>
     </jxb:bindings>
</jxb:bindings>


make sure you have  these two lines ,


  <xjc:serializable />
<xjc:simple />
{code}
it will help you generate @XmlRootElement annotation, Now the problem solved. But I want to  say something more.  <xjc:simple /> is really clever guy. if you have a element like this in your xsd file
{code}
<xs:element name="EquipmentList" type="EquipmentList" />
  <xs:complexType name="EquipmentList">
    <xs:sequence>
      <xs:element name="Equipment" type="Equipment"
        minOccurs="0" maxOccurs="unbounded">
        <xs:annotation>
          <xs:documentation>The equipment to be sent for the request
          </xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>


the generated java class field will pluralized. you will find an additional "s" in the field EquipmentList

import java.io.Serializable;
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.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.jvnet.jaxb2_commons.lang.Equals;
import org.jvnet.jaxb2_commons.lang.EqualsStrategy;
import org.jvnet.jaxb2_commons.lang.HashCode;
import org.jvnet.jaxb2_commons.lang.HashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBEqualsStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBHashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBToStringStrategy;
import org.jvnet.jaxb2_commons.lang.ToString;
import org.jvnet.jaxb2_commons.lang.ToStringStrategy;
import org.jvnet.jaxb2_commons.locator.ObjectLocator;
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;




/**
 * <p>Java class for EquipmentList complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType name="EquipmentList">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Equipment" type="{http://model.core.account.aesd.charter.com/device/legacy/entities/v2_0}Equipment" maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EquipmentList", propOrder = {
    "equipments"
})
@XmlRootElement(name = "EquipmentList")
public class EquipmentList
    implements Serializable, Equals, HashCode, ToString
{


    @XmlElement(name = "Equipment")
    protected List<Equipment> equipments;


    /**
     * Gets the value of the equipments 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 equipments property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getEquipments().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Equipment }
     * 
     * 
     */
    public List<Equipment> getEquipments() {
        if (equipments == null) {
            equipments = new ArrayList<Equipment>();
        }
        return this.equipments;
    }


    public String toString() {
        final ToStringStrategy strategy = JAXBToStringStrategy.INSTANCE;
        final StringBuilder buffer = new StringBuilder();
        append(null, buffer, strategy);
        return buffer.toString();
    }


    public StringBuilder append(ObjectLocator locator, StringBuilder buffer, ToStringStrategy strategy) {
        strategy.appendStart(locator, this, buffer);
        appendFields(locator, buffer, strategy);
        strategy.appendEnd(locator, this, buffer);
        return buffer;
    }


    public StringBuilder appendFields(ObjectLocator locator, StringBuilder buffer, ToStringStrategy strategy) {
        {
            List<Equipment> theEquipments;
            theEquipments = (((this.equipments!= null)&&(!this.equipments.isEmpty()))?this.getEquipments():null);
            strategy.appendField(locator, this, "equipments", buffer, theEquipments);
        }
        return buffer;
    }


    public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
        if (!(object instanceof EquipmentList)) {
            return false;
        }
        if (this == object) {
            return true;
        }
        final EquipmentList that = ((EquipmentList) object);
        {
            List<Equipment> lhsEquipments;
            lhsEquipments = (((this.equipments!= null)&&(!this.equipments.isEmpty()))?this.getEquipments():null);
            List<Equipment> rhsEquipments;
            rhsEquipments = (((that.equipments!= null)&&(!that.equipments.isEmpty()))?that.getEquipments():null);
            if (!strategy.equals(LocatorUtils.property(thisLocator, "equipments", lhsEquipments), LocatorUtils.property(thatLocator, "equipments", rhsEquipments), lhsEquipments, rhsEquipments)) {
                return false;
            }
        }
        return true;
    }


    public boolean equals(Object object) {
        final EqualsStrategy strategy = JAXBEqualsStrategy.INSTANCE;
        return equals(null, null, object, strategy);
    }


    public int hashCode(ObjectLocator locator, HashCodeStrategy strategy) {
        int currentHashCode = 1;
        {
            List<Equipment> theEquipments;
            theEquipments = (((this.equipments!= null)&&(!this.equipments.isEmpty()))?this.getEquipments():null);
            currentHashCode = strategy.hashCode(LocatorUtils.property(locator, "equipments", theEquipments), currentHashCode, theEquipments);
        }
        return currentHashCode;
    }


    public int hashCode() {
        final HashCodeStrategy strategy = JAXBHashCodeStrategy.INSTANCE;
        return this.hashCode(null, strategy);
    }

}

It's fine for most situation. But if it's bug fix. it may a nightmare, especially, coarse-grain project. the set and get method may all have problem.


So, let see the second solution:

Using anonymous complex type. So, we need change our xsd file, if you do not have an anonymous complex type.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
          elementFormDefault="qualified" 
          targetNamespace="http://model.core.account.aesd.charter.com/device"
          xmlns="http://model.core.account.aesd.charter.com/device"
          xmlns:xs="http://www.w3.org/2001/XMLSchema"
          xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
  <xs:include schemaLocation="Equipment.xsd" />
  <xs:include schemaLocation="Component.xsd" />


  <xs:element name="EquipmentList" type="EquipmentList" />
  <xs:complexType name="EquipmentList">
    <xs:sequence>
      <xs:element name="Equipment" type="Equipment"
        minOccurs="0" maxOccurs="unbounded">
        <xs:annotation>
          <xs:documentation>The equipment to be sent for the request
          </xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:schema>


This solution is suitable bug fix, no impact to current project.


References:

http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值