2012-03-06 15 views
7

Próbuję użyć JAXB do rozpakowania kodu XML, ale otrzymuję wyjątek "Nie można utworzyć wystąpienia ...". Rozumiem, dlaczego - próbuje stworzyć instancję klasy abstrakcyjnej. To, czego chcę, to sprawić, że będzie to instancja konkretnej klasy implementującej. Moim celem jest posiadanie specyficznych dla klasy sprawdzeń metod setera. Może "qux" jest poprawną wartością bazową dla BarImpl, ale BarImpl2 chce zrobić coś innego.JAXB i klasy abstrakcyjne

Dostałem część drogi, nie opisując Foo, ale jeśli anuluję pasek, rzeczy stają się brzydkie.

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

import org.junit.Test; 


public class JAXBTest { 

    @Test 
    public void test() throws javax.xml.bind.JAXBException { 
     String xml = 
      "<foo>" + 
      " <bar>" + 
      " <baz>qux</baz>" + 
      " </bar>" + 
      "</foo>"; 

     javax.xml.bind.JAXBContext context = javax.xml.bind.JAXBContext.newInstance(
       FooImpl.class, 
       BarImpl.class 
     ); 

     javax.xml.bind.Unmarshaller unmarshaller = context.createUnmarshaller(); 

     unmarshaller.unmarshal(new java.io.StringReader(xml)); 
    } 

    @XmlRootElement(name="foo") 
    public static abstract class Foo { 
     @XmlElement(name="bar") 
     Bar bar; 
    } 

    @XmlRootElement(name="bar") 
    public static abstract class Bar { 
     @XmlElement(name="baz") 
     String baz; 
    } 

    public static class FooImpl extends Foo { } 
    public static class BarImpl extends Bar { } 
} 

Odpowiedz

14

Można wykonać następujące czynności:

JAXBTest

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlElements; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlTransient; 

import org.junit.Test; 


public class JAXBTest { 

    @Test 
    public void test() throws javax.xml.bind.JAXBException { 
     String xml = 
      "<foo>" + 
      " <bar>" + 
      " <baz>qux</baz>" + 
      " </bar>" + 
      "</foo>"; 

     javax.xml.bind.JAXBContext context = javax.xml.bind.JAXBContext.newInstance(
       FooImpl.class, 
       BarImpl.class 
     ); 

     javax.xml.bind.Unmarshaller unmarshaller = context.createUnmarshaller(); 

     unmarshaller.unmarshal(new java.io.StringReader(xml)); 
    } 

    @XmlTransient 
    public static abstract class Foo { 
     @XmlElements({ 
      @XmlElement(name="bar",type=BarImpl.class), 
      @XmlElement(name="bar",type=BarImpl2.class), 
     }) 
     Bar bar; 
    } 

    @XmlTransient 
    public static abstract class Bar { 
     @XmlElement(name="baz") 
     String baz; 
    } 

    @XmlRootElement(name="foo") 
    public static class FooImpl extends Foo { } 

    @XmlRootElement(name="bar") 
    public static class BarImpl extends Bar { } 

    public static class BarImpl2 extends Bar { } 
} 
+0

Jedna rzecz to brak jest, że jeśli zrobię BarImpl2, bar (w Foo) został już oznaczony jako BarImpl. –

+0

Zaktualizowałem swoją odpowiedź, aby użyć '@ XmlElements' do obsługi tego przypadku użycia. –

+0

To zadziałało! Jedyną irytacją jest to, że implementator BarImpl2 musi zmienić adnotacje w Foo, ale to tylko irytacja. –

Powiązane problemy