Reputation: 13
Been grappling with a problem for about half a week now, and need help as I cannot seem to make any headway.
I've inherited an application which hasn't been treated nicely for 8 years....still on Java 1.4, Maven1 build, no new unit tests for 8 years...
Currently the upgrade to Java 1.6 (Java 1.8 branch also done in parallel, will test both) and Maven 3.3.3 is well in swing - have been making excellent headway.
Now I've hit a wall and not made a breakthrough for a while.
The old sources used local JAXB 1.3 jars to generate classes from a large XSD.
I had to migrate from JAXB1.3 to JAXB2.1 - which also meant i had to spend a lot of time rewriting all the references to the generated classes as the naming conventions changed. Anyway, a lot of time was spent getting the code to compile.
Finally, it compiles, and I try out a unit test to see how it works. This is where i hit my problem.
Most of the classes compiled work fine, but three of the packages throw exceptions when i try to generate the JAXBContext:
@XmlValue is not allowed on a class that derives another class.
I've narrowed the problem down to a pattern which occurs in a couple of the generated classes. The class that causes the exception is defined in the schema as below:
<xs:element name="ContactName">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="First" type="xs:string"/>
<xs:attribute name="Middle" type="xs:string"/>
<xs:attribute name="Last" type="xs:string"/>
<xs:attribute name="Name" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
and then this element is referenced in another as follows:
<xs:element name="ContactInfo">
<xs:complexType>
<xs:annotation>
<xs:documentation>Common contact information</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element ref="ContactName" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="ContactID" minOccurs="0"/>
<xs:element ref="ContactDivision" minOccurs="0" maxOccurs="unbounded"/>
.....
this is generated into:
ContactName:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"value"
})
@XmlRootElement(name = "ContactName")
public class ContactName
extends BaseJaxbDoc
implements Serializable, Cloneable, CopyTo
{
private final static long serialVersionUID = 47110815L;
@XmlValue
protected String value;
@XmlAttribute(name = "First")
protected String first;
@XmlAttribute(name = "Middle")
protected String middle;
@XmlAttribute(name = "Last")
protected String last;
@XmlAttribute(name = "Name")
protected String name;
And then declared in ContactInfo as follows:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"contactName",
"contactID",
"contactDivision",
"contactPhone",
"contactPhoneHome",
"contactPhoneMobile",
"contactFax",
"contactEmail",
"contactEmail2"
})
@XmlRootElement(name = "ContactInfo")
public class ContactInfo
extends BaseJaxbDoc
implements Serializable, Cloneable, CopyTo
{
private final static long serialVersionUID = 47110815L;
@XmlElement(name = "ContactName")
protected List<ContactName> contactName;
The exception thrown is at:
this problem is related to the following location:
at protected java.lang.String xxx.xx.xxxx.xxxx.orders.jaxb.ContactName.value
at xxx.xx.xxxx.xxxx.orders.jaxb.ContactName
at protected java.util.List xxx.xx.xxxx.xxxx.orders.jaxb.ContactInfo.contactName
at xxx.xx.xxxx.xxxx.orders.jaxb.ContactInfo
at protected java.util.List xxx.xx.xxxx.xxxx.orders.jaxb.CustomerReference.contactInfo
at xxx.xx.xxxx.xxxx.orders.jaxb.CustomerReference
at protected java.util.List xxx.xx.xxxx.xxxx.orders.jaxb.Item.customerReference
at xxx.xx.xxxx.xxxx.orders.jaxb.Item
at public xxx.xx.xxxx.xxxx.orders.jaxb.Item xxx.xx.xxxx.xxxx.orders.jaxb.ObjectFactory.createItem()
at xxx.xx.xxxx.xxxx.orders.jaxb.ObjectFactory
There is an XML transformation on the original schema, stripping comments out and creating jaxb:typesafeEnum types. Then the transformed schema is used with a jxb binding file to bind everything to an internal jaxb helper superclass - BaseJaxbDoc
<jaxb:globalBindings generateIsSetMethod="true">
<xjc:serializable uid="47110815"/>
<xjc:superClass name="xxx.xx.xxxx.xxxx.helpers.BaseJaxbDoc"/>
<jaxb:javaType name="java.math.BigDecimal" xmlType="xs:decimal"
parseMethod="xxx.xx.xxxx.xxxx.helpers.AmountConverter.parseAmount"
printMethod="xxx.xx.xxxx.xxxx.helpers.AmountConverter.printAmount"/>
</jaxb:globalBindings>
This is because I am using xjc on 9 different schemas, all generating JAXB packages of classes.
The classes all have the same superclass (defined in a bindings file for each schema) to only implement the JAXB marshall/unmarshall classes once, along with some other helper functions. So my question is how to get around this exception when i cannot modify the schema? Something in the XSLT or something in the bindings file?
My Maven dependencies: for JAXB: org.jvnet.jaxb2.maven2 maven-jaxb21-plugin 0.13.0
JAXB runtime: org.glassfish.jaxb jaxb-runtime 2.2.11
Upvotes: 1
Views: 1936
Reputation: 43671
Try annotating BaseJaxbDoc
with @XmlTransient
.
The problem you're getting is produced here:
if(getBaseClass()!=null) {
builder.reportError(new IllegalAnnotationException(
Messages.XMLVALUE_IN_DERIVED_TYPE.format(), p ));
}
JAXB thinks your BaseJaxbDoc
is a base class. So you should either remove xjc:superClass
or trink JAXB into thinking that your class does not have a base class.
When I look at this part of the code in the ModelBuilder
:
if(reader.hasClassAnnotation(clazz,XmlTransient.class) || isReplaced) {
// handle it as if the base class was specified
r = getClassInfo( nav.getSuperClass(clazz), searchForSuperClass,
new ClassLocatable<C>(upstream,clazz,nav) );
}
It seems that the ModelBuilder
recognizes @XmlTransient
on classes and does not consider them. So there's a chance that assing @XmlTransient
on your BaseJaxbDoc
would help.
Another option is to drop BaseJaxbDoc
construct. You use class inheritance to add marshal/unmarshal functionality to the schema-derived classes. I'd rather move this functionality out into some external services. This is probably not an option here as you're probably facing a lot of legacy code.
A further option is to try MOXy instead of JAXB RI in the runtime.
Upvotes: 1