[英]JAXB marshall/unmarshall objects defined by plugins
讓我們假設以下情況:
我有以下類型的對象的列表:
public class MyObject {
private String name
private SomeClass someField
private List<Fact> facts
}
字段name
和someField
只是為了表明該類具有一些常規成員。 您可以假設知道如何將這些類轉換為xml。
Fact
是一個接口,其中我不知道實現,但由插件提供。 可能需要插件來提供任意代碼,但是我想使其盡可能簡單。
我想將這些對象保存並加載到xml。 請注意,在加載xml時,並非所有實現都可能存在(xml可能是使用一組不同的插件編寫的)。 我希望能夠再次讀取xml而不丟失任何信息。 換句話說:我願意在該類中添加諸如List<Element>
或List<String>
之類的字段,並且在讀取xml時,應該將存在插件的所有部分都讀取到相應的Fact
,而將所有部分沒有插件的應該存儲在Element
或String
並且再次保存時,兩個列表都將被保存,並且可以由具有所有插件的程序讀取。
如何最好地使用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.