I've got a nested object hierarchy which looks like this:
Profile: contains a List<Category>
Category contains a List<Script>. It is exposed via a JavaFX SimpleListProperty, so that it can be bound to via JavaFX's data binding.
Script contains nothing but simple values.
I'm just using JAXB to marshall and unmarshall POJOs. There are no databases or XML schemas involved.
Marshalling a Profile value works fine, and generates valid XML. However, unmarshalling the same XML file later, results in each Category containing an empty List<Script>. This appears to be due to the fact that Category stores the List<Script> by using a JavaFX bindable property.
Is there a way to make JAXB properly deserialize into a SimpleListProperty that contains a custom object?
Here's a minimal sample that demonstrates the same issue.
public class Main
{
public static void main(String[] args) throws Exception
{
Script script1 = new Script();
script1.name = "Script 1";
script1.otherData = "Script 1's data";
Script script2 = new Script();
script2.name = "Script 2";
script2.otherData = "Script 2's data";
ArrayList<Script> scriptList = new ArrayList<Script>();
scriptList.add(script1);
scriptList.add(script2);
Category category1 = new Category();
category1.name = "Category 1";
category1.setCategoryScripts(scriptList);
Category category2 = new Category();
category2.name = "Category 2";
category2.setCategoryScripts(scriptList);
Profile profile = new Profile();
profile.name = "Profile 1";
profile.categories.add(category1);
profile.categories.add(category2);
JAXBContext context = JAXBContext.newInstance(Profile.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter xml = new StringWriter();
m.marshal(profile, xml);
System.out.println(xml.toString());
Profile deserializedProfile = (Profile)context
.createUnmarshaller()
.unmarshal(new StringReader(xml.toString()));
System.out.println("Profile: " + deserializedProfile.name);
for(Category cat : deserializedProfile.categories)
{
System.out.println("Category: " + cat.name);
System.out.println("Scripts:");
for(Script s : cat.getCategoryScripts())
{
System.out.printf("\nName: %s, Data: %s", s.name, s.otherData);
}
}
}
}
#XmlRootElement
class Profile
{
#XmlElement
String name;
#XmlElementWrapper
#XmlElement
ArrayList<Category> categories = new ArrayList<Category>();
}
#XmlRootElement
class Category
{
#XmlElement
String name;
ListProperty<Script> categoryScripts = new SimpleListProperty<Script>();
#XmlElementWrapper
#XmlElement
public final List<Script> getCategoryScripts() { return categoryScripts.get(); }
public final void setCategoryScripts(List<Script> value) { categoryScripts.set(FXCollections.observableArrayList(value)); }
public ListProperty<Script> categoryScriptProperty() { return categoryScripts; }
}
#XmlRootElement
class Script
{
#XmlElement
String name;
#XmlElement
String otherData;
}
One of the principles of StackOverflow is Minimal, Complete, and Verifiable questions. See https://stackoverflow.com/help/mcve
When creating such test code, I did this:
public class Test {
public static void main(String[] args) throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(Categories.class);
Categories categoriesIn = new Categories();
categoriesIn.scripts.add(new Script("Hello"));
categoriesIn.scripts.add(new Script("World"));
StringWriter xml = new StringWriter();
jaxbContext.createMarshaller().marshal(categoriesIn, xml);
System.out.println(xml.toString());
Categories categoriesOut = (Categories)jaxbContext.createUnmarshaller().unmarshal(new StringReader(xml.toString()));
System.out.println(categoriesOut.scripts.size() + " scripts:");
for (Script script : categoriesOut.scripts)
System.out.println(" " + script.name);
}
}
#XmlRootElement
class Categories {
#XmlElementWrapper(name = "Scripts")
#XmlElement(name = "Script")
List<Script> scripts = new ArrayList<>();
}
class Script {
#XmlElement(name = "name")
String name;
Script() {}
Script(String name) { this.name = name; }
}
Running it produced:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><categories><Scripts><Script><name>Hello</name></Script><Script><name>World</name></Script></Scripts></categories>
2 scripts:
Hello
World
It seems to work fine, on Java 8 at least.
Try it out. If it doesn't work, then you might need to upgrade Java to a newer version. If it works, you might use it as a baseline to see what might be different in your code.
I believe you're running into a weirdness of JAXB. Notice that you don't have an addCategoryScript method. So how is JAXB going to add Script objects to the list?
It could create a list of it's own, then give it to you with setCategoryScripts, but how would it know what kind of list to create?
It solves that dilemma by calling getCategoryScripts to get the initial (empty) list, and then add elements to it.
But then what happens if you returned a copy of the internal list?
Ah Ha! Call setCategoryScripts when the list is complete.
This means that it'll call setCategoryScripts with the list returned by getCategoryScripts.
I has an implementation that needed some special handling, so what I did was:
public List<MyObj> getMyList() {
return this.myList;
}
public void setMyList(List<MyObj> myList) {
this.myList.clear();
for (MyObj o : myList)
this.myList.add(handle(o));
}
But oops. The call to clear actually cleared the incoming objList parameter, and I ended up with nothing.
My solution was to copy the parameter list before proceeding.
Related
I have a large XML file that consists of many events. I would like to unmarshal them. As it's a large file, I would like to unmarshal them one by one so the whole file is not stored in memory. It works for some events but fails for some due to the fact that it's unable to map to a particular class as it's already in the next event.
Note: I am aware of the XMLEventReader but most of them have mentioned it as not very memory efficient so I am trying to use XMLStreamReader and accomplish this.
Following is the sample XML file that contains the events:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<extension>
<extension>
<c>
<name>CName</name>
<age>CAge</age>
</c>
</extension>
</extension>
<extension>
<b>
<name>BName</name>
<age>BAge</age>
</b>
</extension>
<a>
<name>AName</name>
<age>AAge</age>
</a>
<extension>
<b>
<name>BName</name>
<age>BAge</age>
</b>
</extension>
I have 3 classes corresponding to them which will be used for unmarshalling:
#XmlRootElement(name = "a")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "a", propOrder = {"name","age"})
public class A
{
private String name;
private String age;
//Getter, Setter and other constructors
}
#XmlRootElement(name = "extension")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "extension", propOrder = {"name","age"})
public class B
{
#XmlPath("b/name/text()")
private String name;
#XmlPath("b/age/text()")
private String age;
//Getter, Setter and other constructors
}
#XmlRootElement(name = "extension")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "extension", propOrder = {"name","age"})
public class C
{
#XmlPath("extension/c/name/text()")
private String name;
#XmlPath("extension/c/age/text()")
private String age;
//Getter, Setter and other constructors
}
Following is my Main class which will be used for unmarshalling:
public class Main{
private Unmarshaller unmarshaller = null;
private JAXBContext jaxbContext = null;
public void unmarshaller(InputStream xmlStream) throws IOException, XMLStreamException, JAXBException {
final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
final XMLStreamReader streamReader = xmlInputFactory.createXMLStreamReader(xmlStream);
//Navigate to next and start of the XML Elements
streamReader.next();
//Read Until the end of the file
while (streamReader.hasNext()) {
//Check if the element is "extension" if so its Class B or C
if (streamReader.isStartElement() && streamReader.getLocalName().equalsIgnoreCase("extension")) {
//Check if the next element also has "extension" if so its Class C
//This is IMPORTANT step for mapping b/w Class B & C which is confusing me
streamReader.next();
if (streamReader.isStartElement() && streamReader.getLocalName().equalsIgnoreCase("extension")) {
//If there is 2 extension tag then its Class C
classSpecifier(C.class);
final C cInfo = unmarshaller.unmarshal(streamReader, C.class).getValue();
System.out.println(cInfo);
}else{
//If there is no "extension" tag then its Class B
//THIS IS WHERE ITS FAILING: IF ITS NOT CLASS C THEN IT WOULD COME HERE BUT SINCE I HAVE
//ALREADY MOVED TO NEXT ELEMENT TO CHECK IF ITS "extension" ITS UNABLE TO MAP THE WHOLE CLASS TO CLASS B
classSpecifier(B.class);
final B bInfo = unmarshaller.unmarshal(streamReader, B.class).getValue();
System.out.println(bInfo);
}
}else if(streamReader.isStartElement() && streamReader.getLocalName().equalsIgnoreCase("a")){
//If there is no "extension" then its class A
classSpecifier(A.class);
final A aInfo = unmarshaller.unmarshal(streamReader, A.class).getValue();
System.out.println(aInfo);
}
}
}
//Method to initialize the JAXBContext and Unmarshaller based on the incoming eventType
private void classSpecifier(Class eventTypeClass) throws JAXBException {
this.jaxbContext = JAXBContext.newInstance(eventTypeClass);
unmarshaller = jaxbContext.createUnmarshaller();
}
public static void main(String args[]){
try{
InputStream xmlStream = Main.class.getClassLoader().getResourceAsStream("InputEPCISEvents.xml");
unmarshaller(xmlStream);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
The problem I am facing is the differentiating between class B and C.
I need to check if the incoming localName is extension.
If it's extension then I need to check if the next element localName is also extension.
If so then it's class C if not then class B.
Since in Step-2 I have already moved to streamreader.next() and if the element is not extension then its unable to map it to class B as I have already moved to next() element and it does not have the whole class.
I am looking for some solutions where I can do the following:
If the element in the 2nd verification is not extension then go back to the previous element then assign the whole class to class B.
Assign the streamReader to tempreader when making a check so that you will be advancing in tempreader. But this also failing.
Is there a way to go back to the previous element in a stream or else how can I tackle this issue? I hope I was able to provide a complete explanation.
"Going back" in a stream implies some kind of memory, so there is no point in sticking to the most memory-efficient tool.
XMLEventReader can handle this with ease:
public class Main {
public static void main(String args[]) throws Exception {
Unmarshaller aUnmarshaller = JAXBContext.newInstance(A.class).createUnmarshaller();
Unmarshaller bUnmarshaller = JAXBContext.newInstance(B.class).createUnmarshaller();
Unmarshaller cUnmarshaller = JAXBContext.newInstance(C.class).createUnmarshaller();
try (InputStream input = Main.class.getResourceAsStream("InputEPCISEvents.xml")) {
XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(input);
while (reader.hasNext()) {
XMLEvent event = reader.peek();
if (event.isStartElement()) {
switch (event.asStartElement().getName().getLocalPart()) {
case "a" -> System.out.println(aUnmarshaller.unmarshal(reader));
case "b" -> System.out.println(bUnmarshaller.unmarshal(reader));
case "c" -> System.out.println(cUnmarshaller.unmarshal(reader));
}
}
reader.next();
}
}
}
#XmlAccessorType(XmlAccessType.FIELD)
static class ABC {
String name;
String age;
public String toString() {
return getClass().getSimpleName() + "{name='" + name + "', age='" + age + "}";
}
}
#XmlRootElement static class A extends ABC {}
#XmlRootElement static class B extends ABC {}
#XmlRootElement static class C extends ABC {}
}
Output:
C{name='CName', age='CAge}
B{name='BName', age='BAge}
A{name='AName', age='AAge}
B{name='BName', age='BAge}
By the way, your XML needs to be wrapped in a parent element as it contains more than one root element.
I'm having trouble parsing xml with simple xml framework. I want to store category id and list of tournaments inside a Map/hashMap how can I do that? I followed the tutorial on simple xml but it doesnt work for me.
I stored it in a list like this:
#ElementList(entry = "Category", inline = true, required = false)
List<Category> category;
but now I wanna store it in a map.
Here is xml:
Tutorial that I followed:
Any help would be appreciated, tnx.
It's not possible by Annoations like #ElementList or #ElementMap, but using a Converter is still an (good) option.
Going that way means: Implementing a Converter for Tournaments which merges the Category-Id / Tournament List pair.
And here is how this is done:
First the necessary (data-) classes.
Tournament:
#Root(name = "Tournament")
public class Tournament
{
#Text
private String data;
public Tournament(String data)
{
this.data = data;
}
private Tournament() { /* Required */ }
// ...
}
Note: I gave the Tournament some data string, since the real data isn't shown. However, actually it doesn't matter what data it contains.
Category:
#Root(name = "Category")
public class Category
{
private String id;
// ...
}
Tournaments
#Root(name = "Tournaments")
#Convert(TournamentsConverter.class) // Specify the Converter used for this class
public class Tournaments
{
private Map<String, List<Tournament>> tournaments;
public Tournaments()
{
tournaments = new HashMap<>();
}
protected void put(String id, List<Tournament> tournaments)
{
this.tournaments.put(id, tournaments);
}
// ...
}
The #Convert will use the following Converter for serialization / deserialization of Tournaments. I haven't implemented the serialization part in this example (it's not difficult though).
Important: #Convert requires an AnnotationStrategy (see example below)!
Tournament Converter
public class TournamentsConverter implements Converter<Tournaments>
{
private final Serializer serializer = new Persister();
#Override
public Tournaments read(InputNode node) throws Exception
{
Tournaments tournaments = new Tournaments();
InputNode childNode = node.getNext();
// Iterate over all childs of 'Tournaments'
while( childNode != null )
{
if( childNode.getName().equals("Category") == true )
{
final String categoryId = childNode.getAttribute("category_id").getValue();
List<Tournament> tournamentList = new ArrayList<>();
InputNode child = childNode.getNext();
// Iterate over all childs of 'Category'
while( child != null )
{
// Use a Serializer to read the nodes data
Tournament tournament = serializer.read(Tournament.class, child);
tournamentList.add(tournament);
child = childNode.getNext();
}
// Insert the Id / Tournament's pair
tournaments.put(categoryId, tournamentList);
}
childNode = node.getNext();
}
return tournaments;
}
#Override
public void write(OutputNode node, Tournaments value) throws Exception
{
// Implement as needed
throw new UnsupportedOperationException("Not supported yet.");
}
}
All the "magic" is done by the Converter:
Iterate over all of Tournaments child nodes
If it's a Category
Get the id
Iterate over all childs and add the Tournament's to a list
Add the id / List of Tournament to the result Tournaments
As shown above, it's possible to use a Serializer for (de-)serialization of nodes. No need to implement that by hand.
Example
Finally, here's an example. Please note the AnnotationStrategy.
Serializer ser = new Persister(new AnnotationStrategy());
final String xml = "<Tournaments>\n"
+ " <Category category_id=\"289\">\n"
+ " <Tournament>aaaa</Tournament>\n"
+ " </Category>\n"
+ " <Category category_id=\"32\">\n"
+ " <Tournament>bbbd</Tournament>\n"
+ " <Tournament>cccc</Tournament>\n"
+ " </Category>\n"
+ "</Tournaments>";
Tournaments t = ser.read(Tournaments.class, xml);
System.out.println(t);
Output:
Using generated toString() added to each class.
Tournaments{tournaments={289=[Tournament{data=aaaa}], 32=[Tournament{data=bbbd}, Tournament{data=cccc}]}}
The problem is that you are trying to create a structure like Map<String, <List<Tournament>> and that doesn't seem to be possible with the ElementMap annotation. You need sort of an ElementMapList annotation. Maybe you can file an issue and Mr. Gallagher can add that.
I have two classes, Package and ModelRefObj. Package contains two sets of ModelRefObj.
I'm using Simple framework to parse their instances from XML, so I've created some JUnit tests. I'm able to parse ModelRefObj XML, but I'm getting the following exception when trying to parse a Package:
org.simpleframework.xml.core.ValueRequiredException: Empty value for #org.simpleframework.xml.Text(empty=, data=false, required=true) on field 'value' private java.lang.String cz.semanta.coc.domain.cognos.ModelRefObj.value in class cz.semanta.coc.domain.cognos.ModelRefObj at line 1
at org.simpleframework.xml.core.Composite.readInstance(Composite.java:580)
at org.simpleframework.xml.core.Composite.readText(Composite.java:467)
at org.simpleframework.xml.core.Composite.access$200(Composite.java:59)
at org.simpleframework.xml.core.Composite$Builder.read(Composite.java:1381)
...
Here is the XML I'm trying to parse:
<package>
<name>GO Sales (nalysis)</name>
<visible>
<refObj>[go_sales]</refObj>
<refObj>[Filters and calculations].[Returns]</refObj>
</visible>
<hidden>
<refObj>[gosales].[BRANCH].[BRANCH_CODE]</refObj>
<refObj>[gosales].[BRANCH].[ADDRESS1]</refObj>
<refObj>[gosales].[BRANCH].[CITY]</refObj>
</hidden>
</package>
Here are my annotated classes:
#Root(name = "package")
public class Package {
#Element
private String name;
#ElementList(name = "visible", entry = "refObj", type = ModelRefObj.class)
private Set<ModelRefObj> visibleRefObjs;
#ElementList(name = "hidden", entry = "refObj", type = ModelRefObj.class)
private Set<ModelRefObj> hiddenRefObjs;
Package() { }
...
}
#Root(name = "refObj")
public class ModelRefObj {
#Text
private String value;
ModelRefObj() { }
public ModelRefObj(String value) {
this.value = value;
}
...
}
I have implemented the classes you have and used the example xml you provided.
I created a main function to test
public static void main(String args[]) throws Exception {
Serializer serializer = new Persister(new Format("<?xml version=\"1.0\" encoding= \"UTF-8\" ?>"));
File source = new File("sample.xml");
Package p = serializer.read(Package.class, source);
System.out.println(p.name);
}
The output is
GO Sales (nalysis)
Inspecting the object p in debug mode shows it has the two Sets with two and three elements.
Your code works fine for me.
I am mapping an object to JSON and have a problem with one variable called Parameters of type List <SimilarityParameter>.
SimilarityParameter looks like this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class SimilarityParameter {
private String name;
private String type;
public SimilarityParameter() {
}
public SimilarityParameter(String name, String type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
When this List is large everything is OK. The JSON looks like this
{
"parameters":[
{
"name":"threshold",
"type":"Double"
},
{
"name":"numberOfResults",
"type":"Integer"
}
]
}
This is OK because after JSON encoding on the client side I have an array of Parameters.
The problem is when List is of size 1. Mapper transfers it logically to:
{
"parameters":{
"name":"numberOfResults",
"type":"Integer"
}
}
When the client decodes this JSON gets gets an array containing name and type. It causes inconsistencies on the client side.
I would like to map List of size 1 to this:
{
"parameters":[
{
"name":"threshold",
"type":"Double"
}
]
}
So after encoding array containing one parameter.
This is how the response looks:
#XmlRootElement(name = "availableSimilarities")
#XmlAccessorType(XmlAccessType.FIELD)
public class SimilarityInfoResult {
private String similarityName;
private List <SimilarityParameter> parameters;
public SimilarityInfoResult() {
}
public SimilarityInfoResult(String similarityName, List<SimilarityParameter> parameters) {
this.similarityName = similarityName;
this.parameters = parameters;
}
public String getName() {
return similarityName;
}
public void setName(String similarityName) {
this.similarityName = similarityName;
}
public List<SimilarityParameter> getParameters() {
return parameters;
}
public void setParameters(List<SimilarityParameter> parameters) {
this.parameters = parameters;
}
}
Is it possible to achieve this?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The problem is when List is of size 1. Mapper transfers it logically
to:
The JAXB specification itself does not cover JSON-binding so sometimes implementations are used with libraries like Jettison which converts XML events to/from JSON and problems occur such as collections of size 1 being represented incorrectly. This is because Jettison (and similar) libraries can only detect collections when they see an element appear more than once.
http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html
Is it possible to achieve this?
The EclipseLink MOXy implementation of JAXB offers native JSON binding meaning that items like collections of size 1 will be properly converted to JSON.
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properites in the same package as your domain model with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(2);
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {SimilarityInfoResult.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum15316288/input.json");
SimilarityInfoResult result = unmarshaller.unmarshal(json, SimilarityInfoResult.class).getValue();
Marshaller marshaller= jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(result, System.out);
}
}
input.json/Output
{
"parameters" : [ {
"name" : "threshold",
"type" : "Double"
} ]
}
For More Information
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
I am working with xstream to read some xml in the following format --
<Objects>
<Object Type="System.Management.Automation.Internal.Host.InternalHost">
<Property Name="Name" Type="System.String">ConsoleHost</Property>
<Property Name="Version" Type="System.Version">2.0</Property>
<Property Name="InstanceId" Type="System.Guid">7e2156</Property>
</Object>
</Objects>
Basically under Objects tag there can be n number of Object Type and each Object Type can have n number of Property tags. So I have modelled by Java classes and the code to read it as follows --
class ParentResponseObject {
List <ResponseObject>responseObjects = new ArrayList<ResponseObject>();
}
#XStreamAlias("Object")
#XStreamConverter(value = ToAttributedValueConverter.class, strings = { "Value" })
class ResponseObject {
String Type;
String Value;
List <Properties> properties = new ArrayList<Properties>();
}
#XStreamAlias("Property")
#XStreamConverter(value = ToAttributedValueConverter.class, strings = { "Value" })
class Properties {
String Name;
String Type;
String Value;
}
public class MyAgainTest {
public static void main (String[] args) throws Exception {
String k1 = //collect the xml as string
XStream s = new XStream(new DomDriver());
s.alias("Objects", ParentResponseObject.class);
s.alias("Object", ResponseObject.class);
s.alias("Property", Properties.class);
s.useAttributeFor(ResponseObject.class, "Type");
s.addImplicitCollection(ParentResponseObject.class, "responseObjects");
s.addImplicitCollection(ResponseObject.class, "properties");
s.useAttributeFor(Properties.class, "Name");
s.useAttributeFor(Properties.class, "Type");
s.processAnnotations(ParentResponseObject.class);
ParentResponseObject gh =(ParentResponseObject)s.fromXML(k1);
System.out.println(gh.toString());
}
}
Using this code, I am able to populate the responseObjects List in the ParentResponseObject class. However, the properties list in the ResponseObject is always null, even though I am using the same technique in both the cases. Can anyone please help on getting this solved. Help on this is highly appreciated.
Your XML format does not match your Java object model. According to the XML, <Property> is a child of <Objects>, but according to your code, the Properties list is part of the ResponseObject. You need to fix this mismatch.
Also, it seems that you are using a mix of annotations and code. Either use only annotations (recommended) or do it all in code. Otherwise, your code becomes confusing and unreadable.
Update:
I see you have fixed your XML. The problem is that you have a Value field in your ResponseObject, but there is no value in the xml element, so remove it.
The following code should work:
#XStreamAlias("Objects")
public class ParentResponseObject {
#XStreamImplicit
List<ResponseObject> responseObjects = new ArrayList<ResponseObject>();
}
#XStreamAlias("Object")
public class ResponseObject {
#XStreamAsAttribute
String Type;
#XStreamImplicit
List<Properties> properties = new ArrayList<Properties>();
}
#XStreamAlias("Property")
#XStreamConverter(value = ToAttributedValueConverter.class, strings = { "Value" })
public class Properties {
String Name;
String Type;
String Value;
}
Main method:
XStream s = new XStream(new DomDriver());
s.processAnnotations(ParentResponseObject.class);
ParentResponseObject gh = (ParentResponseObject) s.fromXML(xml);
for (ResponseObject o : gh.responseObjects) {
System.out.println(o.Type);
for (Properties p : o.properties) {
System.out.println(p.Name + ":" + p.Type + ":" + p.Value);
}
}