2012-03-06 113 views
7

我想使用JAXB解组一些XML,但我得到“无法创建一个......的实例”异常。我明白为什么 - 它试图创建一个抽象类的实例。我想要的是让它创建一个特定的实现类的实例。我的目标是对setter方法进行类特定检查。也许“qux”对BarImpl来说是一个有效的baz值,但BarImpl2想要做其他事情。JAXB和抽象类

通过不注释Foo,我得到了部分途径,但如果我unannotate栏,事情变得丑陋。

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

回答

14

你可以做到以下几点:

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

的一件事它缺少的是,如果我做BarImpl2,巴(中富)已经被标记为BarImpl。 – 2012-03-06 17:29:49

+0

我已经更新了我的答案,使用'@ XmlElements'来处理这个用例。 – 2012-03-06 17:52:56

+0

它的工作!现在唯一的烦恼是BarImpl2的实现者需要更改Foo中的注释,但这只是一个烦恼。 – 2012-03-07 07:45:58