You have two problems : Binding the <Variable> Element to your Map and Binding the <Parameter> elements to different typed Objects.
I'll treat the problems in this order.
For the Map, you'll have to use a XmlAdapter with @XmlJavaTypeAdapter.
Code a class representing your <Variable> element and map it :
public class Variable{
@XmlAttribute
public String Name;
@XmlElement
public String Value;
//Getters and setters
}
Then code the XmlAdapter :
public class YourAdapter extends XmlAdapter<List<Variable>,Map<String,String>>{
public Map<String,String> unmarshall(List<Variable> arg0){
//Logic to convert a List<Variable> into a Map<String,String> and return it
}
public List<Variable> marshall(Map<String,String> arg0){
//Logic to convert a Map<String,String> into a List<Variable> and return it
}
}
Then map your Contract class :
@XmlRootElement
@XmlSeeAlso({Variable.class})
public class Contract{
@XmlElement(name="Variable")
@XmlJavaTypeAdapter(YourAdapter.class)
private Map<String,String> map;
//Getters and setters
}
With this, your map should work.
You have two solutions with your second problem : Either Using JAXB Reference implementation or Using JAXB MOXy implementation.
With JAXB reference implementation
JAXB Reference implementation cannot use Xpath to do its binding. So here is a workaround.
Code a second class and adapter for your <Parameter> element, which is basically going to be the same thing except for the names, and use this mapping for contract :
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({Variable.class,Parameter.class})
public class Contract{
@XmlElement(name="Variable")
@XmlJavaTypeAdapter(YourAdapter.class)
private Map<String,String> map;
@XmlElement(name="Parameter")
@XmlJavaTypeAdapter(YourAdapterForParameter.class)
private Map<String,String> parameterMap;
public Long getId(){
return Long.valueOf(parameterMap.get("id"));
}
public void setId(Long id){
parameterMap.put("id",id.toString());
}
//Same thing for other getters/setters
}
With MOXy implementation
With MOXy implementation, you can use @XmlPath and XPath to make it a bit cleaner :
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({Variable.class})
public class Contract{
@XmlPath("./Variable[@Name='id']/Value")
private Long id;
@XmlPath("./Variable[@Name='templateName']/Value")
private String templateName;
@XmlPath("./Variable[@Name='isComplete']/Value")
private boolean isComplete;
@XmlElement(name="Variable")
@XmlJavaTypeAdapter(YourAdapter.class)
private Map<String,String> map;
//Getters and setters
}
For further information/help, please refer to JAXB/MOXy Documentation.