当前位置: 首页 > 面试题库 >

JAXB:我应该如何封送复杂的嵌套数据结构?

东郭臻
2023-03-14
问题内容

我有几种复杂的数据结构,例如

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)

注意:就我而言,使用Set或List并不重要。

现在我知道JAXB让我定义了 XmlAdapter
,这很好,但是我不想为每个给定的数据结构都定义一个XmlAdapter(这将是太多的复制和粘贴代码)。

我试图通过声明两个泛化的XmlAdapters来实现我的目标:

  • 一个用于地图: MapAdapter<K,V>
  • 一套 SetAdapter<V>

问题
JAXB抱怨如下:

javax.xml.bind.JAXBException:
class java.util.Collections$UnmodifiableMap nor any of its
  super class is known to this context.

这是我的适配器类:

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");
    }

}

}

这是我的JUnit测试用例:

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());
}

}

问题答案:

我已经解决了 没有XmlAdapter的 问题。

我已经为 MapMap.EntryCollection 编写了带有JAXB注释的对象。
主要思想是在 xmlizeNestedStructure(…) 方法内部:

看一下代码:

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);
    }

}

}

有用!

让我们看一个 演示输出

<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>

抱歉,演示输出还使用了称为 “ count” 的数据结构,该数据结构 在适配器的源代码中未提及。

顺便说一句: 有谁知道如何删除所有这些烦人的(对于我而言)不必要的 xsi:type 属性?



 类似资料:
  • 我有一个这样的数组: 中的数组包括另外两个数组(第一个不是必需的,但看看第二个(:这个数组包含不同的 x/y 坐标 ) 我想得到另一个数组的结果,如下所示(解释如下): 数组现在按其 x 值排序 ( -- 我不知道如何编码;这是我到目前为止所拥有的: 编辑:有一点忘记说了,就是应该分组的坐标的不应该大于。看下面的例子:

  • 问题内容: 有没有一种方法可以指定JAXB在XML模式中用于编组/解编对象的适配器? 例如,如果我想将以下内容解析为整数: 我可以在架构中使用以下内容: 当我通过XJC工具运行模式时,应使用Integer.decode()作为值为0x1234的Integer或十进制4660来解码字符串“ 0x1234”。生成的Adapter类正确反映了这一点: 但是,当我想将值编组回XML元素(这是String文

  • 我试图根据第二个嵌套数组中的值的数量将嵌套数组转换为对象。我似乎无法获取值字段的数量并将其用作规范中的键。现在这是我的输入JSON文件: 这是我想要的JSON输出: 这是我目前的规格 有人有类似的情况吗?

  • 如有任何线索将不胜感激。谢谢,约翰 XML是巨大的,但这里有一个片段,序列中的媒体是空的,而它不应该是空的。

  • 问题内容: 可以说我有一个散列,例如 存储这种数据结构的“通常”方式是什么(或者您不会吗?) 您是否可以直接获得价值(例如,获取哈利:年龄? 一旦存储,您是否可以直接更改子键的值(例如,sally:weight = 100) 问题答案: 存储这种数据结构的“通常”方式是什么(或者您不会吗?) 例如,哈利(Harry)和莎莉(Sally)将分别存储在单独的散列中,其中字段代表其属性,例如年龄和体重。

  • 问题内容: 我如何指示JAXB处理此问题? XML格式 根java 这不起作用… allChildren为空。 问题答案: 您可以更改模型并执行以下操作: 根 父母 更新 有可能避免上课吗? 有两种不同的方法可以完成此操作: 选项#1-使用XmlAdapter的任何JAXB实现 您可以使用XmlAdapter虚拟添加类。 子适配器 根 该注释被用于引用。 儿童 选项#2-使用EclipseLink