如何使用XStream与相同数据的变体?

时间:2014-02-11 18:09:05

标签: java xml xstream

在我的场景中,我正在使用XStream,我需要能够以不同的变体存储/解析相同的数据。

考虑以下课程:

用户:

public class User implements Serializable
{

    @XStreamAlias(value = "roles")
    private List<Role> roles = new ArrayList<Role>();

    ...
}

作用:

public class Role implements Serializable
{

    @XStreamAlias(value = "name")
    private String name;

    @XStreamAlias(value = "description")
    private String description;

    ...
}

我需要能够产生以下输出:

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>

但是,我坚持:

<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>

...然而,我想得到:

<users>
    ...
    <user>
        <username>deployer</username>
        <password>password</password>
        <roles>
            <role>
                <name>deploy</name>
                <name>read</name>
                <name>delete</name>
            </role>
        </roles>
    </user>
    ...
</users>

这是可以理解的。 User DTO中的数据结构不同。所以,我想我需要一个Converter。所以,我敲了下面的内容:

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;
    }

}

我的解析器类看起来像这样:

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;
    }
    ...
}

尝试使用以下错误存储XML时失败:

java.lang.ClassCastException: org.foo.User cannot be cast to org.foo.Role
    at org.foo.RoleListConverter.marshal(RoleListConverter.java:35)

显然,当我注册这个转换器时,它试图拦截所有列表并搞砸了。我在这里做错了什么以及如何实现我的目标?

提前致谢!

1 个答案:

答案 0 :(得分:1)

回答可能有点迟了...... 无论如何。

您可以定义

private class UserList extends ArrayList<User> {};
private class RoleList extends ArrayList<Role> {};

xstream.alias("users", UserList.class); 
xstream.alias("roles", RoleList.class);