We are creating jaxb classes for a predefined schema. The schema contains certain elements which uses xs:choice to create complexTypes. In this case the binding being generated contain a List which makes it complex as we have to identify the actual instance and then cast it. We tried using the binding customization attribute "choiceContentProperty="false"" to change this behavior. But this does not seem to work. Any suggestions to override this behavior?
Disclaimer: I am the author of jaxb2-simplify-plugin.
This is a use case for the jaxb2-simplify-plugin.
This:
<xs:complexType name="typeWithElementsProperty">
<xs:choice maxOccurs="unbounded">
<xs:element name="foo" type="xs:string"/>
<xs:element name="bar" type="xs:int"/>
</xs:choice>
</xs:complexType>
Normally generates this:
#XmlElements({
#XmlElement(name = "foo", type = String.class)
#XmlElement(name = "bar", type = Integer.class),
})
protected List<Serializable> fooOrBar;
But with jaxb2-simplify-plugin you'll get this:
#XmlElement(name = "foo", type = String.class)
protected List<String> foo;
#XmlElement(name = "bar", type = Integer.class)
protected List<Integer> bar;
Related
for the following mapping
<xs:complexType name="ParentNode">
<xs:sequence>
<xs:element name="child" type="ChildNode"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ParentNodeRestriction">
<xs:complexContent>
<xs:restriction base="ParentNode">
<xs:sequence>
<xs:element name="child" type="ChildNodeRestriction"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
Jaxb generates the following classes (approximately)
public class ParentNode {
protected ChildNode child;
}
public class ParentNodeRestriction
extends ParentNode
{
}
public class ChildNode {
}
public class ChildNodeRestriction
extends ChildNode
{
}
Knowing that ParentNode is not used elsewhere than ParentNodeRestriction, is it possible to force JAXB to generate the following class (hopefully without modifying the mapping):
public class ParentNodeRestriction
{
protected ChildNodeRestriction child;
}
i.e. I need to have the most precise type for the child field.
ps : I am using jaxb2-maven-plugin version 2.2 with maven
Thank you
Using the xjb directive <xjc:treatRestrictionLikeNewType/> (as indicated by his name) generates classes for restrictions which do not inherit from the class corresponding to the parent mapping.
This solves the problem.
There seems to be a slight annoying consequence : elements with maxOccurs="0" are generated despite the <xjc:simple/> directive.
In fact, elements with maxOccurs="0" can be removed from the restriction definition.
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
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.
I have java class:
public class ActivityAddress {
#XmlElement(name = "Elem1", required = false)
private String elem1;
#XmlElement(name = "Elem2", required = false)
private String elem2;
#XmlElement(name = "PostIndex", required = true)
private String postIndex;
}
I want to get schema like this:
<xs:complexType name="ActivityAddress">
<xs:sequence>
<xs:choice minOccurs="0">
<xs:element name="Elem1" type="xs:string"/>
<xs:element name="Elem2" type="xs:string"/>
</xs:choice>
<xs:element name="PostIndex" type="xs:string"/>
</xs:sequence>
So the two fields "Elem1" and "Elem2" must be in choice.
Decision like this:
#XmlElements({
#XmlElement(name = "Elem1", type = String.class, required = false),
#XmlElement(name = "Elem2", type = String.class, required = false)
})
private String elem;
isn't suitable for me, because in java class i need have both fields.
Ноw i can do it? Can anyone please help?
Generating an XML Schema
For the following Java class:
public class ActivityAddress {
#XmlElement(name = "Elem1", required = false)
private String elem1;
#XmlElement(name = "Elem2", required = false)
private String elem2;
#XmlElement(name = "PostIndex", required = true)
private String postIndex;
}
You are going to get an XML Schema like the following, there isn't a way to generate the choice the way you would like.
<xs:sequence>
<xs:element name="Elem1" type="xs:string" mincOccurs="0"/>
<xs:element name="Elem2" type="xs:string" minOccurs="0"/>
<xs:element name="PostIndex" type="xs:string"/>
</xs:sequence>
Pointing to a Hand Crafted XML Schema
You can however generate an XML Schema and then modify it yourself and then tell JAXB to use it. This is done with the package level #XmlSchema annotation.
package-info.java
#XmlSchema(location="http://www.example.com/foo/mySchema.xsd")
package com.example.foo;
I have an xsd like this -
<xs:element name="teachers" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="teacher" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
When I use XJC to generate class bindings, I see teacher is of type - List < Object > instead of List< String >
protected List<Object> teacher;
public List<Object> getTeacher() {
if (teacher == null) {
teacher = new ArrayList<Object>();
}
return this.teacher;
}
How can I make it to generate List of strings instead of objects? Any help is appreciated.
Update: With the solution provided by 'vamsilp' - After removing the "minOccurs" on "teachers" element, it worked just fine!That XSD is autogenerated by Jersey from this code:
#XmlElementWrapper(name = "teachers")
#XmlElement(name = "teacher")
public StringSet getTeachers() {
return getData().getTeacherss();
I am not sure how to remove the "minOccurs" attribute. Do I need to modify my code to ignore it?
First of all I just dont understand how you are able to generate classes, instead it should show you an error saying "'minOccurs' cannot appear in element 'element'" because you have declared minOccur constraint to your global/root element "teachers". You shouldn't be doing that please refer this. Try regenerating your JAXB classes by removing this constraint that should work
I have the following elements in my schema:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="optimizeModelBase">
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
<xs:complexType name="riskModel">
<xs:complexContent>
<xs:extension base="optimizeModelBase">
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="fullCovariance">
<xs:complexContent>
<xs:extension base="optimizeModelBase">
<xs:attribute name="fromDate" type="xs:date" use="required"/>
<xs:attribute name="toDate" type="xs:date" use="required"/>
<xs:attribute name="windowSize" type="xs:int" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
In my main schema body, I use a element to specify a 1-of situation:
<xs:choice id="RiskModelParameter">
<xs:element name="RiskModel" type="riskModel"/>
<xs:element name="FullCovariance" type="fullCovariance"/>
</xs:choice>
When I run xsd.exe, the resulting code is:
[System.Xml.Serialization.XmlElementAttribute("FullCovariance",
typeof(fullCovariance))]
[System.Xml.Serialization.XmlElementAttribute("RiskModel",
typeof(riskModel))]
public optimizeModelBase Item
{
get
{
return this.itemField;
}
set
{
this.itemField = value;
}
}
The issue is that the element's ID tag is being ignored, and xsd.exe is arbitrarily naming the property "Item". I have to admit, it's not a big issue, but it's starting to annoy me. What makes this extra annoying is that if I have additional elements at the same level, xsd.exe binds them as "Item1", "Item2", etc.
Does anyone know if it's possible to not have xsd.exe name my choice elements as "Item", and instead be able to put in my own property names?
I've searched high and low, but it seems like there is no solution for my problem. According to the link:
http://msdn.microsoft.com/en-us/library/sa6z5baz(VS.80).aspx
It seems like the arbitrary naming of the choice element is not overrideable. Hopefully this information is helpful to others out there...!
Just had this exact problem today.
I do have a workaround so you can circumvent this problem using a group instead of choice.
using the above xsd as the basis:
Rewrite:
<xs:choice id="RiskModelParameter">
<xs:element name="RiskModel" type="riskModel"/>
<xs:element name="FullCovariance" type="fullCovariance"/>
</xs:choice>
To:
<xs:group name="RiskModelGroup">
<xs:sequence>
<xs:element name="RiskModel" type="riskModel"/>
<xs:element name="FullCovariance" type="fullCovariance"/>
</xs:sequence>
</xs:group>
Reference the group in your element:
<xs:element name="Foo">
<xs:complexType>
<xs:sequence>
<xs:element name="SomeFieldId" type="xs:int" />
<xs:group ref="RiskModelGroup" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Run xsd.exe and the result is as follows
public partial class Foo {
private int someFieldIdField;
private riskModel riskModelField;
private fullCovariance fullCovarianceField;
/// <remarks/>
public int SomeFieldId {
get {
return this.someFieldIdField;
}
set {
this.someFieldIdField = value;
}
}
/// <remarks/>
public riskModel RiskModel {
get {
return this.riskModelField;
}
set {
this.riskModelField = value;
}
}
/// <remarks/>
public fullCovariance FullCovariance {
get {
return this.fullCovarianceField;
}
set {
this.fullCovarianceField = value;
}
}
}
Now you have property names RiskModel and FullCovariance
Foo f = new Foo()
f.RiskModel.name
or
f.FullCovariance.fromDate
If you require multiple Items of RiskModels and FullCovariance objects you could add a new element having the RiskModelGroup within a sequence.
Good luck!
For those who still want to know : Just use XSDObjectGenerator (made by Microsoft). It manage XsdChoice by adding one object for each choice to your class. That way, you don't have to look for the right element to use for the Item property.
For example:
<xs:complexType name="AccountSchemeName1Choice">
<xs:sequence>
<xs:choice>
<xs:element name="Cd" type="ExternalAccountIdentification1Code"/>
<xs:element name="Prtry" type="Max35Text"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
became
[XmlType(TypeName = "AccountSchemeName1Choice", Namespace = Declarations.SchemaVersion), Serializable]
public class AccountSchemeName1Choice : INotifyPropertyChanged
{
[XmlElement(ElementName = "Cd", IsNullable = false, Form = XmlSchemaForm.Qualified, DataType = "string", Namespace = Declarations.SchemaVersion)]
public string __Cd;
[XmlIgnore]
public string Cd
{
get { return __Cd; }
set { __Cd = value; RaisePropertyChanged("Cd"); }
}
[XmlElement(ElementName = "Prtry", IsNullable = false, Form = XmlSchemaForm.Qualified, DataType = "string", Namespace = Declarations.SchemaVersion)]
public string __Prtry;
[XmlIgnore]
public string Prtry
{
get { return __Prtry; }
set { __Prtry = value; RaisePropertyChanged("Prtry"); }
}
public AccountSchemeName1Choice()
{
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I once actually parsed an autogenerated xsd.exe file and changed it using NRefactory.
I myself just encountered this limitation in my dealings with XSD.exe. It seems that this is a fairly uniform practice with respect to how XSD.exe interprets the ID attribute for all element types. I'd love to hear a rationalization from someone on the MS development team for why XSD.exe works in this manner.
What's interesting is that I have been working on a SchemaImporterExtension that would, among other things, leverage the ID attribute of choice elements to achieve precisely what you're describing, a means of customizing the field/property names of choice mapped object members.
Unfortunately, not only does it seem that XSD.exe doesn't support ID attribute binding, but it doesn't even appear that ID is included in the XmlSchemaChoice object that reflects the choice element from the parsed schema document.
Perhaps I'm missing something, but if this is indeed the intended behavior and not an error on my part, then it's a pretty ridiculous omission in my estimation, and it speaks to just how much of a neutered XSD representation is reflected in the MS schema auto-generation tools.
XSD.exe adheres to what I'll term as a "lean and mean" interpretation of the XML schema standard. Apparently now WCF obviates XSD.exe, and guess what? WCF's svcutil tool recognizes an even smaller footprint of XML schema; choice element binding is even't supported in svcutil IIRC.
At some point I'm not even sure what value the MS auto-generation tools are going to bring to the table, because you're going to be reduced to using trivial XSD structures (I mean, no choice element support? Really?) to encapsulate your business object modeling.