JAXB 将子类的实例解组到列表中
JAXB unmarshal instances of subclasses into List
假设我想用 xml 表示算术表达式,所以我有:
@XmlRootElement
@XmlTransient
@XmlSeeAlso({Num.class, Add.class})
public abstract class Evaluable
{
public abstract int eval();
}
@XmlRootElement
@XmlType(name = "num")
public class Num extends Evaluable
{
@XmlValue
private int val;
@Override
public int eval()
{
return val;
}
}
@XmlRootElement
@XmlType
public class Add extends Evaluable
{
@XmlAnyElement
private ArrayList<Evaluable> elems;
@Override
public int eval()
{
int sum = 0;
for (Evaluable elem : elems)
{
sum += elem.eval();
}
return sum;
}
}
和我的测试用例:
public class RecursiveUnmarshalTest
{
@Test
public void testAdd() throws Exception
{
String xml = "<add><num>10</num><num>20</num></add>";
assertEquals(30,
((Evaluable) JAXBContext.newInstance(Evaluable.class).createUnmarshaller().unmarshal(new StringReader(
xml))).eval());
}
}
这里的问题是非Evaluable
存储在Add
中的ArrayList
中,原因是类型擦除,JAXB不知道元素是哪种类型应该反映到,所以在 Add
.
的 eval 中会有一个转换错误
我通过以下方式进行了测试:
public class Add extends Evaluable
{
@XmlElements({
@XmlElement(name = "num", type = Num.class),
@XmlElement(name = "add", type = Add.class)
})
private ArrayList<Evaluable> elems;
...
这将得到解决。
但我不想将此 table 传播到全世界。如果我想附加一些子类型,事情就会变得一团糟。
所以我的问题是哪个注释适合我的情况table?或任何输入解组器的系统?
我正在使用 glassfish 的 JAXB,但我无法选择要使用的实现。
您可以使用 @XmlElementRef
来获得您正在寻找的行为:
@XmlElementRef
private ArrayList<Evaluable> elems;
更新
it says Evaluable or any of its subclasses are not known to this
context
啊,没错,因为您已将 Evaluable
标记为 @XmlTransient
,JAXB 忽略它并且不认为它存在。您可能添加了它,因为当您没有它时,您会遇到以下异常。
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Invalid @XmlElementRef : Type "class forum27826242.Evaluable" or any of its subclasses are not known to this context.
this problem is related to the following location:
at private java.util.ArrayList forum27826242.Add.elems
at forum27826242.Add
at @javax.xml.bind.annotation.XmlSeeAlso(value=[class forum27826242.Num, class forum27826242.Add])
at forum27826242.Num
假设我想用 xml 表示算术表达式,所以我有:
@XmlRootElement
@XmlTransient
@XmlSeeAlso({Num.class, Add.class})
public abstract class Evaluable
{
public abstract int eval();
}
@XmlRootElement
@XmlType(name = "num")
public class Num extends Evaluable
{
@XmlValue
private int val;
@Override
public int eval()
{
return val;
}
}
@XmlRootElement
@XmlType
public class Add extends Evaluable
{
@XmlAnyElement
private ArrayList<Evaluable> elems;
@Override
public int eval()
{
int sum = 0;
for (Evaluable elem : elems)
{
sum += elem.eval();
}
return sum;
}
}
和我的测试用例:
public class RecursiveUnmarshalTest
{
@Test
public void testAdd() throws Exception
{
String xml = "<add><num>10</num><num>20</num></add>";
assertEquals(30,
((Evaluable) JAXBContext.newInstance(Evaluable.class).createUnmarshaller().unmarshal(new StringReader(
xml))).eval());
}
}
这里的问题是非Evaluable
存储在Add
中的ArrayList
中,原因是类型擦除,JAXB不知道元素是哪种类型应该反映到,所以在 Add
.
我通过以下方式进行了测试:
public class Add extends Evaluable
{
@XmlElements({
@XmlElement(name = "num", type = Num.class),
@XmlElement(name = "add", type = Add.class)
})
private ArrayList<Evaluable> elems;
...
这将得到解决。
但我不想将此 table 传播到全世界。如果我想附加一些子类型,事情就会变得一团糟。
所以我的问题是哪个注释适合我的情况table?或任何输入解组器的系统?
我正在使用 glassfish 的 JAXB,但我无法选择要使用的实现。
您可以使用 @XmlElementRef
来获得您正在寻找的行为:
@XmlElementRef
private ArrayList<Evaluable> elems;
更新
it says Evaluable or any of its subclasses are not known to this context
啊,没错,因为您已将 Evaluable
标记为 @XmlTransient
,JAXB 忽略它并且不认为它存在。您可能添加了它,因为当您没有它时,您会遇到以下异常。
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Invalid @XmlElementRef : Type "class forum27826242.Evaluable" or any of its subclasses are not known to this context.
this problem is related to the following location:
at private java.util.ArrayList forum27826242.Add.elems
at forum27826242.Add
at @javax.xml.bind.annotation.XmlSeeAlso(value=[class forum27826242.Num, class forum27826242.Add])
at forum27826242.Num