2010-12-16 3 views
6

Пожалуйста, рассмотрим следующий пример:JAXB: Проблема десериализации класса B, который расширяет класс A

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

Некоторые проблемы отмечаются в этом примере:

Основная проблема заключается в том, что ClassA не не имеет по умолчанию конструктор без аргументов, которая требуется JAXB без адаптера. Поэтому я внедрил 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(); 
     } 
    } 
} 

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

+0

Мы рассмотрели этот вопрос в он готов к выпуску EclipseLink JAXB (MOXy). В этом выпуске никаких изменений кода в вашем примере не требуется: http://stackoverflow.com/questions/4459737/jaxb-problem-deserializing-a-class-b-that-extends-a-class-a/4459779#4459779 – 2010-12-17 15:54:32

ответ

2

UPDATE

Мы решили эту проблему в предстоящем EclipseLink JAXB (MOXy) 2.2.0 выпуске (см bug #332742). В этом выпуске абстрактные классы не будут проверяться для конструктора no-arg.

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

Обход

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

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

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

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

+0

Обе статьи разные, потому что неизменяемый объект является полем инкапсулирующего класса, что в моем примере не так. – Robert 2010-12-16 12:04:09

 Смежные вопросы

  • Нет связанных вопросов^_^