Java JAXB:我应该如何封送复杂的嵌套数据结构?
我有几个复杂的数据结构,比如Java JAXB:我应该如何封送复杂的嵌套数据结构?,java,xml,data-binding,data-structures,jaxb,Java,Xml,Data Binding,Data Structures,Jaxb,我有几个复杂的数据结构,比如 Map< A, Set< B > > Set< Map< A, B > > Set< Map< A, Set< B > > > Map< A, Map< B, Set< C > > > and so on (more complex data structures) 这是我的适配器类: import java.util.*; import jav
Map< A, Set< B > >
Set< Map< A, B > >
Set< Map< A, Set< B > > >
Map< A, Map< B, Set< C > > >
and so on (more complex data structures)
这是我的适配器类:
import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
public class Adapters {
public final static class MapAdapter<K, V>
extends XmlAdapter<MapAdapter.Adapter<K, V>, Map<K, V>> {
@XmlType
@XmlRootElement
public final static class Adapter<K, V> {
@XmlElement
protected List<MyEntry<K, V>> key = new LinkedList<MyEntry<K, V>>();
private Adapter() {
}
public Adapter(Map<K, V> original) {
for (Map.Entry<K, V> entry : original.entrySet()) {
key.add(new MyEntry<K, V>(entry));
}
}
}
@XmlType
@XmlRootElement
public final static class MyEntry<K, V> {
@XmlElement
protected K key;
@XmlElement
protected V value;
private MyEntry() {
}
public MyEntry(Map.Entry<K, V> original) {
key = original.getKey();
value = original.getValue();
}
}
@Override
public Adapter<K, V> marshal(Map<K, V> obj) {
return new Adapter<K, V>(obj);
}
@Override
public Map<K, V> unmarshal(Adapter<K, V> obj) {
throw new UnsupportedOperationException("unmarshalling is never performed");
}
}
}
import java.io.*;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
import org.junit.*;
import static java.lang.System.*;
public class SomeTest {
@Test
public void _map2()
throws Exception {
Map<String, Map<String, String>> dataStructure =
new HashMap<String, Map<String, String>>();
Map<String, String> inner1 = new HashMap<String, String>();
Map<String, String> inner2 = new HashMap<String, String>();
dataStructure.put("a", inner1);
dataStructure.put("b", inner1);
inner1.put("a1", "1");
inner1.put("a2", "2");
inner2.put("b1", "1");
inner2.put("b2", "2");
JAXBContext context = JAXBContext.newInstance(Adapters.XMap.class,
Adapters.XCount.class, Adapters.XEntry.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setAdapter(new Adapters.MapAdapter());
StringWriter sw = new StringWriter();
marshaller.marshal(dataStructure, sw);
out.println(sw.toString());
}
}
import java.util.*;
导入javax.xml.bind.annotation.*;
导入javax.xml.bind.annotation.adapters.*;
公共类适配器{
公共最终静态类映射适配器
扩展XmlAdapter{
@XmlType
@XmlRootElement
公共最终静态类适配器{
@XmlElement
受保护的列表键=新的LinkedList();
专用适配器(){
}
公共适配器(原始映射){
对于(Map.Entry:original.entrySet()){
添加(新MyEntry(条目));
}
}
}
@XmlType
@XmlRootElement
公共最终静态类MyEntry{
@XmlElement
受保护的K密钥;
@XmlElement
保护V值;
私人MyEntry(){
}
公共MyEntry(Map.Entry原件){
key=original.getKey();
value=original.getValue();
}
}
@凌驾
公共适配器封送处理(Map obj){
返回新适配器(obj);
}
@凌驾
公共地图解组(适配器obj){
抛出新的UnsupportedOperationException(“从未执行解组”);
}
}
}
这是我的JUnit测试用例:
import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
public class Adapters {
public final static class MapAdapter<K, V>
extends XmlAdapter<MapAdapter.Adapter<K, V>, Map<K, V>> {
@XmlType
@XmlRootElement
public final static class Adapter<K, V> {
@XmlElement
protected List<MyEntry<K, V>> key = new LinkedList<MyEntry<K, V>>();
private Adapter() {
}
public Adapter(Map<K, V> original) {
for (Map.Entry<K, V> entry : original.entrySet()) {
key.add(new MyEntry<K, V>(entry));
}
}
}
@XmlType
@XmlRootElement
public final static class MyEntry<K, V> {
@XmlElement
protected K key;
@XmlElement
protected V value;
private MyEntry() {
}
public MyEntry(Map.Entry<K, V> original) {
key = original.getKey();
value = original.getValue();
}
}
@Override
public Adapter<K, V> marshal(Map<K, V> obj) {
return new Adapter<K, V>(obj);
}
@Override
public Map<K, V> unmarshal(Adapter<K, V> obj) {
throw new UnsupportedOperationException("unmarshalling is never performed");
}
}
}
import java.io.*;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
import org.junit.*;
import static java.lang.System.*;
public class SomeTest {
@Test
public void _map2()
throws Exception {
Map<String, Map<String, String>> dataStructure =
new HashMap<String, Map<String, String>>();
Map<String, String> inner1 = new HashMap<String, String>();
Map<String, String> inner2 = new HashMap<String, String>();
dataStructure.put("a", inner1);
dataStructure.put("b", inner1);
inner1.put("a1", "1");
inner1.put("a2", "2");
inner2.put("b1", "1");
inner2.put("b2", "2");
JAXBContext context = JAXBContext.newInstance(Adapters.XMap.class,
Adapters.XCount.class, Adapters.XEntry.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setAdapter(new Adapters.MapAdapter());
StringWriter sw = new StringWriter();
marshaller.marshal(dataStructure, sw);
out.println(sw.toString());
}
}
import java.io.*;
导入java.util.*;
导入javax.xml.bind.*;
导入javax.xml.bind.annotation.*;
导入javax.xml.bind.annotation.adapters.*;
导入org.junit.*;
导入静态java.lang.System.*;
公共类测试{
@试验
公共空间(u map2)
抛出异常{
地图数据结构=
新的HashMap();
Map inner1=新的HashMap();
Map inner2=新的HashMap();
数据结构put(“a”,inner1);
数据结构put(“b”,inner1);
1.将(“a1”、“1”);
1.认沽权(“a2”、“2”);
第二项认沽权(“b1”、“1”);
2.认沽权(“b2”、“2”);
JAXBContext context=JAXBContext.newInstance(Adapters.XMap.class,
Adapters.XCount.class、Adapters.XEntry.class);
Marshaller=context.createMarshaller();
setProperty(marshaller.JAXB_片段,true);
setProperty(marshaller.JAXB_格式化的_输出,true);
setAdapter(新适配器.MapAdapter());
StringWriter sw=新的StringWriter();
marshaller.Marshall(数据结构,软件);
out.println(sw.toString());
}
}
看来您使用XMLAdapter的方向是正确的。。。错误消息可能是一个线索:
阶级
java.util.Collections$UnmodifiableMap
它的任何一个超级类都不为人所知
这个背景
您是否正在使用Collections.unmodifiableMap()包装地图?错误究竟发生在哪里
(先前的答案留给好奇的人作为陈腐的记录) 您可以创建自定义封送拆收器/解封器逻辑,其工作方式比适配器的想法更严格(我想,我以前从未使用过) 基本上,您可以指定一个静态函数来完成这项工作,还可以创建一个自定义类。(我通常将静态函数放在有问题的类中,但您不必这样做。)然后在.XJB文件中放一行,告诉JAXB使用静态函数 现在,我查看了我现有的代码,我看到我所做的只是将属性字符串转换为自定义Java对象。以下是代码,仅供参考,但仅用于属性 JAXB文件:
<?xml version="1.0" ?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
jaxb:version="2.0">
<jaxb:bindings schemaLocation={your schema} node="/xsd:schema">
<jaxb:bindings node={some XPATH expression to select a node}>
<jaxb:bindings node={maybe another XPATH relative to the above}>
<jaxb:property>
<jaxb:baseType>
<jaxb:javaType name={your custom Java class}
parseMethod={your static method for unmarshaling}
printMethod={your static method for marshaling}
/>
</jaxb:baseType>
</jaxb:property>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
(parseMethod和printMethod转换为属性字符串或从属性字符串转换而来)我在没有XmlAdapter的情况下解决了问题 我已经为Map、Map.Entry和Collection编写了JAXB注释对象
主要思想在方法xmlizeNestedStructure(…)中:
<xMap>
<map>
<entry>
<key xsi:type="xCount" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<count>1</count>
<content xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a</content>
</key>
<value xsi:type="xCollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a1</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a2</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a3</entry>
</list>
</value>
</entry>
<entry>
<key xsi:type="xCount" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<count>2</count>
<content xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b</content>
</key>
<value xsi:type="xCollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b1</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b3</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b2</entry>
</list>
</value>
</entry>
<entry>
<key xsi:type="xCount" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<count>3</count>
<content xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c</content>
</key>
<value xsi:type="xCollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c1</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c2</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c3</entry>
</list>
</value>
</entry>
</map>
</xMap>
看看代码:
public final class Adapters {
private Adapters() {
}
public static Class<?>[] getXmlClasses() {
return new Class<?>[]{
XMap.class, XEntry.class, XCollection.class, XCount.class
};
}
public static Object xmlizeNestedStructure(Object input) {
if (input instanceof Map<?, ?>) {
return xmlizeNestedMap((Map<?, ?>) input);
}
if (input instanceof Collection<?>) {
return xmlizeNestedCollection((Collection<?>) input);
}
return input; // non-special object, return as is
}
public static XMap<?, ?> xmlizeNestedMap(Map<?, ?> input) {
XMap<Object, Object> ret = new XMap<Object, Object>();
for (Map.Entry<?, ?> e : input.entrySet()) {
ret.add(xmlizeNestedStructure(e.getKey()),
xmlizeNestedStructure(e.getValue()));
}
return ret;
}
public static XCollection<?> xmlizeNestedCollection(Collection<?> input) {
XCollection<Object> ret = new XCollection<Object>();
for (Object entry : input) {
ret.add(xmlizeNestedStructure(entry));
}
return ret;
}
@XmlType
@XmlRootElement
public final static class XMap<K, V> {
@XmlElementWrapper(name = "map")
@XmlElement(name = "entry")
private List<XEntry<K, V>> list = new LinkedList<XEntry<K, V>>();
public XMap() {
}
public void add(K key, V value) {
list.add(new XEntry<K, V>(key, value));
}
}
@XmlType
@XmlRootElement
public final static class XEntry<K, V> {
@XmlElement
private K key;
@XmlElement
private V value;
private XEntry() {
}
public XEntry(K key, V value) {
this.key = key;
this.value = value;
}
}
@XmlType
@XmlRootElement
public final static class XCollection<V> {
@XmlElementWrapper(name = "list")
@XmlElement(name = "entry")
private List<V> list = new LinkedList<V>();
public XCollection() {
}
public void add(V obj) {
list.add(obj);
}
}
}
公共最终类适配器{
专用适配器(){
}
公共静态类[]getXmlClasses(){
返回新类[]{
XMap.class、XEntry.class、XCollection.class、XCount.class
};
}
公共静态对象xmlizeNestedStructure(对象输入){
if(映射的输入实例){
返回xmlizeNestedMap((Map)输入);
}
if(集合的输入实例){
返回xmlizeNestedCollection((Collection)输入);
}
返回输入;//非特殊对象,按原样返回
}
公共静态XMap xmlizeNestedMap(映射输入){
XMap ret=新的XMap();
对于(Map.Entry e:input.entrySet()){
ret.add(xmlizeNestedStructure(e.getKey()),
xmlizeNestedStructure(e.getValue());
}
返回ret;
}
公共静态XCollection xmlizeNestedCollection(集合输入){
XCollection ret=新的XCollection();
for(对象输入:输入){
ret.add(xmlizeNestedStructure(条目));
}
返回ret;
}
@XmlType
@XmlRootElement
公共最终静态类XMap{
@XmlElementWrapper(name=“map”)
@xmlement(name=“entry”)
私有列表=新的LinkedList();
公共XMap(){
}
公共无效添加(K键,V值){
添加(新的XEntry(键,值));
}
}
@XmlType
@XmlRootElement
公共最终静态类XEntry{
@XmlElement
私钥;
@XmlElement
私人价值;
私人森特里(){
}
公共XEntry(K键,V值){
this.key=key;
这个值=值;
}
}
@XmlType
@XmlRootElement
公共最终静态类XCollection{
@xmlementwrapper(name=“list”)
@xmlement(name=“entry”)
私有列表=新的LinkedList();
公共XCollection(){
}
公共无效添加(V obj){
列表。添加(obj);
}
}
}
它能工作强>
让我们看一个演示输出:
<xMap>
<map>
<entry>
<key xsi:type="xCount" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<count>1</count>
<content xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a</content>
</key>
<value xsi:type="xCollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a1</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a2</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">a3</entry>
</list>
</value>
</entry>
<entry>
<key xsi:type="xCount" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<count>2</count>
<content xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b</content>
</key>
<value xsi:type="xCollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b1</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b3</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">b2</entry>
</list>
</value>
</entry>
<entry>
<key xsi:type="xCount" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<count>3</count>
<content xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c</content>
</key>
<value xsi:type="xCollection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c1</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c2</entry>
<entry xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">c3</entry>
</list>
</value>
</entry>
</map>
</xMap>
1.
A.
class Adapters {
private Adapters() {
}
public static Class<?>[] getXmlClasses() {
return new Class<?>[]{XMap.class, XEntry.class, XCollection.class};
}
public static Object xmlizeNestedStructure(Object input) {
if (input instanceof Map<?, ?>) {
return xmlizeNestedMap((Map<?, ?>) input);
}
if (input instanceof Collection<?>) {
return xmlizeNestedCollection((Collection<?>) input);
}
return input; // non-special object, return as is
}
public static Object dexmlizeNestedStructure(Object input) {
if (input instanceof XMap<?, ?>) {
return dexmlizeNestedMap((XMap<?, ?>) input);
}
if (input instanceof XCollection<?>) {
return dexmlizeNestedCollection((XCollection<?>) input);
}
return input; // non-special object, return as is
}
private static Object dexmlizeNestedCollection(XCollection<?> input)
{
Class<? extends Collection> clazz = input.getClazz();
Collection collection = null;
try
{
collection = clazz.newInstance();
List dataList = input.getList();
for (Object object : dataList)
{
collection.add(dexmlizeNestedStructure(object));
}
}
catch (Exception e)
{
e.printStackTrace();
}
return collection;
}
private static Object dexmlizeNestedMap(XMap<?, ?> input)
{
Class<? extends Map> clazz = input.getClazz();
Map map = null;
try
{
map = clazz.newInstance();
List<? extends XEntry> entryList = input.getList();
for (XEntry xEntry : entryList)
{
Object key = dexmlizeNestedStructure(xEntry.getKey());
Object value = dexmlizeNestedStructure(xEntry.getValue());
map.put(key, value);
}
}
catch (Exception e)
{
e.printStackTrace();
}
return map;
}
public static XMap<?, ?> xmlizeNestedMap(Map<?, ?> input) {
XMap<Object, Object> ret = new XMap<Object, Object>(input.getClass());
for (Map.Entry<?, ?> e : input.entrySet()) {
ret.add(xmlizeNestedStructure(e.getKey()),
xmlizeNestedStructure(e.getValue()));
}
return ret;
}
public static XCollection<?> xmlizeNestedCollection(Collection<?> input) {
XCollection<Object> ret = new XCollection<Object>(input.getClass());
for (Object entry : input) {
ret.add(xmlizeNestedStructure(entry));
}
return ret;
}
@XmlType
@XmlRootElement
public final static class XMap<K, V>{
private List<XEntry<K, V>> list = new ArrayList<XEntry<K, V>>();
private Class<? extends Map> clazz = null;
public XMap(Class mapClazz) {
this.clazz = (Class<? extends Map>)mapClazz;
}
public XMap() {
}
public void add(K key, V value) {
list.add(new XEntry<K, V>(key, value));
}
@XmlElementWrapper(name = "map")
@XmlElement(name = "entry")
public List<XEntry<K, V>> getList()
{
return list;
}
public void setList(List<XEntry<K, V>> list)
{
this.list = list;
}
@XmlElement(name="clazz")
public Class<? extends Map> getClazz()
{
return clazz;
}
public void setClazz(Class<? extends Map> clazz)
{
this.clazz = clazz;
}
}
@XmlType
@XmlRootElement
public final static class XEntry<K, V> {
private K key;
private V value;
private XEntry() {
}
public XEntry(K key, V value) {
this.key = key;
this.value = value;
}
@XmlElement
public K getKey()
{
return key;
}
public void setKey(K key)
{
this.key = key;
}
@XmlElement
public V getValue()
{
return value;
}
public void setValue(V value)
{
this.value = value;
}
}
@XmlType
@XmlRootElement
public final static class XCollection<V> {
private List<V> list = new ArrayList<V>();
private Class<? extends Collection> clazz = null;
public XCollection(Class collectionClazz) {
this.clazz = collectionClazz;
}
public XCollection() {
}
public void add(V obj) {
list.add(obj);
}
@XmlElementWrapper(name = "collection")
@XmlElement(name = "entry")
public List<V> getList()
{
return list;
}
public void setList(List<V> list)
{
this.list = list;
}
@XmlElement(name="clazz")
public Class<? extends Collection> getClazz()
{
return clazz;
}
public void setClazz(Class<? extends Collection> clazz)
{
this.clazz = clazz;
}
}
}
@XmlJavaTypeAdapter(MapAdapter.class)
Map<String, Map<String, Integer>> mapOfMap = new HashMap<String,Map<String, Integer>>();
public class MapType {
public List<MapEntryType> host = new ArrayList<MapEntryType>();
}
public class MapEntryType {
@XmlAttribute
public String ip;
@XmlElement
public List<LinkCountMapType> request_limit = new ArrayList<LinkCountMapType>();
}
public class LinkCountMapType {
@XmlAttribute
public String service;
@XmlValue
public Integer count;
}
public final class MapAdapter extends XmlAdapter<MapType, Map<String, Map<String, Integer>>> {
@Override
public Map<String, Map<String, Integer>> unmarshal(MapType v) throws Exception {
Map<String, Map<String, Integer>> mainMap = new HashMap<String, Map<String, Integer>>();
List<MapEntryType> myMapEntryTypes = v.host;
for (MapEntryType myMapEntryType : myMapEntryTypes) {
Map<String, Integer> linkCountMap = new HashMap<String, Integer>();
for (LinkCountMapType myLinkCountMapType : myMapEntryType.request_limit) {
linkCountMap.put(myLinkCountMapType.service, myLinkCountMapType.count);
}
mainMap.put(myMapEntryType.ip, linkCountMap);
}
return mainMap;
}
@Override
public MapType marshal(Map<String, Map<String, Integer>> v) throws Exception {
MapType myMapType = new MapType();
List<MapEntryType> entry = new ArrayList<MapEntryType>();
for (String ip : v.keySet()) {
MapEntryType myMapEntryType = new MapEntryType();
Map<String, Integer> linkCountMap = v.get(ip);
List<LinkCountMapType> linkCountList = new ArrayList<LinkCountMapType>();
for (String link : linkCountMap.keySet()) {
LinkCountMapType myLinkCountMapType = new LinkCountMapType();
Integer count = linkCountMap.get(link);
myLinkCountMapType.count = count;
myLinkCountMapType.service = link;
linkCountList.add(myLinkCountMapType);
}
myMapEntryType.ip = ip;
myMapEntryType.request_limit = linkCountList;
entry.add(myMapEntryType);
}
myMapType.host = entry;
return myMapType;
}
<mapOfmap>
<host ip="127.0.0.1">
<request_limit service="service1">7</request_limit>
<request_limit service="service2">8</request_limit>
</host>
</mapOfmap>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>