簡體   English   中英

插件定義的JAXB marshall / unmarshall對象

[英]JAXB marshall/unmarshall objects defined by plugins

讓我們假設以下情況:

我有以下類型的對象的列表:

public class MyObject {
   private String name
   private SomeClass someField
   private List<Fact> facts
}

字段namesomeField只是為了表明該類具有一些常規成員。 您可以假設知道如何將這些類轉換為xml。

Fact是一個接口,其中我不知道實現,但由插件提供。 可能需要插件來提供任意代碼,但是我想使其盡可能簡單。

我想將這些對象保存並加載到xml。 請注意,在加載xml時,並非所有實現都可能存在(xml可能是使用一組不同的插件編寫的)。 我希望能夠再次讀取xml而不丟失任何信息。 換句話說:我願意在該類中添加諸如List<Element>List<String>之類的字段,並且在讀取xml時,應該將存在插件的所有部分都讀取到相應的Fact ,而將所有部分沒有插件的應該存儲在ElementString並且再次保存時,兩個列表都將被保存,並且可以由具有所有插件的程序讀取。

如何最好地使用JAXB做到這一點?

我可以看到的一種方法是使用Map<Class, org.w3c.dom.Element>而不是List<Fact> ,后者可以由JaxB轉換為xml,然后讓任何插件提供從“其”元素轉換為“其”元素的自定義代碼使用org.w3c.dom API,但是使用該API有點麻煩,所以我想知道是否有更好的方法?

沒有best想法,但是一種接近您所描述的方法是:

JAXB不能與接口一起使用。 最好能做的就是抽象類。 這意味着您需要使用List<Object>List<AbstractFact> (但是您可以在getter,pluginresolver或afterUnmarshall()中實施一些限制)。

您的插件提供了擴展的基本類(SPI是常用的方法)。 您收集它們並(在驗證之后)使用它們創建您的JAXBContext (如果要支持多個接口,則可以通過不同的方法提供它們)。

在xml中,您需要具有以下類型標記: <fact xsi:type=\\"aFact\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\"> 如果使用jaxb創建xml,則會自動創建。 (這些類需要具有@XmlRootElement批注)。

這是一個簡化的示例:

interface Fact {

}
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
class R {

    @XmlElement(name = "fact")
    private List<Object> facts;


    @SuppressWarnings("unchecked")
    public List<Fact> getTest() {
        if (facts == null) {
            facts = new ArrayList<>();
        }
        return (List<Fact>) (Object) facts;
    }

    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
        // check if all facts implement same interface
        for(Object object:facts) {
            if (!(object instanceof Fact)) {
                throw new IllegalArgumentException("Unsupported type in facts list");
            }
        }
    }
}

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "aFact")
class AFact implements Fact {

    @XmlElement
    private String a;

    public AFact() {
    }

    public AFact(String a) {
        this.a = a;
    }

    public String getA() {
        return a;
    }

    @Override
    public String toString() {
        return "AFact [a=" + a + "]";
    }

}

public class Jax {
    public static void main(String[] args) throws JAXBException {

        String xml = "<r><fact xsi:type=\"aFact\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><a>ba</a></fact></r>";

        List<Class<?>> contextClasses = new ArrayList<>();
        contextClasses.add(R.class);
        contextClasses.addAll(getClassesFromPlugin());
        JAXBContext context = JAXBContext.newInstance(contextClasses.toArray(new Class<?>[0]));
        R entity = (R) context.createUnmarshaller().unmarshal(new StringReader(xml));

        System.out.println(entity.getTest());

        R r = new R();
        r.getTest().add(new AFact("ab"));

        context.createMarshaller().marshal(r, System.out);
    }

    private static List<Class<?>> getClassesFromPlugin() {
        List<Class<?>> asList = Arrays.asList(AFact.class);
        for(Class<?> cls:asList) {
            if (!Fact.class.isAssignableFrom(cls)) {
                throw new IllegalArgumentException("Unsupported class");
            }
        }
        return asList;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM