JAXB write namespaces to one class from other classes - java

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.

Related

How to use JAXBElement in jackson xml serialization?

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>

JaxB automatic parsing from XML to Java classes

I am new about jaxb. My question is the following: using jaxb, is it possible to do automatic mapping from an xml file to a java object?
Starting from xml file, is there something generate the Java class with annotations jaxb relaitve?
It is indeed possible. However, you'll need an XSD rather than an XML file. There are tools out there (Trang, for instance) that can infer an XSD from one or more example XML files.
Take into account that generating this XSD with a tool might get you inaccurate results if the XML sample isn't complete, or if the schema can't be fully represented in a single XML file (exclusive elements, etc).
Once you have an XSD, use xjc in order to generate the marshaller/unmarshaller classes.
xjc myxsd.xsd
This will generate the annotated classes that JAXB will use for marshalling/unmarshalling. Notice you could also have coded these classes yourself. Once you have them, just use them in your code:
File file = new File("myFile.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(MyRootElement.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
MyRootElement element = (MyRootElement) jaxbUnmarshaller.unmarshal(file);
Yes, JAXB automatically does marshalling and unmarshalling but it requires a schema file.
JaxB is used to bind XML with Java objects. Using the XSD schema file, it does marshalling and unmarshalling. There are few simple ant tasks like XJC that can be used.

Reading XML files in Java

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;
}

How do I assign a xsd location in JaxB

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.

Dynamically adding types to a jaxb context

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");

Categories

Resources