Jaxb XML 使用泛型和基 类 时名称空间不正确
Jaxb XML namespaces incorrect when using generics and base classes
我在两个命名空间中有四个 classes,一个包中的两个用作另一个包中两个的基础 classes,例如:
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo<T extends Bar> {
@XmlElement(name="Bar")
private List<T> bar;
}
和
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
// something
}
派生的 classes 看起来像:
@XmlType(name="Foo" namespace="urn:foo/Bar")
@XmlRootElement(name="Foo")
public class DerivedFoo extends Foo<DerivedBar> {
// something
}
和
@XmlType(name="Bar" namespace="urn:foo/Bar")
public class DerivedBar extends Bar {
// something
}
在包含基础 classes 的包中,没有 package-info.java
或任何包含命名空间信息的内容。包含派生的 classes 的包具有所有命名空间信息。
输出 XML 正确地(有点)命名空间 DerivedFoo
class 但将 DerivedBar
class 分配给未命名的命名空间,本质上:
<Response xmlns:ns2="urn:foo/Bar">
<ns2:Foo>
<Bar>
</Bar>
</ns2:Foo>
</Response>
我认为您要查找的是 @XmlElementRef
and @XmlRootElement
的组合。使用 @XmlElementRef
注释就像说 "here's a thing; go look at its @XmlRootElement
annotation to figure out how to serialize it."
以下设置似乎可以满足您的需求。基地 类:
package base;
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo<T extends Bar> {
@XmlElementRef
public List<T> bar;
}
package base;
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
// something
}
package base;
@XmlRootElement(name = "Request")
@XmlAccessorType(XmlAccessType.FIELD)
public class Request {
@XmlElementRef
public Foo<?> foo;
}
和子类:
package derived;
@XmlRootElement(name = "Foo", namespace = "urn:foo/Bar")
public class DerivedFoo extends Foo<DerivedBar> {
// something
}
package derived;
@XmlRootElement(name = "Bar", namespace = "urn:foo/Bar")
public class DerivedBar extends Bar {
// something
}
我的测试看起来不错:
@Test
public void tryIt() throws Exception {
JAXBContext context = JAXBContext.newInstance(Request.class, DerivedFoo.class, DerivedBar.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Request request = new Request();
DerivedFoo foo = new DerivedFoo();
request.foo = foo;
foo.bar = new ArrayList<DerivedBar>();
foo.bar.add(new DerivedBar());
marshaller.marshal(request, System.out);
}
输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Request xmlns:ns2="urn:foo/Bar">
<ns2:Foo>
<ns2:Bar/>
</ns2:Foo>
</Request>
奖金
由于 @XmlElementRef
在运行时动态查找 XML 绑定,如果您使用不同的命名空间声明 Bar
的另一个子类,它将 "just work"。 小心 不过,因为元素名称也是动态的,如果您派生的 类 不是全部,这可能会导致奇怪的结果使用相同的 name
属性:
<Request xmlns:ns2="urn:rock/roll" xmlns:ns3="urn:yummy">
<ns2:FooFighters>
<ns3:TikiBar/>
</ns2:FooFighters>
</Request>
嵌套类型可能不太在意,但我敢打赌谁在使用 Request
可能不会识别那些元素名称。
我在两个命名空间中有四个 classes,一个包中的两个用作另一个包中两个的基础 classes,例如:
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo<T extends Bar> {
@XmlElement(name="Bar")
private List<T> bar;
}
和
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
// something
}
派生的 classes 看起来像:
@XmlType(name="Foo" namespace="urn:foo/Bar")
@XmlRootElement(name="Foo")
public class DerivedFoo extends Foo<DerivedBar> {
// something
}
和
@XmlType(name="Bar" namespace="urn:foo/Bar")
public class DerivedBar extends Bar {
// something
}
在包含基础 classes 的包中,没有 package-info.java
或任何包含命名空间信息的内容。包含派生的 classes 的包具有所有命名空间信息。
输出 XML 正确地(有点)命名空间 DerivedFoo
class 但将 DerivedBar
class 分配给未命名的命名空间,本质上:
<Response xmlns:ns2="urn:foo/Bar">
<ns2:Foo>
<Bar>
</Bar>
</ns2:Foo>
</Response>
我认为您要查找的是 @XmlElementRef
and @XmlRootElement
的组合。使用 @XmlElementRef
注释就像说 "here's a thing; go look at its @XmlRootElement
annotation to figure out how to serialize it."
以下设置似乎可以满足您的需求。基地 类:
package base;
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo<T extends Bar> {
@XmlElementRef
public List<T> bar;
}
package base;
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
// something
}
package base;
@XmlRootElement(name = "Request")
@XmlAccessorType(XmlAccessType.FIELD)
public class Request {
@XmlElementRef
public Foo<?> foo;
}
和子类:
package derived;
@XmlRootElement(name = "Foo", namespace = "urn:foo/Bar")
public class DerivedFoo extends Foo<DerivedBar> {
// something
}
package derived;
@XmlRootElement(name = "Bar", namespace = "urn:foo/Bar")
public class DerivedBar extends Bar {
// something
}
我的测试看起来不错:
@Test
public void tryIt() throws Exception {
JAXBContext context = JAXBContext.newInstance(Request.class, DerivedFoo.class, DerivedBar.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Request request = new Request();
DerivedFoo foo = new DerivedFoo();
request.foo = foo;
foo.bar = new ArrayList<DerivedBar>();
foo.bar.add(new DerivedBar());
marshaller.marshal(request, System.out);
}
输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Request xmlns:ns2="urn:foo/Bar">
<ns2:Foo>
<ns2:Bar/>
</ns2:Foo>
</Request>
奖金
由于 @XmlElementRef
在运行时动态查找 XML 绑定,如果您使用不同的命名空间声明 Bar
的另一个子类,它将 "just work"。 小心 不过,因为元素名称也是动态的,如果您派生的 类 不是全部,这可能会导致奇怪的结果使用相同的 name
属性:
<Request xmlns:ns2="urn:rock/roll" xmlns:ns3="urn:yummy">
<ns2:FooFighters>
<ns3:TikiBar/>
</ns2:FooFighters>
</Request>
嵌套类型可能不太在意,但我敢打赌谁在使用 Request
可能不会识别那些元素名称。