We are using JAXB for Java-xml binding.We initially created domain class and then using schemagen commandline tool the following schema has been generated. But generated schema is not valid, giving following error message.
Error Message:
cos-all-limited.1.2: An all model group must appear in a particle with {min occurs} = {max occurs} = 1, and that particle must be part of a pair which constitutes the {content type} of a complex type definition.
Use Case:
There are two classes Emp(Base class) and Dept(Child class).
1. There is no restriction on the elements sequence(means empId, deptId and deptName can appear in any order). so we used xs:all element
2. In Dept class, deptId field should appear only once(minOccurs =1, maxOccurs=1) and deptName is optional.
As per my usecase i am unable to generate valid schema. I did search on google. But i couldn't find the solution. So i am anticipating experts can answer this query. Could you please look into below classes,schema and guide me in the right direction.
NOTE: please don't suggest me to create some temporary domain classes.
Thanks in anticipation.
Emp.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name="EmpType", propOrder={})
#XmlRootElement
public class Emp {
#XmlElement(name="empId", required = true)
private String empId;
}
Dept.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name="DeptType", propOrder={})
public class Dept extends Emp
{
#XmlElement(name="deptId", required = true)
private String deptId;
private String deptName;
}
Schema1.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="emp" type="EmpType"/>
<xs:complexType name="EmpType">
<xs:sequence>
<xs:element name="empId" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="DeptType">
<xs:complexContent>
<xs:extension base="EmpType">
<xs:all> <!--showing error message, mentioned above -->
<xs:element name="deptId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="deptName" type="xs:string" minOccurs="0"/>
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
The document structure that you are trying to allow is actually difficult to represent in an XML schema. You may not be able to generate it from a JAXB (JSR-222) annotated model. You do however have a couple of options:
Option #1 - Generate a Simpler XML Schema
If you are not validating XML content with your XML schema and are simply using it as documentation that people can use as a guide then I would drop the all sections and use sequence instead. This will work better with the inheritance relationship that you have. If you don't specify an instance of Schema on the Unmarshaller the order of elements is not enforced so you will be able to read all the XML documents that meet your rules.
Option #2 - Create Your Own XML Schema
If you want the XML schema to exactly reflect all the possible accepted inputs then you will need to write it yourself. You can reference this existing XML schema by using the package level #XmlSchema annotation.
#XmlSchema(location = "http://www.example.com/package/YourSchema.xsd")
package com.example;
import javax.xml.bind.annotation.XmlSchema;
Related
I have a schema where element names are defined in PascalCase eg:
<xsd:element name="EmployeeName" minOccurs="0" maxOccurs="1">
But I would like this to generate as:
#XmlElement(name = "employeeName")
I know this sounds slightly strange but it will then allow me to use Jackson JAXB annotation support to have my JSON generated in camelCase.
Is this possible?
Yes, it is possible to change the XML element name to (nearly) whatever you want by way of the annotation directives.
In this example, "price" is renamed to "itemprice". Java is not case insensitive, so your camel casing will be honored.
//Example: Code fragment
public class USPrice {
#XmlElement(name="itemprice")
public java.math.BigDecimal price;
}
<!-- Example: Local XML Schema element -->
<xs:complexType name="USPrice"/>
<xs:sequence>
<xs:element name="itemprice" type="xs:decimal" minOccurs="0"/>
</sequence>
</xs:complexType>
This example comes from the JAXB javadocs.
Note that JAXB support has a few "how to use it" workflows, "XSD to generate supporting Java classes", and "Java classes to generate an XSD". I prefer the latter, but you may be using the former. If you are, then you need to alter your XSD to have camelCase element names there.
There is no "use my XSD to generate Java classes, but with some overrides" workflow. Perhaps that's where the confusion comes from. Likewise, there is no "Use Java class annotations to generated XSD documents, but with some overrides". What you specify is going to be what you get, name-wise.
I am using Jaxb to generate Java classes. My schema has the following element defined:
<xs:complexType name="AutomobileType" abstract="true">
<xs:sequence>
<xs:element name="Color" type="core:ColorName"/>
<xs:element name="Weight" type="core:PoundsWeightType"/>
<xs:element name="Fuel" type="Fuel"/>
<xs:element name="NumDoors" type="xs:nonNegativeInteger"/>
<xs:element name="NumCylinders">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="12"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="Automobile" type="AutomobileType"/>
As you can see, I have one element called Automobile.
Jaxb creates the classes and an ObjectFactory that I use to create instances of Automobile. The thing that baffles me is the method to create an instance of Automobile is as follows:
public JAXBElement<AutomobileType> createAutomobile(AutomobileType value)
Why does the createAutomobile method have an argument? How do I use this method?
I tried the following:
ObjectFactory objectFactory = new ObjectFactory();
objectFactory.createAutomobile(new Automobile());
but this does not compile because the Automobile class is abstract and therefore I cannot create an instance.
There is another method :
public AutomobileType createAutomobileType();
In JAXB, the xsd:complexType "AutomobileType" construct maps the class of the same name. It is meant to be the data structure that is equivalent to that XML schema type.
The JAXBElement<> is a (parameterized) wrapper type that associates the java object and the element name and namespace, and that's why its constructor takes an AutomobileType object as parameter in the constructor, in addition to the element namespace and the element name.
The generated ObjectFactory "createAutomobile(..)" is just a convenience method to wrap that constructor, hard-coding your namespace and element name from your XML schema.
While this dichotomy is not all straight forward at first, consider that you could have another element by another name
They would be structurally equivalent, but the element name would be different. You would have another ObjectFactory method "createMotorcycle(...)".
You can create an un-named automobileType object for the purpose of building the contents of the xml element, and then tell JAXB exactly which XML element it should be represented as.
I can't recommend enough reading the JAXB documentation on the topic.
I am a new comer to JaxB World and I am facing one problem w.r.t. unmarshalling of the stored xml content into java class object. Problem description is as follows. Let me know if this is solvable
I have my xsd file which contains following content(this is just a example)
Student info
<xs:complexType name="specialization" abstract="true">
</xs:complexType>
<xs:complexType name="Engineering">
<xs:complexContent>
<xs:extension base="specialization">
<xs:sequence>
<xs:element name="percentage" type="xs:int" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Medical">
<xs:complexContent>
<xs:extension base="specialization">
<xs:sequence>
<xs:element name="grade" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Now all the corresponding java classes are generated by compiling the xsd. Now lets assume in my application i will set the specialization attribute of Student info by constructing Engineering class instance. So after all the operation when i save
the xml file that get saved will have the entry like below
<Student>
<Name>Name1</Name>
<Specialization>
<percentage>78<percentage>
</Specialization>
</Student>
Now when the above content goes for unmarshalling, unmarshalling fails saying unexpected element . I guess this is b'cos Specialization element is of type specialization it calls unmarshalling on itself rather than derived object which is stored.
I hope my explanation is clear. Is there any way that we can unmarshall based on derived class instanse type. The xsd and bindings.xjb file is completely in my control so i can add or modify any entries/info which conveys to unmarshalling rules to unmarshall on derived class.
Thanks for your Suggestion but the it still not working for me.
Here is what I tried
Option #1 - xsi:type
My xsd looks same as what is explained in the example but still the Xsi:type doesn't come in the resulted xml. Do i need to add any other setting while compiling? Which JaxB version should i use for this?
Option#2 - Substitution Groups
When i added the substitution entry part in my xsd, XSD compilation failed saying duplicate names "Engineering" and "Medical". I guess element name and type Name being same compilation cribs(All engineering, Medical,specialization being same both in type definition and element Name)
I can't modify the generated classes as we are using Model driven Architecture. Only thing that is in hand is xsd. Any modification to the xsd is allowed. Ideally First option should have worked. But can't figure out why it is not working. Let me know if you have some suggestion to narrow down the problem.
There are different ways of representing Java inheritance in XML when using JAXB:
Option #1 - xsi:type
In this representation an attribute is used to indicate the subtype being used to populate this element.
<Student>
<Name>Name1</Name>
<Specialization xsi:type="Engineering">
<percentage>78<percentage>
</Specialization>
</Student>
For a detailed example see:
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.htmlhtml
Option #2 - Substitution Groups
Here an element name is used to indicate the subtype. This corresponds to the schema concept of substitution groups and leverages JAXB's #XmlElementRef annotation:
<Student>
<Name>Name1</Name>
<Engineering>
<percentage>78<percentage>
</Engineering>
</Student>
For a detailed example see:
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
I am running into JAXB Unmarshalling error as below.
The foo.bar.Base is an abstract class, with an #XmlSeeAlso annotation, which lists foo.bar.SubBase (which is a concrete subclass of foo.bar.Base)
Both of the above classes are statically reachable from a main/entry class: com.example.Request
The JAXBContext is create using the packages string variant viz:
JAXBContext.newInstance("com.example",...);
The above created JAXBContext correctly lists all the three classes : com.example.Request, foo.bar.Base and foo.bar.SubBase as "classes known to this JAXBContext"
But it fails at runtime during the unmarshal call below.. I am unable to figure out what is wrong here.
unmarshaller.unmarshal(<some-DOM-Element-Instance>, com.example.Request.class);
Any pointers will be appreciated!
Thanks!
The stacktrace is:
Caused by: javax.xml.bind.UnmarshalException: Unable to create an instance of foo.bar.Base - with linked exception: [java.lang.InstantiationException]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:642)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:254)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609)
at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:181)
at com.sun.xml.bind.v2.runtime.unmarshaller.XsiTypeLoader.startElement(XsiTypeLoader.java:76)
at com.sun.xml.bind.v2.runtime.unmarshaller.ProxyLoader.startElement(ProxyLoader.java:55)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:481)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:459)
at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:71)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:148)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:239)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:276)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:245)
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:122)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:314)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:293)
Caused by: java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.sun.xml.bind.v2.ClassFactory.create0(ClassFactory.java:123)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:261)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:603)
... 69 more
EDIT #Blaise and #Ross
Thank you very much Blaise and Ross for your pointers. I think I should have included the schema that is being worked off, here.
The relevant schema looks like this:
<xs:complexType name="Request">
<xs:sequence>
<xs:element name="selectedBase" form="unqualified" nillable="true" type="xs:anyType" minOccurs="0"/>
<xs:element name="selectedSubBase" form="unqualified" nillable="true" type="ns1:SubBase" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Base">
<xs:sequence>
<xs:element name="ID" form="unqualified" nillable="true" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="SubBase">
<xs:complexContent>
<xs:extension base="ns1:Base">
<xs:sequence>
<xs:element name="subBaseElement" form="unqualified" nillable="true" type="xs:anyType" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
So the schema doesn't have substitution group definition (so I guess #XmlElementRef doesn't apply here, or would it still work?), but is using extension. The payload will be :
<ns:Request>
<selectedBase>123</selectedBase>
<selectedSubBase>
<ID>321</ID>
<subBaseElement>123</subBaseElement>
</selectedSubBase>
</ns:Request>
So , the element in the payload occuring is <selectedSubBase> and not <selectedBase xsi:type="ns:SubBase"/>
So which strategy would apply here?
The #XmlSeeAlso annotation is used as a convenience mechanism to tell your JAXB impl that metadata should also be created for the referenced classes. While it is most often used to specify subclasses it is not a mechanism to configure inheritance relationships.
Since JAXB is attempting to instantiate an instance of the abstract super class (foo.bar.Base), it appears as though your XML message does not contain enough information to specify the correct sub-type to be unmarshalled.
This can be done with the xsi:type attribute:
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html
You can also use substitution groups (#XmlElementRef), where the element name is used to determine the appropriate sub-type:
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
JAXB implementations (such as EclipseLink JAXB (MOXy)), also contain extensions for handling inheritance:
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-moxy-extension.html
And if you would like to ignore the inheritance relationship altogether you can use the #XmlTransient annotation:
http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html
You need to be using XmlElementRef on the field containing the reference to Base, to tell JAXB that it should look at subclasses. JAXB is clearly trying to instantiate your base class (which it can't do, of course).
Have a look at XmlElementRef's docs.
try #XmlSeeAlso
#XmlSeeAlso({ExchangeFormat.class}) public abstract class MapperJsonXml <T>
#XmlRootElement(name="ExchangeFormat") public class ExchangeFormat extends MapperJsonXml<ExchangeFormat>
it works
Using dom4j DOMDocument to feed validator.validate(DOMSource) fails in java 1.6 (with xsi:noNamespaceSchemaLocation is not allowed to appear in root element), works in 1.5
I'm finding the following problem quite intractable (OK, that's an understatement) - any insights will be appreciated. Currently it seems like the best idea is to drop dom4j in favour of e.g. XOM (http://stackoverflow.com/questions/831865/what-java-xml-library-do-you-recommend-to-replace-dom4j).
I've been validating in memory XML created from dom4j 'new DOMDocument()' - but this will not work with Java 6.
The following call to validate(source) of a dom4j (1.6.1) DOMDocument derived DOMSource works with Java 1.5.x but fails with Java 1.6.x:
public void validate() throws Exception {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setErrorHandler(null);
Schema schemaXSD = schemaFactory.newSchema(new URL(getSchemaURLString()));
Validator validator = schemaXSD.newValidator();
DOMSource source = new DOMSource(getDocument());
validator.validate(source);
}
getSchemaURLString() is also used to add the xsi:noNamespaceSchemaLocation attribute to the root node, i.e.:
xsi:noNamespaceSchemaLocation="http://localhost:8080/integration/xsd/fqlResponseSchema-2.0.xsd"
The exception follows:
Exception: org.xml.sax.SAXParseException: cvc-complex-type.3.2.2: Attribute 'xsi:noNamespaceSchemaLocation' is not allowed to appear in element 'specialfields'.;
complex-type.3.2.2: Attribute 'xsi:noNamespaceSchemaLocation' is not allowed to appear in element 'specialfields'.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:131)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:384)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:318)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:417)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3182)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processAttributes(XMLSchemaValidator.java:2659)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:2066)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:705)
at com.sun.org.apache.xerces.internal.jaxp.validation.DOMValidatorHelper.beginNode(DOMValidatorHelper.java:273)
at com.sun.org.apache.xerces.internal.jaxp.validation.DOMValidatorHelper.validate(DOMValidatorHelper.java:240)
at com.sun.org.apache.xerces.internal.jaxp.validation.DOMValidatorHelper.validate(DOMValidatorHelper.java:186)
at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:104)
at javax.xml.validation.Validator.validate(Validator.java:127)
Here's the start of the XML - generated after disabling the call to validator.validate(source):
<?xml version="1.0" encoding="utf-8"?>
<meetings xsi:noNamespaceSchemaLocation="http://localhost:8080/integration/xsd/fqlResponseSchema-2.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
.............
</meetings>
And of the XSD:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="meetings">
<xs:complexType>
<xs:choice>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" ref="summary" />
<xs:element minOccurs="0" maxOccurs="unbounded" ref="meeting" />
</xs:sequence>
<xs:element ref="error" />
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="summary">
................
So my root element is being rejected because it contains a xsi:noNamespaceSchemaLocation attribute. And the schema itself does not specify that as a valid attribute of my root element?
At this point it seems to me that I need to give up on dom4j for this task and switch to one of the other solutions, for example as outlined here:
But I'd like to know what I've done wrong at any rate!
Thanks in advance.
I had the same issue, and I found the following documentation at
http://www.ibm.com/developerworks/xml/library/x-javaxmlvalidapi/index.html
Validate against a document-specified schema
Some documents specify the schema they expect to be validated against,
typically using xsi:noNamespaceSchemaLocation and/or
xsi:schemaLocation attributes like this:
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
If you create a schema without specifying a URL, file, or source, then
the Java language creates one that looks in the document being
validated to find the schema it should use. For example:
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
However, normally this isn't what you want. Usually the document
consumer should choose the schema, not the document producer.
Furthermore, this approach works only for XSD. All other schema
languages require an explicitly specified schema location.
The reason seems to be that non-namespace aware JAXP SAXParser is being created and used (see Link).
And solution for different libs I found at www.edankert.com.