Статьи

MOXy’s @XmlVariableNode – использование ключа карты в качестве имени узла


Люди часто спрашивают меня, как они могут отобразить
java.util.Map так, чтобы ключи стали именами узлов. В этой статье я продемонстрирую, как это можно сделать с помощью нового отображения узла переменных, которое мы добавили в
EclipseLink MOXy .

Вы можете попробовать это сегодня, используя ночную сборку EclipseLink 2.6.0:

Ввод / вывод

Ниже представлены представления XML и JSON, которые мы будем использовать в этом примере. У каждого есть имена узлов, которые соответствуют ключам и содержимому, которые соответствуют значениям
карты .

XML (input.xml)

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <A>1</A>
   <B>2</B>
</root>
JSON (вывод)

{
   "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).

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);
    }
 
}
Дальнейшее чтение

Если вам понравился этот пост, то вы также можете быть заинтересованы в: