JAXB unmarshal XML elements to object wrapper - java

I am trying unmarshal XML to object with wrapped elements.
XML looks:
<?xml version="1.0" encding="utf-8"?>
<Output xmlns="_xxx_" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Companies>
<Company>
...
</Company>
<Company>
...
</Company>
...
</Companies>
<People>
<Person>
...
</Person>
<Person>
...
</Person>
...
</People>
<Relations>
<Relation>
...
</Relation>
<Relation>
...
</Relation>
...
</Relations>
<Info ... />
</Output>
I would like to have Compenies, People and Relations in Lists. I try this code, but it doesn't work:
Java Code
Ouput
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Output", namespace = "_xxx_")
#XmlType(propOrder={"companies", "people", "relations", "info"})
public class Output {
#XmlElementWrapper(name = "Companies")
#XmlElement(name = "Company" type = Company.class)
private List<Company> companies;
#XmlElementWrapper(name = "People")
#XmlElement(name = "Person", type = Person.class)
private List<Person> people;
#XmlElementWrapper(name = "Relations")
#XmlElement(name = "Relation", type = Relation.class)
private List<Relation> relations;
#XmlElement(name = "Info")
private Info info;
public Output() {
this.companies = new ArrayList<>();
this.people = new ArrayList<>();
this.relations = new ArrayList<>();
}
public List<Company> getCompanies() {
return companies;
}
public void setCompanies(List<Company> companies) {
this.companies = companies;
}
public List<Person> getPeople() {
return people;
}
public void setPeople(List<Person> people) {
this.people = people;
}
public List<Relation> getRelations() {
return relations;
}
public void setRelations(List<Relation> relations) {
this.relations = relations;
}
public Info getInfo() {
return info;
}
public void setInfo(Info info) {
this.info = info;
}
}
And for example Company looks (other classes are similar)
#XmlRootElement(name = "Company")
public class Company {
...
}
If I use this it creates empty Lists, but, if I change code to:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Output", namespace = "_xxx_")
#XmlType(propOrder={"companies", "people", "relations", "info"})
public class Output {
#XmlElement(name = "Companies")
private Companies companies;
#XmlElement(name = "People")
private People people;
....
public Companies getCompanies() {
return companies;
}
public void setCompanies(Companies companies) {
this.companies = companies;
}
...
}
where Companies class looks:
#XmlRootElement(name = "Companies")
#XmlAccessorType (XmlAccessType.FIELD)
public class Companies {
#XmlElement(name = "Company")
private List<Company> companies;
public List<Company> getCompanies() {
return companies;
}
public void setCompanies(List<Company> companies) {
this.companies = companies;
}
}
it works fine, but it isn't nice solution.
Can anyone advise me what is wrong here? Thanks :)

I solved my problem by using the instructions on this link. I use mapping to java.util.Map.

Related

How to set set namespace to xml in spring boot?

.....................I have pojo class:..............................
#Data
#XmlRootElement(name = "service", namespace = "xro")
#NoArgsConstructor
#AllArgsConstructor
public class Server {
private String objectType;
private String xRoadInstance;
private String memberClass;
private String memberCode;
#XmlAttribute(name = "objectType", namespace = "SERVER")
public String getObjectType() {
return objectType;
}
#XmlElement(namespace = "iden", name = "xRoadInstance")
public String getxRoadInstance() {
return xRoadInstance;
}
#XmlElement(namespace = "iden", name = "memberClass")
public String getMemberClass() {
return memberClass;
}
#XmlElement(namespace = "iden", name = "memberCode")
public String getMemberCode() {
return memberCode;
}
}
.....................I would like create xml from pojo like this:...............................
<xro:service iden:objectType="SERVICE">
<iden:xRoadInstance>?</iden:xRoadInstance>
<iden:memberClass>?</iden:memberClass>
<iden:memberCode>?</iden:memberCode>
<iden:subsystemCode>?</iden:subsystemCode>
<iden:serviceCode>?</iden:serviceCode>
<iden:serviceVersion>?</iden:serviceVersion>
</xro:service>
.......................But my my pojo generates xml this: ...............................
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:service xmlns="iden" xmlns:ns2="SERVER" xmlns:ns3="xro" ns2:objectType="SERVICE">
<memberClass>test</memberClass>
<memberCode>test</memberCode>
<xRoadInstance>test</xRoadInstance>
</ns3:service>
Whats wrong in my pojo?

