我正在使用JAXB
序列化一些对象结构。我有时确实有多个继承级别。那是我偶然发现一个问题的地方。
让我们考虑我要序列化Memory
的属性。 Memory
包含一个AbstractClass
的集合,在其中我确实添加了AbstractClass
的所有实现。它们是AbstractSubClass1
和AbstractSubClass2
作为抽象类,而SubClass1
和SubClass2
是实际实现。至此,这些信息对我来说已经足够了。
为了规避诸如JAXBException: Neither class SubClass1 nor one of the associated superclasses is known in this context.
之类的错误,我可以添加
@XmlSeeAlso({
SubClass1.class
,SubClass2.class
})
public static class Memory {
...
}
到Memory
或AbstractClass
。但是,由于我的对象模型很大,所以我不想将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)
...
那是为什么?除了声明Memory
和AbstractClass
的实现之外,没有其他方法吗?不可能有级联列表吗?
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;}
}
}