Mam kilka złożonych struktur danych jakJAXB: Jak powinienem marnować złożone zagnieżdżone struktury danych?
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)
Uwaga: W moim przypadku nie ma znaczenia, czy mogę użyć Set lub List.
Teraz wiem, że JAXB pozwól mi określić XmlAdapter „s, to w porządku, ale nie chcę, aby zdefiniować XmlAdapter dla każdego z podanych struktur danych (to byłoby po prostu zbyt dużo kopiowaniem i wklej kod).
starałem się osiągnąć mój cel, ogłaszając dwa XmlAdapters uogólniając:
- jeden do mapy:
MapAdapter<K,V>
- jeden dla Zestaw:
SetAdapter<V>
problem:
JAXB narzeka jak następuje:
javax.xml.bind.JAXBException:
class java.util.Collections$UnmodifiableMap nor any of its
super class is known to this context.
Oto moja klasa adaptera:
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");
}
}
}
Oto mój przypadek testy 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());
}
}
Super! Być może kiedyś będę musiał to zrobić - czy możesz również opublikować podsumowanie tego, co musisz zrobić w pliku powiązań .xjb? –
Nigdy nie użyłem pliku powiązań .xjb;) Proponowane rozwiązanie po prostu działa;) –
Musiałem dodać '@XmlSeeAlso ({Adapters.XMap.class, Adapters.XCollection.class, Adapters.XEntry.class}) 'na mojej klasie adnotacji JAXB, aby to zadziałało. – ajitomatix