Dmitry Korchemkin Dmitry Korchemkin - 3 months ago 18
Java Question

XStream delete unwanted fields of a collection

I have an object "Role" which can contain several "Privileges", which are objects too. Now, when i try to serialize Role with Xstream my xml looks like this:

<role>
<roleName>Administrator</roleName>
<privileges class="org.hibernate.collection.PersistentSet">
<set>
<privilege>
<privilegeId>1001</privilegeId>
<privilegeName>Admin Privilege</privilegeName>
<privilegeKey>Admin</privilegeKey>
</privilege>
</set>
<initialized>true</initialized>
<owner class="role" reference="../.."/>
<cachedSize>-1</cachedSize>
<rolemodel.valueobject.Role.privileges</role>
<key class="int">3</key>
<dirty>false</dirty>
<storedSnapshot class="map">
<entry>
<privilege reference="../../../set/privilege"/>
<privilege reference="../../../set/privilege"/>
</entry>
</storedSnapshot>
</privileges>
</role>


I want it to look like this:

<role>
<roleName>Administrator</roleName>
<privileges>
<privilegeId>1001</privilegeId>
<privilegeName>Admin Privilege</privilegeName>
<privilegeKey>Admin</privilegeKey>
</privileges>
</role>


How can i omit/delete/not include all those additional fields? Seems like they are "utility" fields, added by hibernate, as i haven't declared them in my hbm.xml.
I already tried omitting them, adding Privileges collection as implicit and other things i found on XStream page.

Edit
I failed to create XSLT template as suggested below, but found that custom converter is really good and simple tool to do this job. Check the help page here - http://x-stream.github.io/converter-tutorial.html.
And here's my marshal method:

public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
Role role = (Role) value;
writer.startNode("roleId");
writer.setValue(role.getRoleId().toString());
writer.endNode();
writer.startNode("roleName");
writer.setValue(role.getRoleName());
writer.endNode();
writer.startNode("privileges");
for (Privilege privilege : role.getPrivileges()){
writer.startNode("privilege");
writer.setValue(privilege.getPrivilegeName());
writer.endNode();
}
writer.endNode();
}


And xml it produces:

<role>
<roleId>3</roleId>
<roleName>Web Administrator</roleName>
<privileges>
<privilege>Web Access</privilege>
</privileges>
</role>

Answer

You can use XSL to transform your XML

XStream is delivered with a SAXSource implementation, that allows an XStream instance to be the source of a XML transformer.

Example Look at the following stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/cat">
    <xsl:copy>
      <xsl:apply-templates select="mName"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

It is used here to remove the age of the cat on the fly (assuming XSLT is a string with the stylesheet above):

XStream xstream = new XStream();
xstream.alias("cat", Cat.class);

TraxSource traxSource = new TraxSource(new Cat(4, "Garfield"), xstream);
Writer buffer = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer(
    new StreamSource(new StringReader(XSLT)));
transformer.transform(traxSource, new StreamResult(buffer));

The result in the buffer:

<cat>
  <mName>Garfield</mName>
</cat>

Check this link for reference