【问题标题】:Create dynamic classes with reserved words as variables使用保留字作为变量创建动态类
【发布时间】:2017-01-19 05:02:40
【问题描述】:

这个问题曾经在Reserved words as variable or method names 被问到除了“你为什么要这样做”之外没有一个令人满意的答案。我将再次询问它,并提供解释为什么它是必要的上下文,甚至是正确解决方案的方向。

我正在编写动态构建类以匹配数据库架构的代码,我无法控制它。在大多数情况下,代码运行良好,但在大约 0.1% 的列案例中,Java 中的保留字被用作列名。以下代码用于在类中创建动态字段:

evalClass.addField(CtField.make("public" + columnType + " " + columnName + ";", evalClass));

现在,使用 Java 语言,这会导致一个问题,但是在 JVM 字节码中,这应该是完全合法的,因此应该有一种方法可以动态创建此字段并使用字节码操作访问它。是否有人有任何示例说明如何以支持任意字符串(包括空格和保留字)的方式完成此操作?谢谢!

【问题讨论】:

  • 这个问题绝对有一个令人满意的答案:"No, there is no way." 你的问题和那个问题之间的区别在于你没有尝试在源代码级别 做它。我建议进行编辑以将该信息移至前台,并在最后仅提及另一个问题:“我看到了这个,但它询问的是源代码,并且我询问的是在字节码级别进行操作,因为我们不能在源代码级别进行。”
  • 我仍然不明白为什么这是必要的。我能想到的每个持久性架构都提供了将字段/bean 属性名称映射到任意列名称的简单技术,避免使用 Java 关键字字段名称是提供该技术的原因之一。当然,您是从模式生成类,但概念是相同的。为什么您的字段名称必须与列名称相同?你为什么不只是例如为所有字段名称(或仅保留字)添加前缀或其他内容?
  • 即使您可以生成这些类,它们的用途是什么?您不能在您编写的任何源代码中使用这些字段。整件事听起来像是浪费大量时间的好方法。花时间将 Jason 提到的映射构建到您的持久性架构中(和/或也许问问自己为什么要编写自己的持久性架构)。
  • @Jason C,就我而言,问题是谓词需要准确映射到数据结构的 SQL,并准确映射到表的列名以防止更多抽象层(并降低性能) 从被添加进来。有问题的代码在 JDBC api 级别以下运行(它实际上是一个 JDBC 驱动程序),因此现有的抽象机制此时已经转换为实际的表名。
  • @ErikBrandsberg 看起来还是很奇怪...我确信你有理由做你正在做的事情,但看起来你已经添加了额外的抽象层?您正在创建这些内部映射类,但最终您只是通过ResultSet 将它们传递回应用程序——它以 VO 的形式提供每列的信息,而不是作为 POJO/bean 的每行的信息-- 它们可能会再次被映射到应用程序端的类。但无论如何,它是否足够简单,例如用“_”作为所有字段名称的前缀并将其删除?另外,锑的答案。

标签: java reflection bytecode javassist


【解决方案1】:

目前尚不清楚您卡在哪一部分。任何字节码操作库都应该允许您这样做。

例如,使用 ASM,您只需将字符串直接传递给 visitField。没有可以跳过的箍或任何东西。

请注意,即使在字节码级别,字段名称仍然存在一些限制。特别是,在 MUTF8 编码中,它们的长度不能超过 65535 字节。

【讨论】:

    【解决方案2】:

    您选择了唯一行不通的方法——Javassist 的源代码级 API。你应该很清楚,如果你使用标识符来构造源代码,那么标识符必须遵守源代码规则。此外,使用已知的意图结构构造源代码,必须再次解析以重构意图,是处理字节码的最低效的方式。

    您可以使用Bytecode level API 来克服这些限制。附带说明一下,大多数其他字节码处理库根本没有源代码级 API,因此使用它们,您从一开始就使用字节码级 API。

    也就是说,您应该重新考虑您的前提。其字段只能通过反射或其他生成代码访问的生成类不提供任何优势,例如HashMap 从标识符映射到值或数组,本质上将列与位置相关联。

    【讨论】:

    • 感谢您的确认,Javassist 似乎是获得所需功能的简单方法,并且在 99.9% 的情况下,它可以工作。由于这个特定的功能只需要用于设置类,性能不是主要因素。前提是,这段代码是 JDBC 级别的驱动程序级代码,我们不控制字段,并且还使用来自合作伙伴的其他代码,该代码依赖于与数据库中的字段匹配的字段。因此,更改字段名称将比仅仅完成这项工作更痛苦。
    • 嗯,源代码级别的 API 不仅在性能方面更昂贵,而且还提供了更多引入错误的可能性。它不仅对匹配关键字的字段名称敏感,添加名称与类型名称匹配的字段也会使 next 声明虚假地失败。
    最近更新 更多