Люди часто спрашивают меня, как они могут отобразить
java.util.Map так, чтобы ключи стали именами узлов. В этой статье я продемонстрирую, как это можно сделать с помощью нового отображения узла переменных, которое мы добавили в
EclipseLink MOXy .
Вы можете попробовать это сегодня, используя ночную сборку EclipseLink 2.6.0:
Ввод / вывод
Ниже представлены представления XML и JSON, которые мы будем использовать в этом примере. У каждого есть имена узлов, которые соответствуют ключам и содержимому, которые соответствуют значениям
карты .
XML (input.xml)
Ниже приведен демонстрационный код, который можно запустить, чтобы доказать, что все работает. Объект
Root будет создан из входных данных XML и упорядочен для создания выходных данных JSON.
Если вам понравился этот пост, то вы также можете быть заинтересованы в:
<?xml version="1.0" encoding="UTF-8"?> <root> <A>1</A> <B>2</B> </root>
JSON (вывод)
Нам нужно представление XML (и JSON) не по умолчанию для
Map, поэтому мы будем использовать
XmlAdapter (см.
JAXB и java.util.Map ). Расширение MOXy
@XmlPath будет использоваться для предотвращения оборачивания содержимого адаптированной
карты в родительский элемент (см.
XPath Based Mapping ).
{
"A" : 1,
"B" : 2
}
Модель Java (Root)
Нам нужно представление XML (и JSON) не по умолчанию для
Map, поэтому мы будем использовать
XmlAdapter (см.
JAXB и java.util.Map ). Расширение MOXy
@XmlPath будет использоваться для предотвращения оборачивания содержимого адаптированной
карты в родительский элемент (см.
XPath Based Mapping ).
package blog.variablenode.map;
import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlPath(".")
@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, Integer> map = new HashMap<String, Integer>();
}
XmlAdapter (MapAdapter)
XMLAdapter используется для преобразования объекта для целей сортировочных / демаршаллизации (см
XMLAdapter — JAXB Секретное оружие ). В этом примере мы преобразовать
карту к
AdaptedMap , который имеет
список из
AdaptedEntry значений. Эти
значения AdaptedEntry имеют поле (
ключ ) для представления ключа. Именно это поле мы будем использовать с
@XmlVariableNode (строка 13). Мы пометим ключевое поле как
@XmlTransient, чтобы предотвратить его маршалинг / демаршаллирование (строка 20).
XMLAdapter — JAXB Секретное оружие ). В этом примере мы преобразовать
карту к
AdaptedMap , который имеет
список из
AdaptedEntry значений. Эти
значения AdaptedEntry имеют поле (
ключ ) для представления ключа. Именно это поле мы будем использовать с
@XmlVariableNode (строка 13). Мы пометим ключевое поле как
@XmlTransient, чтобы предотвратить его маршалинг / демаршаллирование (строка 20).
package blog.variablenode.map;
import java.util.*;
import java.util.Map.Entry;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.persistence.oxm.annotations.XmlVariableNode;
public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<String, Integer>> {
public static class AdaptedMap {
@XmlVariableNode("key")
List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();
}
public static class AdaptedEntry {
@XmlTransient
public String key;
@XmlValue
public Integer value;
}
@Override
public AdaptedMap marshal(Map<String, Integer> map) throws Exception {
AdaptedMap adaptedMap = new AdaptedMap();
for(Entry<String, Integer> 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, Integer> unmarshal(AdaptedMap adaptedMap) throws Exception {
List<AdaptedEntry> adaptedEntries = adaptedMap.entries;
Map<String, Integer> map = new HashMap<String, Integer>(adaptedEntries.size());
for(AdaptedEntry adaptedEntry : adaptedEntries) {
map.put(adaptedEntry.key, adaptedEntry.value);
}
return map;
}
}
демонстрация
Ниже приведен демонстрационный код, который можно запустить, чтобы доказать, что все работает. Объект
Root будет создан из входных данных XML и упорядочен для создания выходных данных JSON.
package blog.variablenode.map;
import java.io.File;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/blog/variablenode/map/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.marshal(root, System.out);
}
}
Дальнейшее чтение
Если вам понравился этот пост, то вы также можете быть заинтересованы в:
- MOXy’s @XmlVariableNode — Пример схемы JSON
- Указание EclipseLink MOXy в качестве вашего JAXB-провайдера
- JAXB и java.util.Map
- JSON Binding с EclipseLink MOXy — пример в Twitter