Java moxy-jaxb中的XmlAdapter和XmlIDREF
我正在尝试使用MOXy JAXB序列化一个类a,它看起来像:Java moxy-jaxb中的XmlAdapter和XmlIDREF,java,xml,jaxb,adapter,moxy,Java,Xml,Jaxb,Adapter,Moxy,我正在尝试使用MOXy JAXB序列化一个类a,它看起来像: @XmlAccessorType(XmlAccessType.NONE) @XmlRootElement public class A { private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>(); private Set<Foo> foos = new HashSet<Foo>(); @XmlJavaType
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class A {
private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>();
private Set<Foo> foos = new HashSet<Foo>();
@XmlJavaTypeAdapter(FooBarMapAdapter.class)
public Map<Foo, Bar> getFooBar() {
return fooBar;
}
public void setFooBar(Map<Foo, Bar> fooBar) {
this.fooBar = fooBar;
}
@XmlElement
public Set<Foo> getFoos() {
return foos;
}
public void setFoos(Set<Foo> foos) {
this.foos = foos;
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class A {
private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>();
private Set<Foo> foos = new HashSet<Foo>();
// Due to a bug a XMLAdapter approch is not possible when using XmlIDREF.
// The map is mapped by the wrapper method getXmlableFooBarMap.
// @XmlJavaTypeAdapter(FooBarMapAdapter.class)
public Map<Foo, Bar> getFooBar() {
return fooBar;
}
public void setFooBar(Map<Foo, Bar> fooBar) {
this.fooBar = fooBar;
}
@XmlElement
public Set<Foo> getFoos() {
return foos;
}
public void setFoos(Set<Foo> foos) {
this.foos = foos;
}
// // WORKAROUND FOR JAXB BUG /////
private List<FooBarMapEntry> mapEntries;
@XmlElement(name = "entry")
public List<FooBarMapEntry> getXmlableFooBarMap() {
this.mapEntries = new LinkedList<FooBarMapEntry>();
if (getFooBar() == null)
return mapEntries;
for (Map.Entry<Foo, Bar> e : getFooBar().entrySet()) {
FooBarMapEntry entry = new FooBarMapEntry();
entry.setFoo(e.getKey());
entry.setBar(e.getValue());
mapEntries.add(entry);
}
return mapEntries;
}
public void setXmlableFooBarMap(List<FooBarMapEntry> entries) {
this.mapEntries = entries;
}
public void transferFromListToMap() {
fooBar = new HashMap<Foo, Bar>();
for (FooBarMapEntry entry : mapEntries) {
fooBar.put(entry.getFoo(), entry.getBar());
}
}
}
然后,在我的XmlAdapter中,我尝试在已调整的映射条目的foo对象上使用XmlIDREF注释:
public class FooBarMapAdapter extends
XmlAdapter<FooBarMapAdapter.FooBarMapType, Map<Foo, Bar>> {
public static class FooBarMapType {
public List<FooBarMapEntry> entries = new ArrayList<FooBarMapEntry>();
}
@XmlAccessorType(XmlAccessType.NONE)
public static class FooBarMapEntry {
private Foo foo;
private Bar bar;
@XmlIDREF
@XmlAttribute
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
@XmlElement
public Bar getBar() {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
@Override
public FooBarMapType marshal(Map<Foo, Bar> map) throws Exception {
FooBarMapType fbmt = new FooBarMapType();
for (Map.Entry<Foo, Bar> e : map.entrySet()) {
FooBarMapEntry entry = new FooBarMapEntry();
entry.setFoo(e.getKey());
entry.setBar(e.getValue());
fbmt.entries.add(entry);
}
return fbmt;
}
@Override
public Map<Foo, Bar> unmarshal(FooBarMapType fbmt) throws Exception {
Map<Foo, Bar> map = new HashMap<Foo, Bar>();
for (FooBarMapEntry entry : fbmt.entries) {
map.put(entry.getFoo(), entry.getBar());
}
return map;
}
}
也就是说,映射中用作键的Foo对象为null。如果我更改映射适配器并封送Foo对象两次,而不是使用ID引用,则不会得到这个空指针
我已经使用JAXB-RI在google上找到了一些关于这方面的帖子,在这里,问题可以通过编写IDResolver来解决,如中所述。不幸的是,我在MOXy JAXB JavaDoc中找不到关于此类的任何信息
解决方案建议
从Blaise Doughan的回答中,我意识到这是JAXB的MOXy实现中的一个bug。我已经能够为这个bug做一个(丑陋的)解决方法。其思想是,不使用XMLAdapter,而是在其定义类中“转换”映射。A级现在看起来像:
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class A {
private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>();
private Set<Foo> foos = new HashSet<Foo>();
@XmlJavaTypeAdapter(FooBarMapAdapter.class)
public Map<Foo, Bar> getFooBar() {
return fooBar;
}
public void setFooBar(Map<Foo, Bar> fooBar) {
this.fooBar = fooBar;
}
@XmlElement
public Set<Foo> getFoos() {
return foos;
}
public void setFoos(Set<Foo> foos) {
this.foos = foos;
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class A {
private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>();
private Set<Foo> foos = new HashSet<Foo>();
// Due to a bug a XMLAdapter approch is not possible when using XmlIDREF.
// The map is mapped by the wrapper method getXmlableFooBarMap.
// @XmlJavaTypeAdapter(FooBarMapAdapter.class)
public Map<Foo, Bar> getFooBar() {
return fooBar;
}
public void setFooBar(Map<Foo, Bar> fooBar) {
this.fooBar = fooBar;
}
@XmlElement
public Set<Foo> getFoos() {
return foos;
}
public void setFoos(Set<Foo> foos) {
this.foos = foos;
}
// // WORKAROUND FOR JAXB BUG /////
private List<FooBarMapEntry> mapEntries;
@XmlElement(name = "entry")
public List<FooBarMapEntry> getXmlableFooBarMap() {
this.mapEntries = new LinkedList<FooBarMapEntry>();
if (getFooBar() == null)
return mapEntries;
for (Map.Entry<Foo, Bar> e : getFooBar().entrySet()) {
FooBarMapEntry entry = new FooBarMapEntry();
entry.setFoo(e.getKey());
entry.setBar(e.getValue());
mapEntries.add(entry);
}
return mapEntries;
}
public void setXmlableFooBarMap(List<FooBarMapEntry> entries) {
this.mapEntries = entries;
}
public void transferFromListToMap() {
fooBar = new HashMap<Foo, Bar>();
for (FooBarMapEntry entry : mapEntries) {
fooBar.put(entry.getFoo(), entry.getBar());
}
}
}
任何关于更好的解决方法/错误修复的建议都将不胜感激:)。注意:我是负责人 我已经能够确认您看到的问题:
@XmlIDREF
逻辑之前处理了XmlAdapter
逻辑。MOXy只传递一次XML文档,并在最后处理@XmlIDREF
关系,以确保已构建所有引用对象(因为引用可能位于引用对象之前,如本例所示)
我将尝试发布此问题的解决方法,您可以使用上述错误跟踪我们在该问题上的进展。我还遇到一个问题,可能与此相关,将\@XmlIDREF方法封送到其类上有\@XmlJavaTypeAdapter注释的对象。这里对整个对象进行封送处理,而不是只指定对象的ID。谢谢您的回答。我在问题中添加了一个解决方法的建议。我也遇到了这个错误。将来会有什么进展吗?或者有没有其他方法可以解决这个问题。同样,在封送包含@XmlIDREF注释的字段时,将忽略传递给封送器的已配置的XmlAdapter实例。它与Sun实现完美配合。
{null=test.moxy.Bar@373c0b53}
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class A {
private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>();
private Set<Foo> foos = new HashSet<Foo>();
// Due to a bug a XMLAdapter approch is not possible when using XmlIDREF.
// The map is mapped by the wrapper method getXmlableFooBarMap.
// @XmlJavaTypeAdapter(FooBarMapAdapter.class)
public Map<Foo, Bar> getFooBar() {
return fooBar;
}
public void setFooBar(Map<Foo, Bar> fooBar) {
this.fooBar = fooBar;
}
@XmlElement
public Set<Foo> getFoos() {
return foos;
}
public void setFoos(Set<Foo> foos) {
this.foos = foos;
}
// // WORKAROUND FOR JAXB BUG /////
private List<FooBarMapEntry> mapEntries;
@XmlElement(name = "entry")
public List<FooBarMapEntry> getXmlableFooBarMap() {
this.mapEntries = new LinkedList<FooBarMapEntry>();
if (getFooBar() == null)
return mapEntries;
for (Map.Entry<Foo, Bar> e : getFooBar().entrySet()) {
FooBarMapEntry entry = new FooBarMapEntry();
entry.setFoo(e.getKey());
entry.setBar(e.getValue());
mapEntries.add(entry);
}
return mapEntries;
}
public void setXmlableFooBarMap(List<FooBarMapEntry> entries) {
this.mapEntries = entries;
}
public void transferFromListToMap() {
fooBar = new HashMap<Foo, Bar>();
for (FooBarMapEntry entry : mapEntries) {
fooBar.put(entry.getFoo(), entry.getBar());
}
}
}
newA.transferFromListToMap();