将JAXB反序列化子类实例为列表

3

假设我想使用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());

    }
}

这里的问题在于在Add中存储了非Evaluable对象到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;
...

这个问题将会被解决。

但我不想把这个表格传遍全世界。如果我想添加一些子类型,事情会变得很混乱。

所以我的问题是哪种注释适合我的情况?或者有没有系统可以输入到非编组解码器中?

我正在使用Glassfish的JAXB,但我无法选择要使用的实现。

1个回答

2

您可以使用@XmlElementRef来得到您所需的行为:

@XmlElementRef
private ArrayList<Evaluable> elems;

更新

它说Evaluable或其任何子类在此上下文中未知

啊哈,这是正确的,因为您已将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

Evaluable或其任何子类在此上下文中未知。 - Jason Hu
我添加它是因为我想在num中有text。我搜索了一下,在我的特定的JAXB实现中,允许这样做的唯一方法是使用XmlTransient,对吗? - Jason Hu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接