JAXB - How to specify xml attributes in binding Java Class - java

I know to create a JAXB Class to marshal/unmarshall an xml like this
<outertag>
<innerelement>
<innerElementDetail1>some value</inner-element-detail1>
</innerelement>
</outertag>
here is the class I created
#XmlRootElement(name ="outertag")
#XmlAccessorType(XmlAccessType.FIELD)
public class OuterTag {
#XmlElement(name = "innerelement")
private List<InnerElement> innerElemements
public static InnerElement{
private String innerElementDetail;
// getters and setters
}
}
If I have to have an attribute on one of the inner elements like this
<outertag>
<innerelement attribute1="attribute1value">
<innerElementDetail1>some value</inner-element-detail1>
</innerelement>
</outertag>
how do I do that ?

This should do it :
#XmlRootElement(name ="outertag")
#XmlAccessorType(XmlAccessType.FIELD)
public class OuterTag {
#XmlElement(name = "innerelement")
private List<InnerElement> innerElemements
public static InnerElement{
#XmlAttribute(name = "attribute1")
protected String attribute1;
private String innerElementDetail;
// getters and setters
}
}

Related

MapStruct mapping on objects of type List

I am trying to use MapStruct for a structure similar to the following:
#Data
public class ClassAEntity {
private int id;
private String name;
private String numT;
private List<ClassBEntity) bs;
}
#Data
public class ClassBEntity {
private int id;
private String name;
private String numT;
private List<Other> oc;
}
#Data
public class ClassA {
private int id;
private String name;
private List<ClassB) bs;
}
#Data
public class ClassB {
private int id;
private String name;
private List<Other> oc;
}
In the interface I have added the following mapping:
ClassAEntity map(ClassA classA, String numT)
I get a warning because it can't map numT to classBEntity.numT and I can't add it with #Mapping in the following way:
#Mapping(source = "numT", target = "bs[].numT")
On the other hand I need to ignore the parameter oc of classBEntity because "Other" object contains classAEntity and forms a cyclic object. (because I use oneToMany JPA). I have tried the following:
#Mapping(target = "bs[].oc", ignore = true)
Thank you for your help
MapStruct does not support defining nested mappings for collections. You will have to define more explicit methods.
For example to map numT into bs[].numT and ignore bs[].oc you'll need to do something like:
#Mapper
public MyMapper {
default ClassAEntity map(ClassA classA, String numT) {
return map(classA, numT, numT);
}
ClassAEntity map(ClassA classA, String numT, #Context String numT);
#AfterMapping
default void setNumTOnClassBEntity(#MappingTarget ClassBEntity classB, #Context String numT) {
classB.setNumT(numT);
}
#Mapping(target = "oc", ignore = "true")
ClassBEntity map(ClassB classB);
}

How to name properties of compex #RequestParams in #RestController?

Is it possible to rename the parameters used inside a GET webservice in spring? Like search.limitResults in the following example:
localhost:8080/firstname=test&search.limitResults=10
You get the idea. Can this be achieved?
#RestController
public class MyServlet {
#RequestMapping(value = "/", method = RequestMethod.GET)
private String test(RestParams p) {
}
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class RestParams {
private String firstname;
private String lastname;
//is that possible to nest?
#XmlElement(name = "search")
private MyComplexSearch search;
public MyComplexSearch getSearch() {return search;}
public void setSearch(MyComplexSearch) {this.search = search;}
#XmlRootElement(name = "search")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyComplexSearch {
private int limitResults;
//some more
}
}
The request will not work with the code above. Instead one would have to use myComplexSearch as the objects name.
localhost:8080/firstname=test&myComplexSearch.limitResults=10
How can I redefine the name of the input property, without having to rename the java class itself?
Nested classes have to be static.
public static class MyComplexSearch

JAXB giving an exception when trying to Marshall with given order

i have a code similar to this
#XmlRootElement(name = "root")
#XmlType(propOrder={"param1", "param2""})
public class Demo{
public Demo() {
}
private int param1;
private String param2;
private String param3;
public int getparam1() {
return param1;
}
#XmlElement
public void setparam1(int param1) {
this.param1= param1;
}
//other setters and getters here except for param3
}
but it gives me
n4 counts of IllegalAnnotationExceptions
exception when i try to run the program (i have 6 parameters in total in original code and only 4 is use for Marshall )
What would be the reason for this?
There is an error in the #XmlType anntation:
#XmlType(propOrder={"param1", "param2","param3"})
If this not fix the problem, try to check the name of the properties in the propOrder OR directly use field accessor type:
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder={"param1", "param2", "param3"})
public class Demo{
public Demo() {
}
private int param1;
private String param2;
private String param3;
//getter & setters without annotations
}

