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