JAXB:XmlSeeAlso的StackOverFlowError

时间:2019-07-08 10:44:03

标签: java xml inheritance jaxb

我正在使用JAXB序列化一些对象结构。我有时确实有多个继承级别。那是我偶然发现一个问题的地方。

让我们考虑我要序列化Memory的属性。 Memory包含一个AbstractClass的集合,在其中我确实添加了AbstractClass的所有实现。它们是AbstractSubClass1AbstractSubClass2作为抽象类,而SubClass1SubClass2是实际实现。至此,这些信息对我来说已经足够了。

为了规避诸如JAXBException: Neither class SubClass1 nor one of the associated superclasses is known in this context.之类的错误,我可以添加

@XmlSeeAlso({
        SubClass1.class
       ,SubClass2.class
})
public static class Memory {
    ...
}

MemoryAbstractClass。但是,由于我的对象模型很大,所以我不想将Memory中可能包含的所有类添加到XmlSeeAlso列表中。所以我想我可以向所有包含其实现列表的超类添加@XmlSeeAlso标记,所以

@XmlSeeAlso({
        AbstractSubClass1.class
       ,AbstractSubClass2.class
})
public static abstract class AbstractClass {
    ...
}

@XmlSeeAlso({
        SubClass1.class
})
public static abstract class AbstractSubClass1{
    ...
}

@XmlSeeAlso({
        SubClass2.class
})
public static abstract class AbstractSubClass2{
    ...
}

但是对于这种方法,我得到了StackOverFlowError

Exception in thread "main" java.lang.StackOverflowError
    at java.base/java.util.Arrays$ArrayItr.<init>(Arrays.java:4439)
    at java.base/java.util.Arrays$ArrayList.iterator(Arrays.java:4431)
    at java.base/java.util.AbstractList.hashCode(AbstractList.java:566)
    at java.base/java.util.Objects.hashCode(Objects.java:116)
    at java.base/jdk.internal.loader.AbstractClassLoaderValue$Sub.hashCode(AbstractClassLoaderValue.java:430)
    at java.base/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
    at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:194)
    at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:423)
    at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1004)
    at com.sun.xml.bind.v2.model.annotation.LocatableAnnotation.create(LocatableAnnotation.java:85)
    at com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader.getClassAnnotation(RuntimeInlineAnnotationReader.java:106)
    at com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader.getClassAnnotation(RuntimeInlineAnnotationReader.java:57)
    at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:287)
    at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:103)
    at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:84)
    at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:254)
    at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:103)
    at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:84)
    at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:227)
    at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:98)
    at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:84)
    ...

那是为什么?除了声明MemoryAbstractClass的实现之外,没有其他方法吗?不可能有级联列表吗?


MWE

import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;

public class MWE {

    public static void main(String args[]) throws JAXBException{

        SubClass1 item1 = new SubClass1();
        SubClass2 item2 = new SubClass2();

        item1.setName(item1.getClass().getSimpleName());
        item2.setName(item2.getClass().getSimpleName());

        Memory memory = new Memory();
        memory.addItem(item1);
        memory.addItem(item2);

        JAXBContext jaxbContext = JAXBContext.newInstance(Memory.class);
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        marshaller.marshal(memory, System.out);

    }

    @XmlRootElement
    public static class Memory {

        @XmlElementWrapper(name="items")
        @XmlElement(name="item")
        private ArrayList<AbstractClass> items = new ArrayList<>();

        public void addItem(AbstractClass v){this.items.add(v);}
        public ArrayList<AbstractClass> getItems(){return items;}

    }

    @XmlTransient
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlSeeAlso({
            AbstractSubClass1.class
           ,AbstractSubClass2.class
    })
    public static abstract class AbstractClass {

        @XmlAttribute
        @XmlID
        private String name;

        public void setName(String name) {this.name = name;}
        public String getName() {return name;}

    }

    @XmlTransient
    @XmlSeeAlso({
            SubClass1.class
    })
    public static abstract class AbstractSubClass1 extends AbstractClass {}

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class SubClass1 extends AbstractSubClass1 {

        private double value = 1.0;

        public void setValue(double value) {this.value = value;}
        public double getValue() {return value;}

    }

    @XmlTransient
    @XmlSeeAlso({
            SubClass2.class
    })
    public static abstract class AbstractSubClass2 extends AbstractClass {}

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class SubClass2 extends AbstractSubClass2 {

        private int value = 1;

        public void setValue(int value) {this.value = value;}
        public int getValue() {return value;}

    }
}

0 个答案:

没有答案