It's not terribly difficult to do with a custom converter. This is a little bit of a long example, but I hope it's simple enough to get the gist of what you need to do:
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
public final class ConverterTest {
public static void main(String[] args) {
XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
xstream.registerConverter(new PositionConverter());
final Position position = new Position();
position.setTitle("The Title");
position.setStartDate("The Start Date");
position.setEndDate("The End Date");
final String xml = xstream.toXML(position);
System.out.println("Generated XML:");
System.out.println(xml);
final Position genPosition = (Position) xstream.fromXML(xml);
System.out.println("Generated Position:");
System.out.println("\tTitle: " + genPosition.getTitle());
System.out.println("\tStart Date: " + genPosition.getStartDate());
System.out.println("\tEnd Date: " + genPosition.getEndDate());
}
@XStreamAlias("Position")
private static class Position {
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public String getStartDate() {
return startDate;
}
public void setStartDate(String startDate) {
this.startDate = startDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
private String title;
private String startDate;
private String endDate;
}
private static class PositionConverter implements Converter {
public boolean canConvert(Class clazz) {
return Position.class == clazz;
}
public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
Position position = (Position)value;
writer.startNode("PositionBorder");
writer.startNode("Title");
writer.setValue(position.getTitle());
writer.endNode();
writer.startNode("StartDate");
writer.setValue(position.getStartDate());
writer.endNode();
writer.startNode("EndDate");
writer.setValue(position.getEndDate());
writer.endNode();
writer.endNode();
}
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
Position position = new Position();
// move it to <PositionBorder> tag.
reader.moveDown();
// now move it to <Title> tag.
reader.moveDown();
String title = reader.getValue();
position.setTitle(title);
reader.moveUp(); // moves back to <PositionBorder>
reader.moveDown(); // should move down to <StartDate> tag
String startDate = reader.getValue();
position.setStartDate(startDate);
reader.moveUp(); // move back to <PositionBorder>
reader.moveDown(); // should move down to <EndDate> tag
String endDate = reader.getValue();
position.setEndDate(endDate);
reader.moveUp(); // move back to <PositionBorder>
return position;
}
}
}
Try running that and see what happens. You'll need to modify it to suit your own types, of course -- I just used strings for all of Position's fields (and I'm sure you're Position class isn't nested, either), but converting from a String to a Date (or whatever) should be rather trivial.
One thing you'll want to keep an eye on (and I might not have gotten it completely right in my example) is matching your reader.moveDown() and reader.moveUp() calls. (And, if you're going to do any marshalling instead of just unmarshalling -- which I don't expect from your question -- you'll want to match your writer.startNode() and writer.endNode() calls as well.) It probably won't cause any problems with this example, but I'm sure it'll raise issues if you're doing anything larger or processing multiple files with the same XStream or Converter instance. Also, if you try reader.moveDown() from an invalid location, you'll get a really ugly exception -- it should be pretty obvious.
I had to play around with the moveUp/moveDown methods a bit to get them in the right places, so I'm sure you'll need to test it and tweak it until you get what you need.