1
12 package com.thoughtworks.xstream.converters.collections;
13
14 import com.thoughtworks.xstream.converters.MarshallingContext;
15 import com.thoughtworks.xstream.converters.UnmarshallingContext;
16 import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
17 import com.thoughtworks.xstream.core.JVM;
18 import com.thoughtworks.xstream.core.util.Fields;
19 import com.thoughtworks.xstream.core.util.HierarchicalStreams;
20 import com.thoughtworks.xstream.core.util.PresortedMap;
21 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
22 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
23 import com.thoughtworks.xstream.mapper.Mapper;
24
25 import java.lang.reflect.Field;
26 import java.util.Comparator;
27 import java.util.SortedMap;
28 import java.util.TreeMap;
29
30
39 public class TreeMapConverter extends MapConverter {
40
41 private static final class NullComparator extends Mapper.Null implements Comparator {
42 public int compare(Object o1, Object o2) {
43 Comparable c1 = (Comparable)o1;
44 Comparable c2 = (Comparable)o2;
45 return c1.compareTo(o2);
46 }
47 }
48
49 private final static Comparator NULL_MARKER = new NullComparator();
50 private final static Field comparatorField = Fields.locate(TreeMap.class, Comparator.class, false);
51
52 public TreeMapConverter(Mapper mapper) {
53 super(mapper, TreeMap.class);
54 }
55
56 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
57 SortedMap sortedMap = (SortedMap) source;
58 marshalComparator(sortedMap.comparator(), writer, context);
59 super.marshal(source, writer, context);
60 }
61
62 protected void marshalComparator(Comparator comparator, HierarchicalStreamWriter writer,
63 MarshallingContext context) {
64 if (comparator != null) {
65 writer.startNode("comparator");
66 writer.addAttribute(mapper().aliasForSystemAttribute("class"),
67 mapper().serializedClass(comparator.getClass()));
68 context.convertAnother(comparator);
69 writer.endNode();
70 }
71 }
72
73 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
74 TreeMap result = comparatorField != null ? new TreeMap() : null;
75 final Comparator comparator = unmarshalComparator(reader, context, result);
76 if (result == null) {
77 result = comparator == null || comparator == NULL_MARKER ? new TreeMap() : new TreeMap(comparator);
78 }
79 populateTreeMap(reader, context, result, comparator);
80 return result;
81 }
82
83 protected Comparator unmarshalComparator(HierarchicalStreamReader reader,
84 UnmarshallingContext context, TreeMap result) {
85 final Comparator comparator;
86 if (reader.hasMoreChildren()) {
87 reader.moveDown();
88 if (reader.getNodeName().equals("comparator")) {
89 Class comparatorClass = HierarchicalStreams.readClassType(reader, mapper());
90 comparator = (Comparator) context.convertAnother(result, comparatorClass);
91 } else if (reader.getNodeName().equals("no-comparator")) {
92 comparator = null;
93 } else {
94
95 return NULL_MARKER;
96 }
97 reader.moveUp();
98 } else {
99 comparator = null;
100 }
101 return comparator;
102 }
103
104 protected void populateTreeMap(HierarchicalStreamReader reader, UnmarshallingContext context,
105 TreeMap result, Comparator comparator) {
106 boolean inFirstElement = comparator == NULL_MARKER;
107 if (inFirstElement) {
108 comparator = null;
109 }
110 SortedMap sortedMap = new PresortedMap(comparator != null && JVM.hasOptimizedTreeMapPutAll() ? comparator : null);
111 if (inFirstElement) {
112
113 putCurrentEntryIntoMap(reader, context, result, sortedMap);
114 reader.moveUp();
115 }
116 populateMap(reader, context, result, sortedMap);
117 try {
118 if (JVM.hasOptimizedTreeMapPutAll()) {
119 if (comparator != null && comparatorField != null) {
120 comparatorField.set(result, comparator);
121 }
122 result.putAll(sortedMap);
123 } else if (comparatorField != null) {
124 comparatorField.set(result, sortedMap.comparator());
125 result.putAll(sortedMap);
126 comparatorField.set(result, comparator);
127 } else {
128 result.putAll(sortedMap);
129 }
130 } catch (final IllegalAccessException e) {
131 throw new ObjectAccessException("Cannot set comparator of TreeMap", e);
132 }
133 }
134 }
135