I have the following xml:
Company.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
<employeeList>
<employee name="Jane Doe" id="A">
</employee>
<employee name="John Smith" id="B">
</employee>
<employee name="Anne Jones" id="C">
</employee>
</employeeList>
</company>
Department.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<departmentList>
<departmentList>
<department name="Dev" id="1">
<employee>A</employee>
<employee>B</employee>
</department>
<department name="Sales" id="2">
<employee>C</employee>
</department>
</departmentList>
</departmentList>
The class Department.java has an employee list
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Department {
#XmlAttribute
private String id;
#XmlElement(name="employee")
#XmlJavaTypeAdapter(EmpAdapter.class)
public List<Employee> employeeList;
public Department(){
employeeList = new ArrayList<Employee>();
}
and the employee.java class has an id attribute with the #XmlId tag.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
#XmlAttribute
#XmlID
private String id;
I know how to get the employee objects to be pointed at from the department object using an adapter. However that is if the Company.xml file is unmarshalled first because it has the employee details in it.
So what I want is to be able to unmarshall the Department.xml first and have it create some sort of placeholder so that once the Company.xml has been unmarshalled the employeeList in the department object is filled in.
EDIT
POSSIBLE SOLUTION: As suggested by #laune I can use the adapter to create Employee objects as a placeholder, and then once the employee list is unmarshalled fill in these details in the employee objects under the department class
WHAT I NEED:
But this way I have to always handle each of the cases individually through code and new methods. Main problem is I cannot predict the order in which the unmarshalling will happen. Is there a way to have JAXB unmarshall without worrying about dependencies and ordering of creating objects? Maybe using schemas?
You can modify the EmpAdapter to return a placeholder Employee object created from an (additional) constructor
public Employee( String id ){
this.id = id;
}
Also, the EmpAdapter should maintain a Map<String,Employee> mapping ids to employees.
After you have unmarshalled the employees into a flat list, iterate the list and fill the fields of the placeholder (located via the map) from the list element.
Things would be much easier if employee data contains the deparment id.
Related
I am trying to create XML using the Moxy Marshalling approach. Everything seems to be working fine except for one small thing. Basically, I would like to know how to add wrapper element to the class itself during the marshalling.
As we are aware we can add #XmlPath("test/name/text()") to add a wrapper to any of the String elements. Also for collection we can make use of #XmlElementWrapper(name="languages"), #XmlElement(name="language"). But these are for the fields within the class. How can I add the wrapper element to the class itself which is being marshalled?
I have the following class:
#XmlRootElement(name = "customer")
#XmlType(name="customer",propOrder={"name","languages"})
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer{
#XmlPath("extension/name/text()")
private String name;
#XmlElementWrapper(name = "languages")
#XmlElement(name = "language")
private List<String> languages;
//Getter, Setter and other constuctors
}
This will produce the output XML something like this:
<customer>
<extension>
<name>Hello</name>
</extension>
<languages>
<language>English</language>
<language>UK English</language>
</languages>
</customer>
However, I would like to add the wrapper element to event the whole class so that output would look something like this: (Notice the whole customer is wrapper within classWrapper)
<classWrapper>
<customer>
<extension>
<name>Hello</name>
</extension>
<languages>
<language>English</language>
<language>UK English</language>
</languages>
</customer>
</classWrapper>
I tried adding the #XmlPath and #XmlElementWrapper to the Customer class but it throws an error as it can be added only to the fields within the class but not to the whole class.
Following is my Main class which would be used for marshalling:
public class HelloWorld{
public static void main(String []args){
Customer customer = new Customer();
List<String> languages = new ArrayList<String>();
languages.add("English");
languages.add("UK English");
customer.setName("Hello");
customer.setLanguages(languages);
JAXBContext context = JAXBContext.newInstance(Customer.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(customer,System.out);
}
}
I am aware that I can write another wrapper class add the custom field to it then use that wrapper class for the marshalling. Actually, I am doing the same as of now. However, trying to find if there is some Moxy approach of doing this similar to how we have #XmlPath and #XmlElementWrapper
Can someone please suggest some form of Moxy Jaxb related approach for achieving the wrapper element to the whole class?
This is a temporary workaround that works as expected for me. Posting the answer here so it can be helpful to someone in the future.
Change the #XmlRootElement("customer") to #XmlRootElement("classWrapper"). So you will get the classWrapper as the outer element.
Then change all the element within the Customer class using the #XmlPath so that all element go under the Customer tag. So overall customer.class would look something like this:
#XmlRootElement(name = "classWrapper")
#XmlType(name="customer",propOrder={"name","languages"})
#XmlAccessorType(XmlAccessType.FIELD)
#Getter
#Setter
public class Customer{
#XmlPath("customer/extension/name/text()")
private String name;
#XmlPath("customer/languages/language/text()")
private List<String> languages;
//Getter, Setter and other constuctors
}
Just a tip while using the #XmlPath:
do not use text() if its not simple type such as String,Date, etc type.
For example if the element is of Custom type with List then do not use /text()
#XmlPath("extension/elements/element")
List<myType> elements;
This will add extension -> elements -> element then content.
<extension>
<elements>
<element></element>
<element></element>
......
</elements>
</extension>
If the elements are of String type then you have to use text()
#XmlPath("extension/elements/text()")
List<String> elements;
<MyRoot>
<Person>
<Name>Joe</Name>
<Age>20</Age>
</Person>
<Address>
<HouseName>Joe</HouseName>
<Place>Delhi</Place>
</Address>
<Person>
<Name>James</Name>
<Age>21</Age>
</Person>
<Address>
<HouseName>Joe</HouseName>
<Place>Mumbai</Place>
</Address>
</MyRoot>
From above xml, you can see that person and address tag is not wrapped in a wrapper tag. I want to generate an xml using JAXB in same format. I don't know how to do that without a wrapper tag.
Are you looking into creating java object that contains a list of Persons and a list of addresses?
public class MyRootObject {
private List<Person> persons;
private List<Address> addresses;
}
If the above is what you intend on doing then note that the XML object will change...
If you really want to preserve a mixed sequence like <Person> <Address> <Person> <Address> (as you say in your comment to #Vankuisher's answer),
then you need to keep the Persons and Addresses not in 2 separate Lists,
but together within the same List.
For that to work Person and Address must be subclasses of a common superclass
(e.g. class Person extends Item and class Address extends Item).
Then you use an #XmlElements annotation to define the mapping between
XML element names and Java classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "MyRoot")
public class MyRoot {
#XmlElements({
#XmlElement(name = "Address", type = Address.class),
#XmlElement(name = "Person", type = Person.class)
})
private List<Item> items;
// public getters and setters (omitted here for brevity)
}
When marshalling such a MyRoot object you will get an XML output
with the same sequence of items as given within the List<Item>.
I have a mapping from a DTO model to a JAXB generated datamodel that is full of JAXBElement<> wrapper objects.
For example, there is a class Person defined as (getters and setters are omitted):
public class Person {
private JAXBElement<Name> name;
}
Name is defined as:
public class Name {
private String value;
}
For constructing JAXBElement I created an ObjectFactory:
public class NameFactory extends ObjectFactory<JAXBElement<Name>> {
protected JAXBElement<Name> createObject(#Nonnull Class<?> context) {
// here, ObjectFactory is the JAXB generated ObjectFactory
return new ObjectFactory().createName();
}
}
In my ConfigurableMapper I create a class mapping from PersonDto to Person like so:
factory.createClassMap(PersonDto.class, Person.class)
.field("name", "name.value.value")
.register;
With this config, the mapping of a PersonDto with no name (name equals null) will result in a Person element that has a name member with its value set to null. This is probably better explained by showing the XML that is generated after performing the class mapping:
<Person>
<Name>
<value></value>
</Name>
</Person>
In my case, this XML is invalid, when there is a Name element, its value should always be non-null. The XML should therefore be:
<Person>
</Person>
Is it possible to prevent Orika from constructing the Name object, knowing its value will be set to null?
Going through the code again a day later with a clear mind, it turns out that Orika doesn't create the wrapper element (as I expected it wouldn't) and that it was a different issue entirely...
I wonder if is possible to convert a xml file that uses element hook, into java object.
Xml:
<?xml version="1.0" encoding="UTF-8" ?>
<personControl>
<personList>
<person>
<name>John</name>
<lastName>Doe</lastName>
<fullName>${lastName} ${name}</fullName>
</person>
...
</personList>
</personControl>
Java classes:
#Data
#XmlRootElement
public class PersonControl {
private PersonList personList;
}
#Data
public class PersonList {
private List<Person> person;
}
#Data
public class Person {
private String name;
private String lastName;
private String fullName;
}
To be simple, I need field concatenation, is that possible?
Thanks.
As I found the answer for my question, I'll post here, maybe someone will consider useful.
I was using the java implementation, that does not have the cyclic reference implementation.
I changed it for the X-Stream implementation.
http://x-stream.github.io/graphs.html
As you can see, X-Stream implements the cyclic reference:
<list>
<cd>
<id>maria rita</id>
</cd>
<cd>
<id>basement_jaxx_singles</id>
</cd>
<cd reference="/list/cd[2]"/>
<list reference="/list"/>
</list>
I'm parsing an XML document which has a fairly complex data structure.
Example:
<Companies>
<LISTID>6353HHJDLS628JNHJ6</LISTID>
<Company>
<ID>123ABC</ID>
<Value>True</Value>
<Order>
<Text>Because </Text>
<ListOfReasons>
<InputName>
<Text>your company did not meet requirements</Text>
</InputName>
<Text>, </Text>
<InputName>
<Text>your company was not listed as qualified</Text>
</InputName>
<Text> etc...</Text>
</ListOfReasons>
</Order>
</Company>
<Company>
<ID>123DEF</ID>
<Value>False</Value>
<Order>
<Text>We can't get any more details on </Text>
<NodeName>
<Text>neither your company or the entity in question</Text>
</NodeName>
<Text> right now.</Text>
</Order>
</Company>
</Companies>
</root>
How should I model my pojo class? To me it seems it should have nested or inner classes. I am not sure how this would look like
I know all about JaxB but I don't really know how to use it and unless there is some easy way to implement it, I prefer writing a pojo, because I understand it.
I'm DOM parsing and I'd like to represent it in Java objects. That is the purpose for writing this model. Can anyone give me an example data model class using the XML I've shown. Any help or assistance would be much appreciated.
There's a great tool that will get you started here.
In your case there are classes like this:
#XmlRootElement
class Companies {
private String LISTID;
private List<Company> companies;
#XmlElement(name = "company")
public void setCompany(List<Company> companies) {
this.companies = companies;
}
#XmlElement
public void setLISTID(String LISTID) {
this.LISTID = LISTID;
}
/** Others standard POJO Methods */
}
#XmlRootElement
public class Company {
private String id;
private String value;
private List<Order> orders;
/** Like in the previous example**
}
With the tool showed above, your work will only to decorate classes with #Xml* annotations.