issues while Unmarshalling using JaxB

I have the following XML file to unmarshall
<root>
<emp>Google</emp>
<emp>Yahoo</emp>
<xyz>random</xyz>
</root>
And i have used annotations in the following way,
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlElement(name = "emp")
private String emp1;
#XmlElement(name = "emp")
private String emp2;
#XmlElement(name = "xyz")
private String xyz;
// added getters and setters for these fields
}
My problem is while i'm trying to get
obj.getEmp1(); // result is Yahoo instead of Google
obj.getEmp2(); // result is null.
Kindly clarify me, what am i doing wrong?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The standard JAXB (JSR-222) annotations do not support mapping 2 different properties to the same XML element.
You could use EclipseLink JAXB (MOXy)'s #XmlPath extension for this use case.
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlPath("emp[1]/text()")
private String emp1;
#XmlPath("emp[2]/text()")
private String emp2;
#XmlElement(name = "xyz")
private String xyz;
// added getters and setters for these fields
}
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If for whatever reason you cannot use MOXy, another solution would be to map the emp element as a list
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlElement(name = "emp")
private List<String> emp;
#XmlElement(name = "xyz")
private String xyz;
// added getters and setters for these fields
}
And then use the following code to get the values:
obj.getEmp().get(0);
obj.getEmp().get(1);
But Blaise's solution is more elegant
You could have a String[] field and have your current accessor methods access the String[].
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
private String[] emp = new String[2];
private String xyz;
public String getEmp1() {
return emp[0];
}
public void setEmp1(String emp1) {
this.emp[0] = emp1;
}
public String getEmp2() {
return emp[1];
}
public void setEmp2(String emp2) {
this.emp[1] = emp2;
}
public String getXyz() {
return xyz;
}
public void setXyz(String xyz) {
this.xyz = xyz;
}
}
This might work.
<root>
<emp1>Google</emp1>
<emp2>Yahoo</emp2>
<xyz>random</xyz>
</root>
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlElement(name = "emp1")
private String emp1;
#XmlElement(name = "emp2")
private String emp2;
#XmlElement(name = "xyz")
private String xyz;
}

Two #XmlJavaTypeAdapters for one #XmlAttribute in JAXB?

I have a class like this:
#XmlRootElement(name = "PricingGroup")
public class PricingGroup {
...
#XmlAttribute(name = "partyName")
#XmlJavaTypeAdapter(CustomerGroupRelationships.Adapter.class)
private List<BilltoCustomer> billtoCustomers = new ArrayList<BilltoCustomer>();
#XmlAttribute(name = "partyName")
#XmlJavaTypeAdapter(PartyNames.Adapter.class)
private PartyName partyName;
...
}
It seems JAXB can't map two #XmlJavaTypeAdapters for one attribute (here partyName). If I comment out either the annotations on billtoCustomers or the annotations on partyName, the other member variable is read from XML without problems.
How can I get both values at the same time?
You could map one of the properties (partyName) and then use an afterUnmarshal event to derive the other property (billToCustomers):
#XmlRootElement(name = "PricingGroup")
public class PricingGroup {
...
#XmlTransient
private List<BilltoCustomer> billtoCustomers = new ArrayList<BilltoCustomer>();
#XmlAttribute(name = "partyName")
#XmlJavaTypeAdapter(PartyNames.Adapter.class)
private PartyName partyName;
void afterUnmarshal(Unmarshaller u, Object parent) {
// Derive billToCustomers from partyName
}
...
}

Categories

Resources