Reputation: 32607
In my scenario I'm using XStream and I need to be able to store/parse the same data in different variants.
Consider the following classes:
User:
public class User implements Serializable
{
@XStreamAlias(value = "roles")
private List<Role> roles = new ArrayList<Role>();
...
}
Role:
public class Role implements Serializable
{
@XStreamAlias(value = "name")
private String name;
@XStreamAlias(value = "description")
private String description;
...
}
I need to be able to produce the following outputs:
users.xml
<users>
<user>
<username>admin</username>
<password>password</password>
<roles>
<role>administrator</role>
</roles>
</user>
<user>
<username>deployer</username>
<password>password</password>
<roles>
<role>deploy</role>
</roles>
</user>
</users>
roles.xml:
<roles>
<role>
<name>admin<name>
<description>Administrative role</description?
</role>
<role>
<name>deploy<name>
<description>Deployment role</description?
</role>
...
</roles>
However, I am stuck with:
<users>
<user>
<username>admin</username>
<password>password</password>
<roles>
<role>
<name>admin</name>
</role>
</roles>
</user>
<user>
<username>deployer</username>
<password>password</password>
<roles>
<role>
<name>deploy</name>
</role>
<role>
<name>read</name>
</role>
<role>
<name>delete</name>
</role>
</roles>
</user>
</users>
... Whereas, I would like to be getting:
<users>
...
<user>
<username>deployer</username>
<password>password</password>
<roles>
<role>
<name>deploy</name>
<name>read</name>
<name>delete</name>
</role>
</roles>
</user>
...
</users>
This is understandable. The data in the User
DTO is structured differently. So, I figured I needed a Converter
. So, I knocked up the following:
public class RoleListConverter
implements Converter
{
public boolean canConvert(Class clazz)
{
return AbstractList.class.isAssignableFrom(clazz);
}
public void marshal(Object value,
HierarchicalStreamWriter writer,
MarshallingContext context)
{
if (value instanceof List)
{
//noinspection unchecked
List<Role> roles = (List<Role>) value;
for (Role role : roles)
{
writer.startNode("role");
writer.setValue(role.getName());
writer.endNode();
}
}
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context)
{
List<Role> roles = new ArrayList<Role>();
while (reader.hasMoreChildren())
{
reader.moveDown();
Role role = new Role();
final String nodeName = reader.getNodeName();
if (nodeName.equals("role"))
{
role.setName(reader.getValue().trim());
roles.add(role);
}
reader.moveUp();
}
return roles;
}
}
My parser class looks like this:
public class UserParser
extends GenericParser<User>
{
...
public XStream getXStreamInstance()
{
XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
xstream.alias("user", User.class);
xstream.alias("users", List.class);
xstream.alias("role", Role.class);
xstream.alias("credentials", Credentials.class);
xstream.registerConverter(new RoleListConverter());
return xstream;
}
...
}
This fails when trying to store the XML with the following error:
java.lang.ClassCastException: org.foo.User cannot be cast to org.foo.Role
at org.foo.RoleListConverter.marshal(RoleListConverter.java:35)
Apparently, when I register this converter, it tries to intercept all lists and screws up. What am I doing wrong here and how could achieve my goal?
Thanks in advance!
Upvotes: 0
Views: 126
Reputation: 584
Probably a bit late as answer... Any way.
You could define
private class UserList extends ArrayList<User> {};
private class RoleList extends ArrayList<Role> {};
xstream.alias("users", UserList.class);
xstream.alias("roles", RoleList.class);
Upvotes: 1