当前位置: 首页 > 知识库问答 >
问题:

JAXB marshall/unmarshall由插件定义的对象

云俊名
2023-03-14

让我们假设以下场景:

我有以下类型的对象列表:

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

字段namesomething Field只是为了表明该类有一些常规成员。您可以假设知道如何将这些类转换为xml。

Fact是一个接口,其中的实现我不知道,但由插件提供。插件可以被要求提供任意代码,但我想让它尽可能简单。

我想将这些对象保存并加载到xml中。请注意,在加载xml时,并不是所有的实现都存在(xml可能是用不同的插件集编写的)。我希望在再次保存时仍能读取xml,并且不会丢失任何信息。换句话说:我愿意添加一个字段,比如List

如何最好地使用JAXB实现这一点?

我能看到的一种方法是使用Map


共有1个答案

谭卜鹰
2023-03-14

不知道best,但一种接近您描述的方法是:

JAXB不使用接口;它所能做的最好是一个抽象类。意思是你需要使用列表

您的插件提供了扩展的基本类(SPI将是通常的方法)。您收集它们并(在验证后)使用它们来创建您的JAXBContext。(如果您想支持多个接口,可以通过不同的方法提供它们)。

在xml中,需要有这样一个类型标记:

下面是一个简单的例子:

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

 类似资料:
  • 插件类是用户编写的, 但是它需要继承自Yaf_Plugin_Abstract. 对于插件来说, 上一节提到的7个Hook, 它不需要全部关心, 它只需要在插件类中定义和上面事件同名的方法, 那么这个方法就会在该事件触发的时候被调用. 而插件方法, 可以接受俩个参数, Yaf_Request_Abstract实例和Yaf_Response_Abstract实例. 一个插件类例子如下: 例 7.1.

  • 本文向大家介绍jQuery定义插件的方法,包括了jQuery定义插件的方法的使用技巧和注意事项,需要的朋友参考一下 有些WEB开发者,会引用一个JQuery类库,然后在网页上写一写$("#"),$("."),写了几年就对别人说非常熟悉JQuery。我曾经也是这样的人,直到有一次公司里的技术交流,我才改变了自己对自己的看法。 扩展jquery的时候。最核心的方法是以下两种: $.extend(obj

  • 英文原文: http://emberjs.com/guides/routing/defining-your-routes/ 当启动你的应用时,路由器会负责展示模板,载入数据,以及设置应用状态等任务。 这些都是通过将当前的URL与你定义的路由进行匹配来实现的。 1 2 3 4 App.Router.map(function() { this.route("about", { path: "/a

  • 我使用了一个自定义插件,该插件使用PluginManager类以编程方式注册,以加载map中的值,并根据map的内容更改RollingFileAppender的文件名。 然后,我更改了配置,使用路由追加器,以便能够使用ThreadContext内容进一步更改文件名(基本上,我希望应用程序的每个线程都有一个日志文件)。 然而,自从我开始使用Routing appender以来,我的自定义插件不再产生

  • 下面的这些代码可以帮助您通过CSS文件和SCSS文件,创建和编译 CSS 和 JS 文件的source-maps。 安装依赖 为了运行编译和压缩任务,你必须安装 node 和 npm。 命令行 // (Optional) Install Gulp module globally npm install gulp -g // Install fullpage's build dependen

  • 注册路由规则 route目录下的任何路由定义文件都是有效的,默认的路由定义文件是route.php,但你完全可以更改文件名,或者添加多个路由定义文件(你可以进行模块定义区分,但最终都会一起加载)。 ├─route 路由定义目录 │ ├─route.php 路由定义 │ ├─api.php 路由定义 │ └─...