Is there any way to marshal Map<String, Object> with Moxy to JSON so that the result uses natural constructs of JSON?
That is, the keys are strings and for all possible values following rules apply (possibly not a complete set):
Number (e.g., Integer) becomes a JSON number (or a string if it's too big)String becomes a JSON stringSet, Array, Iterable become a JSON arrayMap<String, Object>, the same rules are recursively appliedThere is already an example how to marshal Map<String, Integer> and other specific maps by using @XmlVariableNode (see http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-using-maps-key-as.html?m=1), but I was unable to extend this idea to a point where also subtypes can be inserted as a value.
Note that Moxy should be able to unmarshal the JSON back to the original Map.
Jackson is capable of doing this by default.
I've tried to get something like you want with JAXB RI (XML):
@XmlRootElement
public class Foo {
@XmlJavaTypeAdapter(MapAdapter.class)
public Map<String, Object> map;
}
public class MapAdapter extends XmlAdapter<MapEntry[], Map<String, Object>> {
@Override
public Map<String, Object> unmarshal(MapEntry[] v) throws Exception {
Map<String, Object> map = new HashMap<>();
for (MapEntry me : v)
map.put(me.key, me.value);
return map;
}
@Override
public MapEntry[] marshal(Map<String, Object> v) throws Exception {
MapEntry[] mes = new MapEntry[v.size()];
int i = 0;
for (Map.Entry<String, Object> entry : v.entrySet())
mes[i++] = new MapEntry(entry.getKey(), entry.getValue());
return mes;
}
}
public class MapEntry {
public String key;
public Object value;
public MapEntry() {}
public MapEntry(String key, Object value) {
this.key = key;
this.value = value;
}
}
Unfortunately MOXy has some bug ( https://bugs.eclipse.org/bugs/show_bug.cgi?id=465014 ) and is not able to handle this.
If you need MOXy then you have to use the approach described in Blaise's blog:
@XmlRootElement
public class MoxyFoo {
@XmlJavaTypeAdapter(MoxyMapAdapter.class)
public Map<String, Object> map = new HashMap<>();
}
public class MoxyMapAdapter extends XmlAdapter<MoxyMapAdapter.AdaptedMap, Map<String, Object>> {
@Override
public AdaptedMap marshal(Map<String, Object> map) throws Exception {
AdaptedMap adaptedMap = new AdaptedMap();
for (Entry<String, Object> entry : map.entrySet()) {
AdaptedEntry adaptedEntry = new AdaptedEntry();
adaptedEntry.key = entry.getKey();
adaptedEntry.value = entry.getValue();
adaptedMap.entries.add(adaptedEntry);
}
return adaptedMap;
}
@Override
public Map<String, Object> unmarshal(AdaptedMap adaptedMap) throws Exception {
List<AdaptedEntry> adaptedEntries = adaptedMap.entries;
Map<String, Object> map = new HashMap<>(adaptedEntries.size());
for (AdaptedEntry adaptedEntry : adaptedEntries) {
map.put(adaptedEntry.key, adaptedEntry.value);
}
return map;
}
public static class AdaptedMap {
@XmlVariableNode("key")
List<AdaptedEntry> entries = new ArrayList<>();
}
public static class AdaptedEntry {
@XmlTransient
public String key;
@XmlValue
public Object value;
}
}
It's working fine for XML, but not for JSON. For JSON only marshalling is working now. I've filled a bug to fix unmarshalling: https://bugs.eclipse.org/bugs/show_bug.cgi?id=465016 .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With