I have an application doing XML<->conversions using Jaxb and automatically generated classes with maven-jaxb2-plugin.
Someplace deep in my schema, I have the possibility to enter "ANY" xml.
Update: this better describes my schema. Some known XML wrapping a totally unknown part (the "any" part).
<xs:complexType name="MessageType">
<xs:sequence>
<xs:element name="XmlAnyPayload" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:any namespace="##any"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="OtherElements">
....
</xs:sequence>
This maps (by jaxb) to a inner class like this.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"any"
})
public static class XmlAnyPayload {
#XmlAnyElement(lax = true)
protected Object any;
When I unmarshall the entire structure, it is no problem. The "Object any" will render into a org.apache.xerces.dom.ElementNSImpl. Now, I want to recreate the Java object manually and then go to XML. How do I take some random XML and put into the any (org.apache.xerces.dom.ElementNSImpl) element to be able to build up the Java object?
Also, the next case is when I have this element as java, I want to unmarshall this very part (to be able to extract the XML string of this element). But this is not possible. I get an exception about root elements. But it is not possible to annotate ElementNSImpl.
unable to marshal type "com.sun.org.apache.xerces.internal.dom.ElementNSImpl" as an element because it is missing an #XmlRootElement annotation
Do you have any suggestions on how to handle these problems?
#XmlAnyElement(lax = true) means in plain English something like:
Dear JAXB! If you have a mapping for this element, please unmarshal it
into a Java object. If you don't know this element, just leave it as a
DOM element.
This is exactly what is happening in your case. So if you want to actually unmarshal the content of this lax any, provide JAXB context with a mapping for the element you wish to unmarshal. The easiest way to do this is to annotate your class with #XmlRootElement
#XmlRootElement(name="foo", namespace="urn:bar")
public class MyClass { ... }
Now when you create your JAXB context, add MyClass into it:
JAXBContext context = JAXBContext.newInstance(A.class, B.class, ..., MyClass.class);
In this case, if JAXB meets the {urn:bar}foo element in the place of that xs:any, it will know that this element is mapped onto MyClass and will try to unmarshal MyClass.
If you are creating JAXB context based on the package name (you probably do), you can still add you class (say, com.acme.foo.MyClass) to it. The easiest way is to create a com/acme/foo/jaxb.index resource:
com.acme.foo.MyClass
And the add your package name to the context path:
JAXBContext context = JAXBContext.newInstance("org.dar.gee.schema:com.acme.foo");
There are other ways with ObjectFactory etc., but the trick with jaxb.index is probably the easiest one.
Alternatively, instead of unmarshalling everything in one run, you can leave the content of xs:any as DOM and unmarshal it into the target object in a second unmarshalling with anothe JAXB context (which know your MyClass class). Something like:
JAXBContext payloadContext = JAXBContext.newInstance(MyClass.class);
payloadContext.createUnmarshaller().unmarshal((Node) myPayload.getAny());
This approach is sometimes better, especially when you have a combination of container/payload schemas which are relatively independent. Depends on the case.
All said above applies to marshalling as well. It's all neatly bidirectional.
I think you need the XSDs for this "any" part and generate classes for them as well.
Here is some more information:
http://jaxb.java.net/guide/Mapping_of__xs_any___.html
Edit: if your object you want to marshal doesn't have the #XmlRootElement annotation (see error message), then I think you have to wrap it with a JAXBElement.
<xs:any/>
requires some not intuitive stuff to be converted to java object. If you have no difference, try using
<element name="any" type="xs:anyType"/>
Related
I am using JAXB, I have xsd files which I cannot modify which has elements with
minOccurs="0" nillable="true"
Which results that in the generated ObjectFactory class I have a lot of code like:
JAXBElement<SomeObject>
Then the code, that I have to write to both marshall and unmarshall is boilerplate and ugly.
Is there a way to generate somehow automaticaly another layer of abstraction so that I would have some other ObjectFactory class as well, but it would not operate on JAXBElement but instead would have it wrapped in some methods? Like it is when in the binding.xjb you specify the following:
<jaxb:globalBindings localScoping="toplevel" generateElementProperty="false">
which is unfortunately not an option for me.
My application is calling a webservice and I have generated the Java classes from the WSDL/XSDs with the maven-jaxb2-plugin. The webservice calls worked fine for a while but recently I had a problem on marshalling an object into XML:
[org.xml.sax.SAXParseException: cvc-complex-type.2.4.d: Invalid content was found starting with element 'ns1:TheFooAndBarThing'.
No child element '{"http://www.myschemanamespace.xyz/v1":BarId}' is expected at this point.]
The XSD part looks like this:
<xs:complexType name="TheFooAndBarThing">
<xs:sequence>
<xs:element name="FooId" minOccurs="1" maxOccurs="1" type="nx:FooIdType"/>
<xs:element name="BarId" minOccurs="1" maxOccurs="100" type="nx:BarIdType"/>
</xs:sequence>
</xs:complexType>
The generated class TheFooAndBarThing looks like this (Javadoc removed):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "TheFooAndBarThing", propOrder = {
"fooId",
"barId"
})
public class TheFooAndBarThing {
#XmlElement(name = "FooId", required = true)
protected String fooId;
#XmlElement(name = "BarId", required = true)
protected List<String> barId;
public String getFooId() {
return fooId;
}
public void setFooId(String value) {
this.fooId = value;
}
public List<String> getBarId() {
if (barId == null) {
barId = new ArrayList<String>();
}
return this.barId;
}
}
It cost me some time and coffee to find out the real problem. My mistake was that I put more than 100 BarId elements in my list.
So here's my question:
How can I get the maxOccurs/minOccurs value from the XSD into my Java code so that I can use it as a max/min value while building my list of elements?
Short answer: there is no easy way.
Schema-derived classes have no reference to the original schema anymore. Even if you use something as XSOM or whatever to parse the original schema, you will not be able to find corresponding XML Schema constructs to check.
The best way to address the issue would be writing a custom XJC plugin (I wrote quite a few of them).
When XJC compiles the schmema it first creates a model, then a so-called outline (pre-rendered code) and then renders the code. The model still has information about the original XML Schema constructs, so you can find all the relevant min/maxOccurs information there.
The problem is just that you don't always have 1:1 mapping between schema constructs and properties of schema-derived classes. Sometimes several elements are mapped onto one property. There's a huge number of exceptions and special cases. You can get it working for the straightforward cases, though. Anyway, the task is not easy.
Use could try JAXB-Facets.
Here is an example of setting specific values for minoccurs and maxoccurs:
#MinOccurs(value = 0)
#MaxOccurs(value = 100)
private List<String> test;
I have an XML content without defined attributes, like this:
<rootElement>
<subElement1/>
</rootElement>
I want to populate this XML content with required attributes defined in XML Schema (XSD) for this XML.
For example, according to XSD subElement1 has required attribute 'id'.
What is the best way (for Java processing) to detect that and add such attributes to XML?
We need to add required attributes and set appropriate values for them.
As a result for example above we need to have the following XML:
<rootElement>
<subElement1 id="some-value"/>
</rootElement>
In the XML schema definition, i.e. XSD file, attributes are optional by default. To make an attribute required, you have to define:
<xs:attribute name="surname" type="xs:string" use="required"/>
You will find a very good introduction on XML and XML Schema Definitions, i.e. XSD, on W3 Schools.
In Java the equivalent of defining a XML schema is using JAXB, i.e. Java API for XML Binding that is included into Java SE. There you would define, e.g.
#XmlRootElement
public class Person { public #XmlAttribute(required=true) String surname; }
Hope this could clarify your question.
I would suggest you to use JAXB for that. Search the Internet for tutorials.
Steps to proceed further with JAXB,
Generate Java files using JAXB by providing the schema
Unmarshal your XML to generated Java classes (beans). Don't do validation or set validation handler here.
Populate those classes with appropriate values. required elements can be found using annotation look up. JAXB annotation for element would look like something, #XmlElement(name = "ElementName", required = true). And an attribute annotation would be something similar to this, #XmlAttribute(required = true)
Marshal your bean back to XML. You can validate your bean using ValidationHandler, while marshalling. Below is the sample code snippet,
marshller = JAXBContext.newInstance(pkgOrClassName).createUnmarshaller();
marshller.setSchema(getSchema(xsd)); // skip this line for unmarshaller
marshller.setEventHandler(new ValidationHandler()); // skip this line for unmarshaller
Use a DOM parser.Has methods to traverse XML trees, access, insert, and delete nodes
I have had the same idea of Cris but I think that with this validator you don't have information about the point in which you have had the error.
I think that you have to create or extend your own validator.
I'm working on a xml schema resolver and I'm using JAXB with XMLSchema.xsd.
I experience problems with JAXB, because I don't get classes for all the top level elements. For example for
<xs:element name="maxLength" id="maxLength" type="xs:numFacet">
I do not get a class MaxLength or anything like that. Only NumFacet exists.
Anyone else experienced that and could please help me?
Cheers,
XLR
As far as I remember jaxb, the schema compiler xjc creates classes for each complex type of the schema given. Thus, if you like to have a class MaxLength you should add a complex type declaration to your schema:
<xs:complexType name="MaxLength">
<xs:attribute name="value" type="xs:int"/>
</xs:complexType>
<xs:element name="MyMaxLength" type="MaxLength"/>
You should now get a class MaxLength with a member variable value of type integer.
JAXB will not generate a class for anything that already has a type, and neither do you need one.
If you unmarshal a global element like your maxLength element, then JAXB will return you a JAXBElement wrapping the NumFacet type. Something like this:
JAXBElement<?> root = unmarshaller.unmarshal(myStream);
NumFacet value = (NumFacet) root.getValue();
There are other methods on JAXBElement to find out what the element name was, etc.
Do people have any recommendations on how i could write my own custom JAXB annotation handling class to support the generation of xs:annotation/xs:documentation elements in the xsd schema?. I'd like to create a new java annotation "#XmlAnnotation" which would include a "documentation" attribute. I'd then make these classes available to the JAXB schema generator via the classpath. The schema generator would then take this sample java code
#XmlRootElement(name="ClientData")
public class ClientData {
/**
* The first address field of the person
*/
#XmlAnnotation(documentation="The first address field of the client")
private String address1 = null;
}
and create this xsd schema
<xs:complexType name="clientData">
<xs:sequence>
<xs:element minOccurs="0" name="address1" type="xs:string">
<xs:annotation>
<xs:documentation>The first address field of the client</xs:documentation>
</xs:annotation>
Would it be easier to extend from the existing #XmlElement annotation class, and just add support of an extra documentation attribute?
This XmlRootElement is almost empty ( http://docjar.org/src/api/javax/xml/bind/annotation/XmlRootElement.java, there is not 'active' code inside
The main modification would be to change the code using this annotation and generating the xsd file.
That would only allow the construct for the root element. It is valid in just about ALL the xs namespace elements.
I don't understand why it wasn't supported as standard.