【问题标题】:JAXB, XJC: Generating field to Class OutlineJAXB、XJC:为类大纲生成字段
【发布时间】:2018-01-17 14:34:23
【问题描述】:

我的问题是关于编写 JAXB 插件,尤其是 ClassOutline internals。

com.sun.tools.xjc.outline.ClassOutline中有字段:

  • 目标
  • 参考
  • implClass
  • implRef

代码:

/**
 * This {@link ClassOutline} holds information about this {@link CClassInfo}.
 */
public final @NotNull CClassInfo target;

/**
 * The exposed aspect of the a bean.
 *
 * implClass is always assignable to this type.
 * <p>
 * Usually this is the public content interface, but
 * it could be the same as the implClass.
 */
public final @NotNull JDefinedClass ref;

/**
 * The implementation aspect of a bean.
 * The actual place where fields/methods should be generated into.
 */
public final @NotNull JDefinedClass implClass;

/**
 * The implementation class that shall be used for reference.
 * <p>
 * Usually this field holds the same value as the {@link #implClass} method,
 * but sometimes it holds the user-specified implementation class
 * when it is specified.
 * <p>
 * This is the type that needs to be used for generating fields.
 */
public final @NotNull JClass implRef;

据我所知 (SO Answer):

  • target - 在Model 中保存信息,表示已解析和分析的架构文件 (.xsd)
  • ref 通常等于 implClass 并且两者都持有 Code Model
  • implClass 是放置新生成的字段、方法等的正确位置。
  • implRef - 这是什么?

我想为ClassOutline描述的类添加新字段,所以代码如下:

JDefinedClass dstClass = classOutline.ref;
JFieldVar dstField = dstClass.field(srcField.mods().getValue(),
                        srcField.type(), srcField.name());

它工作得很好,直到在执行上述代码并使用com.sun.tools.xjc.outline.ClassOutline.getDeclaredFields() 方法后有另一个插件工作。

想象一下 - Plugin1 创建新字段,然后执行 CopyablePlugin 并希望添加 clone() 方法,该方法复制每个字段。但是CopyablePlugin 看不到Plugin1 新生成的字段-因为要从ClassOutline 检索所有字段,CopyablePlugin 使用com.sun.tools.xjc.outline.ClassOutline.getDeclaredFields() 方法,如下所示:

/**
 * Gets all the {@link FieldOutline}s newly declared
 * in this class.
 */
public final FieldOutline[] getDeclaredFields() {
    List<CPropertyInfo> props = target.getProperties();
    // ...

请注意,getDeclaredFields()ClassOutline.target 字段(这是 Model - 已解析的 XSD 架构)检索属性并完全忽略生成到 ClassOutline.implClass 的代码。

这是错误还是功能?

现在我找到了解决方法。同样的字段也作为属性添加到target

classOutline.target.addProperty(prop);

问题

  1. 能否解释一下,ref/implClass/implRef 的作用是什么?
  2. 我应该在哪里生成全新的字段/方法?转入ref/implClass
  3. 是否需要保持ref/implClasstarget 之间的一致性?添加到implClass 的新字段应该也添加到target,对吧?
  4. com.sun.tools.xjc.outline.ClassOutline.getDeclaredFields() 正确吗?或者如何正确地从 ClassOutline 中检索所有字段?也许这应该是targetimplClass 内容的联合?

【问题讨论】:

    标签: java jaxb xjc sun-codemodel jcodemodel


    【解决方案1】:

    我建议不要向ClassOutline 添加字段。太晚了,也太麻烦了。相信我,我已经试过了。

    我发现向CClassInfo 添加属性更简单、更优雅。这是之前的一个阶段,在这里您可以操作模型。然后在下一步中,将从模型中生成轮廓,因此您甚至不必关心向ClassOutline 添加任何内容。

    要将属性添加到CClassInfo,您只需实例化该属性(例如new CAttributePropertyInfo(...)),然后将其添加到CClassInfomyClassInfo.addProperty(myPropertyInfo);

    对于Copyable 插件,如果您的插件向模型添加属性并且您的插件在Copyable 插件之前被调用,则后者将看到新添加的字段。这正是我建议扩充模型而不是修改大纲或代码模型的原因。

    现在回答你的问题。

    1. ref/implClass/implRef 通常都是目标生成的类。分离是由于 XJC 分别生成“公共接口”和“实现类”的一些生成方式。我不知道implRef 是什么,JavaDoc 说了一些关于用户指定类的内容,所以我正在考虑jaxb:class/@ref 绑定。不过,从来没有处理过。

    2. 最好的办法是扩充模型(如果您想添加新的属性/字段)。如果你想添加一些与模型无关的代码(比如来自Copyable 插件的clone 方法),我将它添加到classOutline.implClass

    3. 技术上没有必要保持代码模型 (classOutline.implClass) 和模型 (classOutline.target) 同步。如果你不这样做,这不会破坏 XJC。我可以想象这可能会破坏一些 XJC 插件。例如,插件可能会遍历JDefinedClass 中的字段并尝试找到相应的模型属性。但危险是理论上的。

    4. ClassOutline.getDeclaredFields()正确,但它只为您提供在此类中声明的字段 - 没有来自超类的字段。但是递归地收集所有字段是非常简单的。 getDeclaredFields() 基于来自 target CClassInfo 的属性生成 FieldOutlines。 忘记implClass,那只是ClassOutline 的代表。 所以“targetimplClass 的联合”没有多大意义。

    【讨论】:

    • 很好的答案。感谢您的所有解释。以及关于CClassInfo 的好建议。
    猜你喜欢
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    相关资源
    最近更新 更多