gpt4 book ai didi

java - JAXB:我应该如何整理复杂的嵌套数据结构?

转载 作者:行者123 更新时间:2023-12-02 00:02:29 28 4
gpt4 key购买 nike

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

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(这会导致太多的复制粘贴代码)。

我试图通过声明两个通用 XmlAdapter 来实现我的目标:

  • map :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's

我为 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 属性?

关于java - JAXB:我应该如何整理复杂的嵌套数据结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58171947/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com