Unmarshaling xml with tags contains attributes only to List

I can’t understand what I am doing wrong.I need to unmarshal xml file that looks like this:
<ApplicationMetadata xmlns="http://www.sas.com/xml/schema/namespace/ApplicationMetadata-9.4">
<Role Name="name1" Desc="desc1 " DisplayName="disp1 ">
<Members/>
<ContributingRoles/>
<Capabilities>
<Capability CapabilityId="1"/>
<Capability CapabilityId="2"/>
<Capability CapabilityId="3"/>
</Capabilities>
</Role>
<Role Name="name2" Desc="desc2" DisplayName="disp2">
<Members>
<UserGroup Name="userGoup"/>
</Members>
<ContributingRoles/>
<Capabilities>
<Capability CapabilityId="1"/>
<Capability CapabilityId="2"/>
</Capabilities>
</Role>
</ApplicationMetadata>
I have next classes:
#XmlRootElement(name = "ApplicationMetadata", namespace = "http://www.sas.com/xml/schema/namespace/ApplicationMetadata-9.4")
#XmlAccessorType(XmlAccessType.FIELD)
public class ApplicationMetaData {
#XmlElement(name = "Role")
private List<Role> roles;
getters and setters
}
#XmlRootElement(name = "Role")
#XmlAccessorType(XmlAccessType.FIELD)
public class Role {
#XmlAttribute(name = "Name")
private String name;
#XmlAttribute(name = "Desc")
private String desc;
#XmlAttribute(name = "DisplayName")
private String displayName;
#XmlElementWrapper(name = "ContributingRoles")
#XmlElement(name = "UserGroup")
private List<UserGroup> contributionRoles;
#XmlElementWrapper(name = "Members")
#XmlElement(name = "UserGroup")
private List<UserGroup> members;
#XmlElementWrapper(name = "Capabilities")
#XmlElement(name = "Capability")
private List<Capability> capabilities;
getters and setters
}
#XmlRootElement(name = "Capability")
#XmlAccessorType(XmlAccessType.FIELD)
public class Capability {
#XmlAttribute(name = "CapabilityId")
private String id;
getters and setters
}
#XmlRootElement (name = "UserGroup")
#XmlAccessorType(XmlAccessType.FIELD)
public class UserGroup {
#XmlAttribute(name = "Name")
private String name;
getters and setters
}
My code for unmarshaling is:
File file = new File(fileName);
ApplicationMetaData appMetaData = (ApplicationMetaData)
WorkWithXml.unmarshalXml(file, ApplicationMetaData.class);
public static Object unmarshalXml(File file, Class unmarshallerClass) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(unmarshallerClass);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
return unmarshaller.unmarshal(file);
} catch (JAXBException e) {
LOG.error("", e);
throw new AutotestError(e);
}
}
As result I have appMetaData object with all roles from file. Roles has attributes, but all lists inside roles are empty. Not null, but empty. Where I have a mistake?
P.S. It is all about Java code :)
I have done it :)
Instead
#XmlElementWrapper(name = "Capabilities")
#XmlElement(name = "Capability")
private List<Capability> capabilities;
in Role class I have used
#XmlElement (name = "Capabilities")
Capabilities capabilities;
And here Capabilities class
#XmlRootElement(name = "Capabilities")
#XmlAccessorType(XmlAccessType.FIELD)
public class Capabilities {
#XmlElement(name = "Capability")
private List<Capability> capability;
public List<Capability> getCapability() {
return capability;
}
public void setCapability(List<Capability> capability) {
this.capability = capability;
}
}

#XmlElementWrapper not taken into account in XML/REST Spring webservice

