Using JAXB, marshal nested element in JAVA - java

I would like to get a xml result as below which using JAXB to get java object.
<Mall>
<ProductInfo>
<Product>
<name>chair</name>
<price>150</price>
</Product>
</ProductInfo>
</Mall>
To get this result, I made 3 java classes which are
Define XmlRootElement, XmlElement
component of product (getter/setter)
Main class which insert the value of component
In this way, I could make only 3 depths using XmlRootElement, XmlElement, Component of product.
Hence I need one more depth..
I tried to use a XmlElementWrapper to give one more depth, but there was an error regarding it is not a collecting attribute...
Please help me to solve this out...

Below is class structure that should work
#XmlRootElement (name = "mall")
public class Mall {
Mall(){ }
#XmlElement(name="ProductInfo")
private ProductInfo info; // must create getter and setter
}
}
public class ProductInfo { // you should be missing this
ProductInfo(){
}
#XmlElement(name="Product")
private List<Product> info; // must create getter and setter
}
}
public class Product {
Product(){
}
#XmlElement(name="name")
private ProductInfo info; // must create getter and setter
#XmlElement(name="price")
private ProductInfo info; // must create getter and setter
}
}

Related

Unmarshall MixedContent with Jaxb returns Objects with null variables

I want to unmarshall a XML-File with mixed Content. I found a thread on stackoverflow which seemed appropriate (JAXB- #XmlMixed usage for reading #XmlValue and #XmlElement) where the user bdoughan defined 3 Use-Cases to deal with mixed content.
The third use case would keep the text between the tags in a single String variable and save the elements in a List. Which is what I wanted. Unfortunately I couldn't get it to work and the thread is quite old and maybe outdated.
I've tried the Usecase #3 with a List of Objects and a List of my Reference Class. Also I tried #XmlElement and #XmlValue Annotations.
I'm using the javax.xml.bind jaxb-api in version 2.3.1 and the org.glassfish.jaxb jaxb-runtime in version 2.3.1 in a Maven Projec with Java SE Version 12.0.2.
A Sample XML I tested with
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Date>
2018.06.27
<reference id="AnyId1">
</reference>
</Date>
My Class Representation
#XmlRootElement(name="Date")
public class TestPojo {
#XmlMixed
public String getTextContent() {
return textContent;
}
public void setTextContent(String textContent) {
this.textContent = textContent;
}
#XmlElementRef(name="reference", type = Reference.class)
public List<Object> getRef() {
return ref;
}
public void setRef(List<Object> ref) {
this.ref = ref;
}
String textContent;
List<Object> ref = new ArrayList<Object>();
}
I'd expect that the xml is unmarshalled into a POJO object and the right values are assigned. The Objects variables (textContent & ref) are null after unmarshalling.
You could try this:
Using a Reference class as below,
#XmlAccessorType(XmlAccessType.FIELD)
public class Reference {
#XmlAttribute
private String id;
}
And your Root class,
#XmlRootElement(name="Date")
public class TestPojo {
#XmlMixed
#XmlAnyElement
private List<Object> textContent;
#XmlElement
private Reference reference;
}
This will unmarshall giving you the reference element and everything else in a List.
For the example you have it will be 2 entries. The date value/text along with tab character (\t) and new line characters (\n), and another entry with new line character.
So you can use this list to process the contents and use what you want.
If there is a cleaner solution, I am interested. Cheers
Update to answer to comment:
In order to be more clear with the fix. What I did was using #XmlElement instead of #XmlElementRef for a single Reference instead of list (cos that's what I saw in the xml).
Also I added the #XmlAnyElement annotation for the mixed content made it a list. This is what fixed it. So sticking with your class, it would look like below:
#XmlRootElement(name="Date")
public class TestPojo {
List<Object> textContent;
Reference ref;
#XmlMixed
#XmlAnyElement
public List<Object> getTextContent() {
return textContent;
}
public void setTextContent(List<Object> textContent) {
this.textContent = textContent;
}
#XmlElement(name="reference")
public Reference getRef() {
return ref;
}
public void setRef(Reference ref) {
this.ref = ref;
}
}
The #XmlAccessorType saved me time from writing getters and setters. For an explanation of what this annotation does with an example (and in relation to #XmlElement, check this:
What is the difference between using #XmlElement before field and before getter declaration?

#XmlVariableNode ignores the second property if used twice

I have to create POJOs so that I can generate XML using JAXB for the below XML (Just a sample because child elements may go beyond 40).
Here, important thing to note is that I cannot declare these elements as properties in POJO because I won't be knowing the elements name.
<User>
<FirstName>Mahendra</FirstName>
<MiddleName>Singh</MiddleName>
<LastName>Dhoni</LastName>
<Organization>
<Name>Electronics</Name>
<id>elc001</id>
</Organization>
<Manager>
<Name>Sourabh</Name>
<id>emp_001</id>
</Manager>
</User>
I have created POJO for above XML as:
Fields1.java : For elements having value only.
public class Fields1
{
#XmlTransient
public String fieldName1;
#XmlValue
public String value;
// getter,setter
}
Fields2.java : For elements having child elements.
public class Fields2
{
#XmlTransient
public String fieldName2;
#XmlElement(name="NAME")
public String name;
#XmlElement(name="ID")
public String id;
// getter,setter
}
User.java : Root element class
public class User
{
#XmlVariableNode("fieldName1")
public List<Fields1> fields1;
#XmlVariableNode("fieldName2")
public List<Fields2> fields2;
// getter, setter
}
Here, #XmlVariableNode is helping me to generate elements name dynamically.
1. But, it only works fine if there is only single property
2. and if, there are two properties then it just works for the first one and ignores the next.
AFAIK, multiple #XmlVariableNodes in the same class are not possible. EclipseLink's documentation states:
Since this [#XmlVariableNode] makes use of the any logic during unmarshal and MOXy only
handles one Any mapping on a class if a class makes use of the
XmlVariableNode annotation then that class can not have XmlAnyElement
annotations or any other variables that would cause AnyObject or
AnyCollection mappings to be created.
(Source: EclipseLink/DesignDocs/406697)
You might be able to solve your problem by using nested #XmlVariableNodes:
public class TopLevelField {
#XmlTransient
public String fieldName;
#XmlVariableNode("fieldName")
public List<NestedField> fields;
// ...
}
public class NestedField {
#XmlTransient
public String fieldName;
#XmlValue
public String value;
// ...
}
#XmlRootElement
public class User {
#XmlVariableNode("fieldName")
public List<TopLevelField> fields;
}

Export specific fields on XML extraction in Java

I am using #XmlRootElement annotation to get XML data from the database.
Right now, if I put #XmlTransient to getters, the fields are ignored.
For example:
public class Student {
private Integer studentId;
private String studentName;
#XmlTransient // Do not get student id
public Integer getStudentId() {
return this.studentId;
}
public String getStudentName() {
return this.studentName;
}
...// Setter goes here
Then, student ids are not appear in the XML file.
However, can I do this in the opposite way? I want to specify fields that I want to have in the XML file - there are too many fields in the Student class.
My server(Spring Framework 3.2.3) also uses the Jackson library, so I wonder I could use it if that is possible.
You could annotate your class with:
#XmlAccessorType(XmlAccessType.NONE)
Now you have to explicitly map properties in order to be serialized. See the Javadoc: http://docs.oracle.com/javaee/7/api/javax/xml/bind/annotation/XmlAccessType.html

JAXB binding nested elements

I am using JAXB-impl. I need to be able to map nested elements to class fields as simple types. For example:
<mapping>
<search>
<channel>main-channel</channel>
<url>my-channel-url</url>
</search>
<items>
<item>first</item>
<item>second</item>
<item>third</item>
</items>
</mapping>
Assuming I need to bind "url" tag to a field in the class, this will not work (of course):
class Mapping{
#XmlElement
private String url;
}
#XmlElementWrapper, is for collections only. I have seen some post about using eclipse MOXy, and utilize #XmlPath, but this is not an option. It has to be JAXB-impl.
for reference:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/XPath#Marshal_to_XML_-_MOXy_Customization_.231_-_Grouping_Element
Is there a way to get this mapping without having to create these extra nested classes ?
With additional class Search, but this class is private nested class, and not used outside of Mapping class.
public API of class Mapping returns url as expected
#XmlAccessorType(XmlAccessType.FIELD)
class Mapping
{
#XmlAccessorType(XmlAccessType.FIELD)
private static class Search
{
private String channel;
private String url;
}
private Search search;
public String getUrl()
{
return search == null ? null : search.url;
}
}

Convert java.util.Set attributes with Commons BeanUtils

I have a problem converting the following request URL:
entity.name=Test&entity.window[0].size=1&entity.windows[1].size=2
to the following JavaBean:
public class House {
private String nome;
private Set<Window> windows;
// ... getters and setters ...
}
public class Window {
private int size;
// ... getters and setters ...
}
I get this error when I use BeanUtils.populate:
Property 'windows' is not indexed on bean class 'class House'
I think this problem occurs because Sets don’t have a known order to follow. So I can’t map values with indices like [0]...[1]...[2]. For my purpose, for converting request params to java.util.Set attributes, can I continue using BeanUtils with some adjustments or do I have to pick another library (which one)?

Categories

Resources