Люди часто спрашивают меня, как они могут отобразить
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