JAXB: проблема десериализации класса B, который расширяет класс A - PullRequest
6 голосов
/ 16 декабря 2010

Пожалуйста, рассмотрите следующий пример:

Существует ClassA и ClassB , которые расширяют его. Теперь моя проблема заключается в том, что мне нужно удалить файл ClassB из xml-файла. Обратите внимание, что ClassA не может быть изменено, поскольку оно не находится под моим контролем.

В этом примере отмечено несколько проблем:

Основная проблема заключается в том, что ClassA не имеет конструктора по умолчанию без аргументов, который требуется JAXB без Adapter. Поэтому я реализовал MyAdapter , который отображает ClassB на простой класс ValB , который может обрабатываться JAXB без каких-либо проблем.

Основная проблема в том, как заставить JAXB использовать этот адаптер? Ни определение @ XmlJavaTypeAdapter на уровне класса, ни регистрация Адаптера для демаршаллера не делают этого.

Кто-нибудь знает, как заставить JAXB использовать MyAdapter , чтобы unmarshaller возвращал объект, который является экземпляром ClassA ?

public class JaxbTest {

    public static abstract class ClassA {
        public ClassA(String id) {
        }
    }

    @XmlRootElement
    @XmlJavaTypeAdapter(MyAdapter.class) // does not have an effect
    public static class ClassB extends ClassA {

        public String text;

        public ClassB() {
            super("");
        }
    }

    public static class ValB {
        public String text;
    }

    public static class MyAdapter extends XmlAdapter<ValB, ClassB> {

        @Override
        public ClassB unmarshal(ValB v) throws Exception {
            ClassB b = new ClassB();
            b.text = v.text;
            return b;
        }

        @Override
        public ValB marshal(ClassB v) throws Exception {
            ValB b = new ValB();
            b.text = v.text;
            return b;
        }

    }

    public static void main(String[] args) {
        try {
            JAXBContext context = JAXBContext.newInstance(ClassB.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            unmarshaller.setAdapter(new MyAdapter()); // does not have an effect
            ClassA a = (ClassA) unmarshaller.unmarshal(new File("test.xml"));
            // do somthing with a
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Кстати: не воспринимайте код слишком серьезно - это всего лишь пример, демонстрирующий проблему. Я знаю, что определения ClassA и ClassB не очень полезны.

1 Ответ

2 голосов
/ 16 декабря 2010

ОБНОВЛЕНИЕ

Мы решили эту проблему в следующем EclipseLink JAXB (MOXy) 2.2.0 выпуске (см. ошибка # 332742 ).В этом выпуске абстрактные классы не проверяются на наличие конструктора без аргументов.

Предварительные версии с этим исправлением можно получить здесь, начиная с 18 декабря:

Обходной путь

Для этого предназначена аннотация @XmlTransient.Если возможно, сделайте следующее:

@XmlTransient
public static abstract class ClassA {
    public ClassA(String id) {
    }
}

Если невозможно напрямую аннотировать ClassA, вы можете использовать расширение EclipseLink JAXB (MOXy) для этого.MOXy позволяет вам указывать метаданные JAXB в виде файла XML.Это полезно, когда вы не можете изменить класс модели:

Ниже приведены некоторые статьи, объясняющие @XmlAdapter:

...