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;
}
Related
I am using the tutorial here for understanding JAXB.
When the writer comes to create the root of the document, the writer begins as below:
//This statement means that class "Bookstore.java" is the root-element of our example
#XmlRootElement(namespace = "de.vogella.xml.jaxb.model")
public class Bookstore {
...
}
Although I will be manually generating my classes rather than letting Eclipse do it, I will supply an XSD with my jar file (not packed inside but rather in the folder containing jar file) so that when my application starts, it will validate whether the XML document has been tampered with.
So, in the XSD file, the targetNamespace will be de.vogella.xml.jaxb.model because it was declared above as #XmlRootElement(namespace = "de.vogella.xml.jaxb.model") ?
I recommend using the package level #XmlSchema annotation to specify the namespace qualification for you model. A package level annotation goes in a special class called package-info that contains the exact content as shown below. That annotation will mean that all elements in your document without an explicit namespace given will use that namespace.
org/example/foo/package-info.java
#XmlSchema(
namespace = "http://www.example.org/foo",
elementFormDefault = XmlNsForm.QUALIFIED)
package org.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Overriding the Namespace
You can override the namespace given in the #XmlSchema for all properties in a class using the #XmlType annotation.
You can override the namespace for a given element using the namespace property on the #XmlRootElement or #XmlElement annotation.
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html
#XmlRootElement annotation can be used to map a class or enum type to XML type.
When a top level class or an enum type is annotated with the #XmlRootElement annotation, then its value is represented as XML element in an XML document.
Follow the example given below to get more idea:
Associate an element with XML Schema type
// Example: Code fragment
#XmlRootElement
class Point {
int x;
int y;
Point(int _x,int _y) {x=_x;y=_y;}
}
//Example: Code fragment corresponding to XML output
marshal( new Point(3,5), System.out);
<!-- Example: XML output -->
<point>
<x> 3 </x>
<y> 5 </y>
</point>
I'm working with a xml file that is generated and used in a .NET application.
I need to deserialize this file in Java and chose to use JAXB.
However, after trying to create the matching class I figured out one major difference.
When having a
#XmlRootElement
public class SomeClass{
List<NestedClass> classes;
}
I get the following structure:
<SomeClass>
...
<NestedClasses>
...
</NestedClasses>
<NestedClasses>
...
</NestedClasses>
</SomeClass>
As oppesed to the required existing structure:
<SomeClass>
...
<NestedClasses>
<NestedClass>
...
</NestedClass>
<NestedClass>
...
</NestedClass>
</NestedClasses>
</SomeClass>
Is there is a way to get my required structure without adding a class that will only contain the list of the nested class?
You will need to have a class that wraps the collection. To get the desired mapping, you can use the #XmlElementWrapper annotation to specify that a grouping element should be used. Then you can use the #XmlElement annotation to specify the name of the element that represents the items in the collection:
#XmlRootElement
public class SomeClass{
#XmlElementWrapper
#XmlElement(name="NestedClass")
List<NestedClass> classes;
}
For More Information
http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html
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'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.
I have multiple plug-ins in my RCP-based project. I want to be able to define #XMLElements in one plug-in that can then be marshaled / un-marshaled from the core plugin. To do so, I report the classes that are serializable as soon as the plug-in is loaded. However, dynamically adding classes seems to be not supported by the JAXBContext. I implemented a work-around by holding all classes in a list and creating a new JAXBContext every time some new classes are reported based on that list, but this solution is not really nice.
Is there a better way to do that?
You definitely can not add classes dynamically to a JAXBContext. This has to do with maintaining the thread safety of JAXBContext.
I have recently posted an example on my blog explaining how to leverage the #XmlAnyElement annotation to generate a generic message that could have different payloads:
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
Root Object
The root element for the body property will be controlled by that objects #XmlRootElement.
package message;
import javax.xml.bind.annotation.*;
#XmlRootElement#XmlAccessorType(XmlAccessType.FIELD)
public class Message {
#XmlAttribute
private String to;
#XmlAttribute
private String from;
#XmlAnyElement
private Object body;
}
Creating the JAXBContext
Instead of creating the JAXBContext on an array of classes, the JAXBContext could be created on a context path:
JAXBContext.newInstance("message:customer:product");
This context path includes 3 package names seperated by the colon ':' character. In each of these packages we need to include a file named jaxb.index with a list of files. Below is an example of the jaxb.index file in the customer package:
Address
Customer
When we want to add a model to represent orders to our framework we would extend our JAXBContext creation to like (this String could be passed in as a variable):
JAXBContext.newInstance("message:customer:product:order");