8

我的问题涉及编写 JAXB 插件,特别是 JAXB 代码模型。

ClassOutline(和它的同伴)和JClass(和同伴)和CClass(和同伴)的作用是什么?查看相应包中的类列表时,不清楚什么是鸡什么是鸡蛋。

我的解释是CClass( CPropertyInfo, CEnumConstant, ...) 是 XJC 在 XSD 的初稿解析时创建的。然后发生了一些神奇的事情,这个模型被转换为JClass( JFieldVar, JEnumConstant, ...) 并且在这个转换过程中应用了自定义。之后调用插件。ClassOutline被用作这两个模型之间的桥梁。整体看起来非常复杂。

通过这些并行模型,我相信可以通过多种方式得出相同的信息。例如类字段类型:

  • JClass#fields()JFieldVar#typeJType
  • CClassInfo#getProperties()CPropertyInfo#baseTypeJType

我正在寻找上述模型生命周期的详细解释。谢谢。

4

2 回答 2

20

哦,哦,有人对XJC内部感兴趣。我可能会有所帮助,因为我可能开发的 JAXB 插件比其他任何人都多(例如,请参阅JAXB2 基础知识

好的,让我们开始吧。在 XJC 中,模式编译器大约执行以下操作

  • 解析架构
  • 创建模式的模型(CClass、CPropertyInfo 等)
  • 创建大纲(ClassOutline、FieldOutline 等)
  • 呈现代码模型(JClass、JDefinedClass、JMethod 等)
  • 写入物理代码(例如磁盘上的 Java 文件)

让我们从最后两个开始。

我希望 Java 文件不需要解释。

代码模型也是一件相对容易的事情。它是一种 API,可用于以编程方式构造 Java 代码。您可以只使用字符串连接,但它更容易出错。使用 CodeModel,您几乎可以保证获得至少语法正确的 Java 代码。所以我希望这部分也很清楚。(顺便说一句,我非常喜欢 CodeModel。最近根据 CodeModel 的想法编写了JavaScript Code Model 。)

现在让我们看看“模型”和“轮廓”。模型是解析传入模式的结果。它对传入模式的构造进行建模,主要根据对应于复杂类型的“类”和对应于元素、属性和值的“属性”(例如,当您拥有具有简单内容的复杂类型时)。

该模型应该被理解为接近 XML 和模式的逻辑建模结构。因此,它只描述了它们拥有的类型和属性。它肯定比我描述它的方式复杂得多,有各种各样的例外和警告——从通配符类型(xsd:any)、替换组、枚举、内置类型等等开始。

非常有趣的是,在运行时 JAXB 使用了Modelis的兄弟。RuntimeTypeInfoSetImpl所以它也是一种模型——然而它不是从 XML Schema 中解析出来的,而是从类中的 JAXB 注释中解析出来的。概念是一样的。模型和RuntimeTypeInfoSetImpl实现TypeInfoSet都是超结构的接口。检查像ClassInfo和这样的接口PropertyInfo——它们在编译时(CClassInfo以及CPropertyInfo在 XJC 中)和运行时(RuntimeClassInfoImpl对于 JAXB RI 等)都有实现。

好的,所以当 XJC 解析和分析模式时,你得到了Model. 这Model还不能生成代码。事实上,产生代码的策略不同。您可以只生成带注释的类,也可以像在 JAXB 1 中那样生成接口/实现类对。整个代码生成实际上并不是模型的任务。此外,还有许多方面与 Java 代码的物理性质相关,但与模型并不真正相关。例如,您必须将类分组到包中。这是由 Java 的打包系统驱动的,而不是由模型本身的属性驱动的。

这就是大纲发挥作用的地方。您可以将大纲视为模式模型和代码模型之间的步骤。您可以将大纲视为负责组织代码和从s生成JDefinedClasses的代码模型元素的工厂。CClassInfo

所以你是对的,它确实非常复杂。我不是 Sun/Oracle 的员工,不是我设计的(不过我认识做这件事的人,并且非常尊重他)。我可以猜测某些设计决策的几个原因,例如:

  • 对编译时和运行时模型使用相同的接口
  • 允许不同的代码生成策略
  • 允许插件操作创建的模型

我同意这个设计非常复杂,但它有它的原因。一个证明是,实际上可以为 XML 到 JavaScript 的映射构建一个映射生成器——基本上在相同的模型上。我只需要替换代码生成,保持模式分析不变。(请参阅Jsonix。)

好的,希望我能阐明为什么 XJC 中的事情是这样的。祝这些 API 好运,它们并不简单。随意检查现有的开源代码,有很多可用的示例。

附言。真的一直想写这个。:)

于 2012-02-22T22:40:52.110 回答
2

(这是为了回答您的进一步问题。)

是的,可以检查自定义。这是我用来访问自定义的类。

诀窍是引用属性没有自己的自定义,自定义放置在引用的元素属性中。

public static CCustomizations getCustomizations(
        final CPropertyInfo propertyInfo) {

    final CCustomizations main = new CCustomizations(
            propertyInfo.getCustomizations());

    final Collection<CCustomizations> elementCustomizations = propertyInfo
            .accept(new CPropertyVisitor<Collection<CCustomizations>>() {
                public Collection<CCustomizations> onAttribute(
                        CAttributePropertyInfo info) {
                    return Collections.emptyList();
                }

                public Collection<CCustomizations> onElement(
                        CElementPropertyInfo arg0) {
                    return Collections.emptyList();
                }

                public Collection<CCustomizations> onReference(
                        CReferencePropertyInfo info) {

                    final List<CCustomizations> elementCustomizations = new ArrayList<CCustomizations>(
                            info.getElements().size());

                    for (CElement element : info.getElements()) {
                        if (!(element instanceof CElementInfo && ((CElementInfo) element)
                                .hasClass())) {
                            elementCustomizations.add(element
                                    .getCustomizations());
                        }
                    }

                    return elementCustomizations;
                }

                public Collection<CCustomizations> onValue(
                        CValuePropertyInfo arg0) {
                    return Collections.emptyList();
                };

            });

    CCustomizations customizations = main;

    for (CCustomizations e : elementCustomizations) {
        main.addAll(e);
    }

    return customizations;
}

我想说 users@jaxb.java.net 是进行此类讨论的好地方。

于 2012-03-27T23:31:21.977 回答