Search code examples
javaxstream

Having backward compatible for xstream in the following case


I had the following class.

class SimpleDate {
    private final int year;   /* ? */
    private final int month;  /* 0 ~ 11 */
    private final int date;   /* 1 ~ 31 */
}

Now, I plan to re-factor the class to.

class SimpleDate {
    private final int year;   /* ? */
    private final int month;  /* 1 ~ 12!!!!! <-- change from 0 based to 1 based */
    private final int day;    /* 1 ~ 31 */
}

To solve the the variable renaming issues, I will use alias.

xStream.aliasField("date", SimpleDate.class, "day");

However, how can I know I am reading an old XML file, and I will +1 for the newly read month field, to change it from based 0 to based 1?


Solution

  • // Converter used to make sure XStream still able to read old version of XML
    // files.
    private static Converter getSimpleDateConverter() {
        return new Converter() {
            @Override
            public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext mc) {
                SimpleDate simpleDate = (SimpleDate) o;
                writer.startNode("year");
                writer.setValue("" + simpleDate.getYear());
                writer.endNode();
                writer.startNode("month");
                writer.setValue("" + simpleDate.getMonth());
                writer.endNode();
                writer.startNode("day");
                writer.setValue("" + simpleDate.getDay());
                writer.endNode();
            }
    
            @Override
            public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext uc) {
                Map<String, String> map = new HashMap<String, String>();
                while (reader.hasMoreChildren()) {
                    reader.moveDown();
                    map.put(reader.getNodeName(), reader.getValue());
                    reader.moveUp();
                }
                // Introduce since version 1.0.6.
                // We had renamed 'date' field to 'day' field.
                final boolean isOldVersion = map.containsKey("date");
                if (isOldVersion) {
                    final int year = Integer.parseInt(map.get("year"));
                    // We changed 0 based month to 1 based month, to fit into Joda library.
                    final int month = Integer.parseInt(map.get("month")) + 1;
                    final int day  = Integer.parseInt(map.get("date"));
                    return new SimpleDate(year, month, day);
                } else {
                    final int year = Integer.parseInt(map.get("year"));
                    final int month = Integer.parseInt(map.get("month"));
                    final int day  = Integer.parseInt(map.get("day"));
                    return new SimpleDate(year, month, day);
                }
            }
    
            @Override
            public boolean canConvert(Class type) {
                return SimpleDate.class.isAssignableFrom(type);
            }
        };
    }
    

    xStream.registerConverter(getSimpleDateConverter());