CodeOutline / JClass / CClass在CodeModel中的作用是什么?

时间:2012-02-12 09:26:26

标签: jaxb xjc sun-codemodel jcodemodel

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

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

我的解释是CClassCPropertyInfoCEnumConstant,...)是由XJC在XSD初稿解析时创建的。然后发生了一些魔法,并将此模型转换为JClassJFieldVarJEnumConstant,...),并在此转换过程中应用自定义。然后调用插件。 ClassOutline用作这两个模型之间的桥梁。总之看起来很复杂。

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

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

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

2 个答案:

答案 0 :(得分:18)

哦,哦,有人对XJC内部感兴趣。我可能会有所帮助,因为我可能开发了比其他任何人更多的JAXB插件(例如,参见JAXB2 Basics

好的,我们开始吧。在XJC中,模式编译器大致遵循

  • 解析架构
  • 创建架构模型(CClass,CPropertyInfo等)
  • 创建轮廓(ClassOutline,FieldOutline等)
  • 呈现代码模型(JClass,JDefinedClass,JMethod等)
  • 写入物理代码(ex.Java文件在磁盘上)

让我们从最后两个开始。

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

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

现在让我们来看看“模型”和“大纲”。 模型是解析传入模式的结果。它模拟传入模式的结构,主要是对应于复杂类型的“类”和对应于元素,属性和值的“属性”(例如,当你有一个简单内容的复杂类型时)。

应该将模型理解为接近XML和模式的逻辑建模构造。因此,它只描述了它们具有的类型和属性。我描述它的方式肯定要复杂得多,有各种例外和警告 - 从wilcard类型(xsd:any),替换组,枚举,内置类型等开始。

非常有趣的是,Model的兄弟是RuntimeTypeInfoSetImpl,JAXB在运行时使用它。所以它也是一种模型 - 然而,它不是从XML Schema中解析而是从类中的JAXB注释中解析出来的。这个概念是一样的。 Model和RuntimeTypeInfoSetImpl都实现了TypeInfoSet接口,这是一个超级构造。检查ClassInfoPropertyInfo等接口 - 它们是针对编译时(XJC中的CClassInfoCPropertyInfo)和运行时(RuntimeClassInfoImpl等)实现的。对于JAXB RI)。

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

这就是轮廓发挥作用的地方。您可以在架构模型和代码模型之间看到大纲。您可以将轮廓视为负责组织代码和从JDefinedClass生成CClassInfo es的代码模型元素的工厂。

所以你是对的,确实非常复杂。我不是Sun / Oracle员工,我没有设计它(我知道做过它的人,但非常尊重他)。 我可以猜出某些设计决策的几个原因,例如:

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

我同意这种设计非常复杂,但它有其原因。一个证明就是实际上可以构建用于XML到JavaScript映射的映射生成器 - 基本上在相同的模型上。我只需要替换代码生成,使模式分析完整无缺。 (请参阅Jsonix。)

好的,希望我能说明为什么XJC中的事情是这样的。祝你好运这些API,它们并非直截了当。随意检查现有的开源代码,有很多可用的例子。

PS。真的一直想写这个。 :)

答案 1 :(得分:2)

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

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

技巧是引用属性没有自己的自定义,自定义放在引用的元素属性中。

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是进行此类讨论的好地方。