JAXB、XJC:生成字段到 Class 大纲

JAXB, XJC: Generating field to Class Outline

我的问题涉及编写 JAXB 插件,特别是 ClassOutline 内部。

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

代码:

/**
 * 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):


我想向 ClassOutline 描述的 class 添加新字段,因此代码如下所示:

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. 我应该在哪里生成全新的 fields/method?进入ref/implClass?
  3. ref/implClasstarget有必要保持一致吗?添加到 implClass 的新字段也应该添加到 target,对吗?
  4. com.sun.tools.xjc.outline.ClassOutline.getDeclaredFields()是否正确?或者如何正确地从 ClassOutline 中检索所有字段?也许这应该是 targetimplClass 内容的结合?

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

我发现向 CClassInfo 添加属性更容易也更优雅。这是更早的一个阶段,在这里您可以操纵模型。然后在下一步中将从模型生成轮廓,因此您甚至不必关心向 ClassOutline.

添加任何内容

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

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

现在回答你的问题。

  1. ref/implClass/implRef 通常都是生成的目标 class。分离是由于一些生成模式,其中 XJC 分别生成 "public interface" 和 "implementing class"。我不知道 implRef 是什么,JavaDoc 说了一些关于用户指定的 classes 所以我在考虑 jaxb:class/@ref 绑定。不过从来没有处理过。

  2. 最好是扩充模型(如果你想添加新的 properties/fields)。如果你想添加一些与模型无关的代码(比如 Copyable 插件中的 clone 方法),我只是将它添加到 classOutline.implClass.

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

  4. ClassOutline.getDeclaredFields() 正确的,但它只为您提供在此 class 中声明的字段 - 没有来自 super[= 的字段73=]。但是递归地收集所有字段是非常微不足道的。 getDeclaredFields() 根据 target CClassInfo 的属性生成 FieldOutlines。 忘记 implClass,那只是 ClassOutline 的表示。 所以"union of target and implClass"没有多大意义。