I'm using JaxB 2.2, can't use MOXy or other JaxB implementations due restrictions.
Is there a way to assign a created xsd to a Xml Element or Class in Eclipse? For example if I have an xsd in WebContent/validators/schemas and the file name is "foo.xsd" and I have a class in "foo.bar.classes" package named "foobar.java" with three fields "foo1" "foo2" "foo3". How do I assign the xsd to the class or the fields? I'm using #XMLElement and #XmlRootElement on that class. Thanks.
Related
I am confused as to how the #XmlElementDecl annotation is generated from a WSDL file that was generated by an XSD file. I have noticed that there are tags in my XSD file that are formatted in the following manner:
<xsd:element>...</xsd:element>
and others are formatted as such:
<element>...</element>
or they have a type="element" attribute. The latter two types do not generate any code that contains the #XmlElementDecl annotation, but the first format does.
The annotation is present in the ObjectFactory file.
Does this mean there is a requirement for the schema to have xsd:element as a prefix?
You have to use #XmlElementDecl along with #XmlRegistry annotation in the class to generate the element. You can find this link with an example.
https://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlElementDecl.html
I have autogenerated java classes from xsd using xsd2java. I cannot modify neither xsd nor the java classes.
Problem: in one class an element of List<JAXBElement> is generated.
If I now add any JAXBElement, the jackson xml marshaller won't show the proper xml element, but the properties of the JAXBElement serialized. Like declaredType, scope, etc. See below.
#XmlRootElement(name = "bookingRequest")
public class AutogeneratedReq {
private List<JAXBElement<?>> someElements;
}
Usage:
AutogeneratedReq req = new AutogeneratedReq();
JAXBElement<?> person = new ObjectFactory().createPerson();
req.getSomeElements().add(person);
Result:
<someElements>
<JAXBElement>
<name>person</name>
<declaredType>net.some.company.Person</declaredType>
<scope>net.some.company</scope><value someattribues="test"/>
<nil>false</nil>
<globalScope>false</globalScope>
<typeSubstituted>false</typeSubstituted>
</JAXBElement>
</someElements>
Question: how can I tell jackson or spring-mvc to generate proper xml, and not JAXBElement serialization explicit?
I don't know which xsd2java utility you currently use, but you can try the following maven plugin to generate Java classes from XSD files.
https://github.com/highsource/jaxb2-basics/wiki/Using-JAXB2-Basics-Plugins
And then you can use following extension to create correctly typed POJO's.
https://github.com/highsource/jaxb2-basics/wiki/JAXB2-Simplify-Plugin
BUT even if you can create typed POJO attributes, the XML file generated from this POJO may not be 100% valid against original XSD file.
<jaxb:bindings multiple="true" node="//xs:element[#name='someElement']//xs:complexType//xs:choice//xs:element">
<simplify:as-element-property/>
</jaxb:bindings>
I have a big XML file and several POJO clasess needed to read this XML. When i try read test file with one POJO i use this:
JAXBContext jaxbContext = JAXBContext.newInstance(Test.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Test ts = (Test)jaxbUnmarshaller.unmarshal(file);
System.out.println(ts.getName());
But when i have 30 POJOs what i gonna do? Create this 4 lines 30 times? Give me advice.
UPDATE
How i understand from this example http://blog.bdoughan.com/2010/08/using-xmlanyelement-to-build-generic.html
for using several POGOs i gonna use
JAXBContext.newInstance("message:customer:product:order");
And in this examle autor have 3 clesses but only in two of it he whire #XmlRootElement annotation. Why?
You could create JAXBContext with all 30 POJOs you have. Also you could store their names in jaxb.index index file in your package, and create JAXBContext.newInstance("your.package")
Here is some details about jaxb.index from javadoc
Alternatively than being listed in the context path, programmer annotated JAXB mapped classes can be listed in a jaxb.index resource file, format described below. Note that a java package can contain both schema-derived classes and user annotated JAXB classes. Additionally, the java package may contain JAXB package annotations that must be processed. (see JLS 3rd Edition, Section 7.4.1. "Package Annotations").
Your classes should be annotated with #XmlRootElement or #XmlType annotations.
Also you could find all classes annotated as #XmlRootElement using scannotation framework, and create JAXBContext with all JAXB POJOs you have.
Please if you have questions, comment and I will update an answer.
Hope it helps.
Ideally, you would create the JAXBContext only once and cache it for re-use. Now
But when i have 30 POJOs what i gonna do? Create this 4 lines 30 times?
If all of your 30 POJOs are in the same package (for e.g. com.abc) then create the context as JAXBContext.newInstance("com.abc")
In this examle autor have 3 clesses but only in two of it he whire #XmlRootElement annotation. Why?
Only the POJOs that correspond to the global element declarations in the XSD Schema have the #XmlRootElement annotation. This is because a global element declaration is a potential root element in an instance document.
It would be better if you can post a sample of your XML Schema and XML instance document for us to provide a more specific answer.
The following should help.
ANNOTATIONS
JAXB model classes do not require any annotations. There is not annotation that indicates that a class should automatically be processed when creating a JAXBContext.
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
CREATING A JAXBContext
There are two main ways of creating a JAXBContext
1 - On Classes
You pass in an array of domain classes. Mappings are then created for these classes. Mappings are also created for referenced (see WHAT CLASSES ARE BROUGHT IN below).
2 - On Context Paths
My article that you cited (http://blog.bdoughan.com/2010/08/using-xmlanyelement-to-build-generic.html) uses a context path. A context path consists of colon delimited package names. Each package must contain either a jaxb.index file or ObjectFactory class. The jaxb.index file is a carriage return separated list of class names you wish to create the JAXBContext on. Just as with creating a JAXBContext on an array of classes, reference classes are also processed.
WHAT CLASSES ARE BROUGHT IN
Below are some of the key concepts involved on what secondary classes are processed when creating a JAXBContext.
1 - Referenced Classes
If a JAXBContext is created on the Foo class, then Bar will also be processed since it is referenced by Foo.
#XmlAccessorType(XmlAccessType.FIELD)
public class Foo {
private List<Bar> bar;
}
2 - Super Classes
If a class is processed then its super class is also processed. You can put the #XmlTransient annotation on a class to prevent it from being processed (see: http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html).
public class Foo extends Bar {
}
3 - Subclasses
If a class is processed then its subclasses are not automatically processed. You can put the #XmlSeeAlso annotation on a class to specify its subclasses that you wish to process.
#XmlSeeAlso({Bar.class})
public class Foo {
}
4 - Classes Referenced from JAXB annotations
If a class is processed, then classes specified on JAXB annotations within that class are also processed
public class Foo {
#XmlElements({
#XmlElement(name="a", type=A.class),
#XmlElement(name="b", type=B.class)
})
private Object bar;
}
When i create a jaxbcontext with all my classes, jaxb build xml for a class with a namespace from other class.
If i pass to jaxbcontext only one class it work fine.
My classes are generated by xjc.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
})
#XmlRootElement(name = "eReq")
public class EReq {
...
And when i pass only this class to jaxbcontext the output is following.
<eReq><status>UNBLOCKED</status></eReq>
But i put all my classes into jaxb context output will be like this:
<eReq xmlns:ns2="myns1" xmlns:ns3="myns2" xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/"><status>UNBLOCKED</status></eReq>
This is namespaces from my other classes. Why jaxb put it to this class?
Why jaxb put it to this class?
Because the JAXB context contains the superset of all namespaces that it's created with, and it just puts them all in each document it generates.
It does this because the namespaces need to be added to the root element (to avoid hugely wasteful re-declaration of namespaces on each child element), and it doesn't know in advance which namespaces are required for any given set of bound objects (JAXB supports incremental serialization).
So the JAXB runtime probably could avoid doing that; but it doesn't.
If you don't like it, then you need to build multiple contexts.
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.