JAXB 和抽象类
我正在尝试使用 JAXB 来解组一些 XML,但我收到无法创建...的实例"异常.我明白为什么——它试图创建一个抽象类的实例.我想要的是让它成为特定实现类的实例.我的目标是对 setter 方法进行特定于类的检查.也许qux"是 BarImpl 的有效 baz 值,但 BarImpl2 想做其他事情.
I'm trying to use JAXB to unmarshall some XML, but I'm getting an "Unable to create an instance of..." exception. I understand why--it's trying to make an instance of an abstract class. What I want is to have it make an instance of a specific implementing class. My goal with this is to have class-specific checks on setter methods. Maybe "qux" is a valid baz value for BarImpl, but BarImpl2 wants to do something else.
我通过不注释 Foo 获得了部分方法,但如果我不注释 bar,事情就会变得很糟糕.
I got part of the way there by not annotating Foo, but if I unannotate bar, things get ugly.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
public class JAXBTest {
@Test
public void test() throws javax.xml.bind.JAXBException {
String xml =
"<foo>" +
" <bar>" +
" <baz>qux</baz>" +
" </bar>" +
"</foo>";
javax.xml.bind.JAXBContext context = javax.xml.bind.JAXBContext.newInstance(
FooImpl.class,
BarImpl.class
);
javax.xml.bind.Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.unmarshal(new java.io.StringReader(xml));
}
@XmlRootElement(name="foo")
public static abstract class Foo {
@XmlElement(name="bar")
Bar bar;
}
@XmlRootElement(name="bar")
public static abstract class Bar {
@XmlElement(name="baz")
String baz;
}
public static class FooImpl extends Foo { }
public static class BarImpl extends Bar { }
}
您可以执行以下操作:
- 使用
@XmlRootElement
而不是抽象类来注释 impl 类. - 用
@XmlTransient
标记抽象类(参见 http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html) - 在
bar
属性上使用@XmlElement(type=BarImpl.class)
来指定具体类型(请参阅 http://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html).
- Annotation the impl classes with
@XmlRootElement
instead of the abstract classes. - Mark the abstract classes with
@XmlTransient
(see http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html) - Use
@XmlElement(type=BarImpl.class)
on thebar
property to specify the concrete type (see http://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html).
JAXBTest
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.junit.Test;
public class JAXBTest {
@Test
public void test() throws javax.xml.bind.JAXBException {
String xml =
"<foo>" +
" <bar>" +
" <baz>qux</baz>" +
" </bar>" +
"</foo>";
javax.xml.bind.JAXBContext context = javax.xml.bind.JAXBContext.newInstance(
FooImpl.class,
BarImpl.class
);
javax.xml.bind.Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.unmarshal(new java.io.StringReader(xml));
}
@XmlTransient
public static abstract class Foo {
@XmlElements({
@XmlElement(name="bar",type=BarImpl.class),
@XmlElement(name="bar",type=BarImpl2.class),
})
Bar bar;
}
@XmlTransient
public static abstract class Bar {
@XmlElement(name="baz")
String baz;
}
@XmlRootElement(name="foo")
public static class FooImpl extends Foo { }
@XmlRootElement(name="bar")
public static class BarImpl extends Bar { }
public static class BarImpl2 extends Bar { }
}