This question already has answers here:
JAXB Compiler and Attribute Order [duplicate]
(3 answers)
Closed 5 years ago.
I have two classes:
#XmlSeeAlso(ListType.class)
public class Type {
private int id;
public int getId() {
return id;
}
#XmlAttribute
public void setId(int id) {
this.id = id;
}
}
#XmlRootElement
public class ListType extends Type {
private String name;
private String namespace;
public String getName() {
return name;
}
#XmlAttribute
public void setName(String name) {
this.name = name;
}
public String getNamespace() {
return namespace;
}
#XmlAttribute
public void setNamespace(String namespace) {
this.namespace = namespace;
}
}
And I make marshalling:
ListType listType = new ListType();
listType.setId(123);
listType.setName("Name");
listType.setNamespace("Namespace");
JAXBContext jaxbContext = JAXBContext.newInstance(UserType.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(listType, System.out);
Finally, I get XML like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<listUserType name="Name" namespace="Namespace" id="123"/>
All is well, just tell me, how can I specify the order of the attributes in my XML?
I want them to go in this order:
<listType id="123" name="Name" namespace="Namespace" />
This is very necessary for solving my task. Thank you
Annotate the parent class with #XmlTransient, it will help you to include the properties from parent class then
add this #XmlType(propOrder={"Id", "Name", "Namespace"}) on top of ListUserType class.
Related
I have 3 input XML that have, pretty much, the same elements and attributes, in fact, they represent the same thing, so I want to marshall them to the same object, something like this:
Request One:
<?xml version="1.0" encoding="UTF-8"?>
<RequestOne>
<id>123</id>
<name>foo</name>
</RequestOne>
Request Two:
<?xml version="1.0" encoding="UTF-8"?>
<RequestTwo>
<id>123</id>
<value>val</value>
</RequestTwo>
Request Three:
<?xml version="1.0" encoding="UTF-8"?>
<RequestThree>
<name>foo</name>
<value>val</value>
</RequestThree>
Desired Object (something like):
#XmlRootElement
public class Resource{
#XmlElement
private String id;
#XmlElement
private String name;
#XmlElement
private String value;
//(...) more code
}
But I can't use multiple RootElement annotations to ask JAXB to unmarshall all of the 3 request to objects of the class Resource
Is there a way to do it? Or I must make the 3 sepparated classes?
Thanks for your help
Option 1
Unmarshal using the overloaded Generic unmarshal method :
public static class Base {
private String name ;
#XmlElement(name = "name")
public String getName() {
return name;
}
public Base setName(String name) {
this.name = name;
return this;
}
}
public static void main (String [] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Base.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<Base> basea = unmarshaller.unmarshal(new StreamSource(new StringReader("<RootA><name>nanana</name></RootA>")), Base.class);
System.out.println(basea.getValue().getName());
JAXBElement<Base> baseb = unmarshaller.unmarshal(new StreamSource(new StringReader("<RootB><name>nbnbnb</name></RootB>")), Base.class);
System.out.println(baseb.getValue().getName());
}
Option 2
You can always use Java's class subtyping capabilites ? JAXB does annotation scanning on parent class as well. This example works
public static class Base {
private String name ;
#XmlElement(name = "name")
public String getName() {
return name;
}
public Base setName(String name) {
this.name = name;
return this;
}
}
#XmlRootElement( name = "RootA")
public static class RootA extends Base{
}
#XmlRootElement( name = "RootB")
public static class RootB extends Base {
}
public static void main (String [] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(RootA.class,RootB.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
RootA rootA = (RootA)unmarshaller.unmarshal(new StringReader("<RootA><name>nanana</name></RootA>"));
System.out.println(rootA.getName());
RootB rootB = (RootB)unmarshaller.unmarshal(new StringReader("<RootB><name>nbnbnb</name></RootB>"));
System.out.println(rootB.getName());
}
I have to check whether I have getting string in integer field in xml when unmarshaling using JAXB.
Implementation Class:
import java.io.IOException;
import javax.xml.bind.JAXB;
public class JAXBDemo {
public static void main(String[] args) throws IOException {
try {
String xmlString = "file:///c:/xml/stud.xml";
// unmarshal XML string to class
Student st = JAXB.unmarshal(xmlString, Student.class);
// prints
System.out.println("Age : "+st.getAge());
System.out.println("Name : "+st.getName());
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
Mapping Class :
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Student{
String name;
int age;
int id;
public String getName(){
return name;
}
#XmlElement
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
#XmlElement
public void setAge(int age){
this.age = age;
}
public int getId(){
return id;
}
#XmlAttribute
public void setId(int id){
this.id = id;
}
}
Input XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student id="10">
<age>hello</age>
<name>Malik</name>
</student>
Output:
Age : 0
Name : Malik
when I give String value in integer field it gives as zero. I have to check how to check an integer field in xml having non numeric value and throw an error.
JAXB is a convenience class that encompass JAXBContext, Unmarshaller and other JAXB API libraries to make it easier to perform simple operations.
The problem with it, that it's not really dealing with issues like validating the schemas and performance issues. it'll try to do a "best effort" and ignore issues for not matching data fields, such as String in an int field.
in order to circumvent that, you'll have to use the JAXB API directly, and validate the schema during the unmarshaling process.
I haven't tested this code, but it should be something similar to this:
JAXBContext jc = JAXBContext.newInstance(Student.class);
Unmarshaller u = jc.createUnmarshaller();
Student st = u.unmarshal(new File(xmlString));
you might need to explicitly cast the unmarshal to Student, i.e:
Student st = (Student)u.unmarshal(new File(xmlString));
JAXB annotated class:
#XmlRootElement(name = "group")
#XmlType(propOrder = {"name", "description", "types" })
public class GroupElement implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String description;
private String name;
private List<TypeElement> types;
#XmlTransient
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#XmlElement(name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "type")
public List<TypeElement> getTypes() {
return types;
}
public void setTypes(List<TypeElement> types) {
this.types= types;
}
}
java-package.info
#XmlSchema(namespace = "http://www.test.at/r1/v1" ,
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns={#XmlNs(prefix="cdr1", namespaceURI="http://www.test.at/r1/v1")})
JAXB marshalling:
JAXBContext jaxbContext = JAXBContext.newInstance(Group.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(group, sw);
I need to set the namespace dynamically depending on the group. With the package-info approach I get the same namespace in every XML file.
I also tried
JAXBElement<Group> element = new JAXBElement<Group>(new
QName(latestStructure.getNamespace(), "group", "cdr1"),
Group.class, group);
But With this approach only the root element gets the namespace and prefix assigned.
Does anyone have an idea how to do this?
You could remove namespace info from the class and package, but create object factories with qualified names (so as many object factories as many namespaces),
#XmlRegistry
public class ObjectFactory {
...
}
and then use the correct factory to initiate your context instead of the Group class:
JAXBContext.newInstance(ObjectFactory.class);
For me easier would be to again use beans without namespaces, marshall to namespace free xml and transform the xml using xslt to add correct "dynamic" namespace as required.
I am using JAXB to unmarshal an XML file.
All I know about the XML file is that it is valid XML.
How then am I supposed to specify a class and/or package to newInstance?
JAXBContext jaxbContext = JAXBContext.newInstance(??????);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object o = (Object) unmarshaller.unmarshal(myFile);
I did not see anything in the docs that address this issue.
You need to tell JaxB what class to unmarshall to so that it can use the annotations in the class to resolve the hierarchy of the xml. You will need to have a class that is also annotated with something like #XmlRootElement. If you want to parse arbitrary xml you will probably need to do something with a DocumentBuilder or xpath.
See this artical for more info.
http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html
I have used something like this to convert arbitrary xml to a class. The any field will actually be a list of org.w3c.dom.Element in which you can get information from.
http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/Element.html
#XmlRootElement
class Wrapper {
/**
* Everything else
*/
#Transient
#XmlAnyElement(lax = true)
private List<Element> any;
public List<Element> getAny() {
return any;
}
}
In newInstance you must add the class root element that map your xml... below an example
Here an example ..
public static void main(String[] args) throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(Vehicals.class);
final Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
final Vehicals vehicals = new Vehicals();
List<Car> cars = new ArrayList<Car>();
Car c = new Car();
c.setName("Mercedes");
cars.add(c);
c = new Car();
c.setName("BMW");
cars.add(c);
vehicals.setCar(cars);
m.marshal(vehicals, System.out);
}
Vehicals.java
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Vehicals {
private List<Car> Car;
public List<Car> getCar() {
return Car;
}
public void setCar(List<Car> cars) {
this.Car = cars;
}
}
Car.java
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlRootElement
public class Car {
#XmlTransient
private Long id;
private String name;
#XmlTransient
private String code;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
output.xml
<Vehicle>
<Car>
<name>Mercedes</name>
</Car>
<Car>
<name>BMW</name>
</Car>
</Vehicle>
For the Unmarshal is the same thing. In my case i added Vehicals as parameter in newInstance method.
Given this XML:
<response>
<detail Id="123" Length="10" Width="20" Height="30" />
</response>
This is what I have now, but it is not working (I'm getting empty result):
#XmlRootElement(name="response")
public class MyResponse {
List<ResponseDetail> response;
//+getters +setters +constructor
}
public class MyResponseDetail {
Integer Id;
Integer Length;
Integer Width;
Integer Height;
//+getters +setters
}
I'm making a call to a remote service using RestOperations and I want to parse the <detail ..> element. I've tried passing both MyResponse and MyResponseDetail classes to RestOperations but the result is always empty.
What should my object structure look like to match that XML?
You need to annotate your classes like that:
#XmlRootElement
public class Response {
private List<Detail> detail;
public void setDetail(List<Detail> detail) {
this.detail = detail;
}
public List<Detail> getDetail() {
return detail;
}
}
public class Detail {
private String id;
/* add other attributes here */
#XmlAttribute(name = "Id")
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}