JAXB: StackOverFlowError для XmlSeeAlso - PullRequest
1 голос
/ 08 июля 2019

Я работаю над сериализацией части моей структуры объектов с 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?Не возможно ли иметь каскадный список?


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;}

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...