I want to give custom names to the xml root element and to list elements.
But the annotations don't work.
#XmlRootElement(name = "test")
#XmlAccessorType(XmlAccessType.FIELD)
public class TestRsp {
#XmlElementWrapper(name = "persons")
#XmlElement(name = "pax")
private List<Person> persons;
}
public class Person {
private String name;
private String age;
}
Usage:
#RestController
public class MyServlet {
#RequestMapping("/test")
public TestRsp test() {
//...
return rsp;
}
}
Result:
<TestRsp> <!-- should be named "test" -->
<persons>
<persons> <!-- should be named "pax" -->
<name />
<age />
</persons>
<persons>
//...
</persons>
</persons>
</TestRsp>
So my xml annotations are not picked up. But why?
Try using #JsonProperty annotation.
It should look something like thit:
#JsonProperty("test")
EDIT 1:
Try annotating the getter of the fields that you want to change like so:
#XmlElement(name="someName")
EDIT 2:
#XmlRootElement(name="persons")
public class Root {
private List<String> someList;
#XmlElement(name="pax")
public List<String> getSomeList() {
return someList;
}
public void setSomeList(List<String> someList) {
this.someList = someList;
}
public Root(String numValue,List<String> someListValue) {
this();
this.number = numValue;
this.someList = someListValue;
}
/**
*
*/
public Root() {
// TODO Auto-generated constructor stub
}
}
Maybe this will provide:
<persons>
<pax>FOO</pax>
<pax>BAR</pax>
</persons>
EDIT 3:
Maybe if you want to make your solution works you need to add a file called jaxb.properties in with your model classes with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
It turned out I have to use #JacksonXml* annotations instead:
#JacksonXmlRootElement(localName = "test")
public class TestRsp {
#JacksonXmlElementWrapper(localName = "persons")
#JacksonXmlProperty(localName = "pax")
#JsonProperty(name = "persons")
private List<Person> persons;
}

JAX-WS: XmlElementWrapper produces extra client code

I have some service with some WebMethod that returns object of Foo class:
public class Foo {
private List<Detail> detailList;
#XmlElement(name = "detail")
#XmlElementWrapper(name = "detailList")
public List<Detail> getDetailList() {
return detailList;
}
public void setDetailList(List<Detail> value) {
this.detailList = value;
}
public Foo() {
this.detailList = new ArrayList();
}
}
This code produces proper XML like:
<detailList>
<detail>
<key></key>
<value></value>
</detail>
<detail>
<key></key>
<value></value>
</detail>
<detailList/>
After building client JAR library it works OK.
But I really don't like the code I need to call to get the List:
foo.getDetailList().getDetail();
Because getDetailList() returns DetailList object.
How can I have getDetailList() method returning List without any changes in above XML?
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Root", propOrder = {
"detailList"
})
public class Foo {
#XmlElementWrapper(name = "detailList", required = true)
#XmlElement(name = "detail")
private List<Detail> detailList;
public List<Detail> getDetailList() {
return detailList;
}
public void setDetailList(List<Detail> value) {
this.detailList = value;
}
public Foo() {
this.detailList = new ArrayList();
}
}

How to change the name of the XmlRootElement in JAXB deppending on the object?

I have the following objects
Film
#Entity
#Table(name="film")
#XmlRootElement(name = "film")
public class Film implements Serializable {
#Id
#Column(name="id")
private String fbId;
#Column(name="title")
private String title;
#ManyToMany
#JoinTable(
name="direction",
joinColumns={#JoinColumn(name="film", referencedColumnName="id")},
inverseJoinColumns={#JoinColumn(name="person", referencedColumnName="id")})
private Collection<Person> directors;
#OneToMany(cascade={CascadeType.ALL}, mappedBy="film")
#MapKey(name="character")
private Map<String, Performance> performances;
//GETTERS
#XmlAttribute(name = "fbId")
public String getFreebaseId() {
return this.fbId;
}
#XmlElementRefs({
#XmlElementRef(name="director", type=Person.class)
})
public Collection<Person> getDirectors() {
return this.directors;
}
#XmlAnyElement(lax=true)
public Collection<Performance> getPerformances() {
ArrayList performancesArray = new ArrayList<Performance>();
for (Map.Entry<String, Performance> entry : this.performances.entrySet()) {
Performance value = entry.getValue();
performancesArray.add(value);
}
return performancesArray;
}
}
Person
#Entity
#Table(name="person")
public class Person implements Serializable {
#Id
#Column(name="id")
private String fbId;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#OneToMany(cascade={CascadeType.ALL}, mappedBy="actor")
#XmlTransient
private Collection<Performance> performances;
//GETTERS
#XmlAttribute(name = "fbId")
public String getFreebaseId() {
return this.fbId;
}
#XmlElement(name = "firstName")
public String getFirstName() {
return this.firstName;
}
#XmlElement(name = "lastName")
public String getLastName() {
return this.lastName;
}
#XmlTransient
public Collection<Performance> getPerformances() {
return this.performances;
}
}
Each film has one (or many) directors and performances which are "Persons". I don't need a class for directors but I do for perfomances because they have more info.
Performance
#Entity
#Table(name="performance")
#XmlRootElement(name = "performace")
public class Performance implements Serializable {
#Id
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="film")
private Film film;
#Id
#Column(name="film_character")
private String character;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="actor")
private Person actor;
//TO STRING
public String toString() {
return this.actor.toString() + " - " + this.character;
}
//GETTERS
#XmlTransient
public Film getFilm() {
return this.film;
}
#XmlElementRefs({
#XmlElementRef(name = "firstName", type = Person.class),
#XmlElementRef(name = "lastName", type = Person.class)
})
public Person getActor() {
return this.actor;
}
#XmlElement(name = "character")
public String getCharacter() {
return this.character;
}
}
When I run this through JAXB I get this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<film fbId="1">
<description>Nice film</description>
<person fbId="1">
<firstName>Quentin</firstName>
<lastName>Tarantino</lastName>
</person>
<performace>
<person fbId="4">
<firstName>Steve</firstName>
<lastName>Buscemi</lastName>
</person>
<character>Billy</character>
</performace>
<performace>
<person fbId="2">
<firstName>Jhon</firstName>
<lastName>Travolta</lastName>
</person>
<character>Vincent</character>
</performace>
<performace>
<person fbId="3">
<firstName>Samuel</firstName>
<lastName>L Jackson</lastName>
</person>
<character>Jules</character>
</performace>
<performace>
<person fbId="1">
<firstName>Quentin</firstName>
<lastName>Tarantino</lastName>
</person>
<character>Jimmie</character>
</performace>
<title>Pulp Fiction</title>
</film>
Is there a way to change the name of the "person"? To get something like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<film fbId="1">
<description>Nice film</description>
<director fbId="1">
<firstName>Quentin</firstName>
<lastName>Tarantino</lastName>
</director>
<performace fbId="4">
<firstName>Steve</firstName>
<lastName>Buscemi</lastName>
<character>Billy</character>
</performace>
<performace fbId="2">
<firstName>Jhon</firstName>
<lastName>Travolta</lastName>
<character>Vincent</character>
</performace>
<performace fbId="3">
<firstName>Samuel</firstName>
<lastName>L Jackson</lastName>
<character>Jules</character>
</performace>
<performace fbId="1">
<firstName>Quentin</firstName>
<lastName>Tarantino</lastName>
<character>Jimmie</character>
</performace>
<title>Pulp Fiction</title>
</film>
Options:
Make Director extends Person with its own #XmlRootElement
Use JAXBElement<? extends Person> instead of Person
The problem is, #XmlElementRef.name does not work for #XmlRootElement, read here:
If type() is JAXBElement.class , then namespace() and name() point to
a factory method with XmlElementDecl. The XML element name is the
element name from the factory method's XmlElementDecl annotation or if
an element from its substitution group (of which it is a head element)
has been substituted in the XML document, then the element name is
from the XmlElementDecl on the substituted element.
If type() is not JAXBElement.class, then the XML element name is the
XML element name statically associated with the type using the
annotation XmlRootElement on the type. If the type is not annotated
with an XmlElementDecl, then it is an error.
If type() is not JAXBElement.class, then this value must be "".
By the way
#XmlElementRefs({
#XmlElementRef(name = "firstName", type = Person.class),
#XmlElementRef(name = "lastName", type = Person.class)
})
does not seem valid to me. #XmlElementRef are not supposed to map properties of the target class.

Categories

Resources