【问题标题】:Conditional generation of method bodies to satisfy large interfaces in Java有条件地生成方法体以满足 Java 中的大型接口
【发布时间】:2012-08-01 05:53:00
【问题描述】:

Java OpenGL GL 接口包含大约 2000 个方法,出于调试目的,我想包装一个实例并在进行一些日志记录时委托对它的调用。在每种情况下,日志代码都可以推送到相同的方法,因此写出方法实现的任务看起来可以自动化。我正在尝试做的一个例子:

import javax.media.opengl.GL;

public class GLErrorLogger implements GL {
  private final GL backing;

  public GLErrorLogger(GL delegateToMe) {
    backing = delegateToMe;
  }

  private void checkErrorCode() {
    // Log frame and thread details depending on gl state
  }

  /**
   * Example of a method
   */
  @Override
  public int glGenLists(int arg0) {
    checkErrorCode();
    int retVal = backing.glGenLists(arg0);
    checkErrorCode();
    return retVal;
  }

  // rest of methods here...
}

换句话说,将方法名称和参数(减去它们的类型)复制到对支持对象的调用中,并围绕对日志记录方法的调用,如果有返回类型,则将结果分配给该类型的变量并在方法结束时返回。

我查看了创建一次性 Eclipse 代码模板来自动生成方法,但没有立即明显的方法来对返回类型进行模式匹配。任何人都可以建议一种在 Eclipse 或其任何代码生成工具中执行此操作的方法,以节省我提取正则表达式工具包的时间吗?

【问题讨论】:

标签: java eclipse templates code-generation pattern-matching


【解决方案1】:

您可能希望使用 Aspect 为您创建必要的字节码,而不是生成所有源代码。在此处查看 Traceing Aspect 示例:Traceing Aspect Example

作为替代方案,如果您不想将 AspectJ 用作第三方库,则可以创建 Java 动态代理。请参考Dynamic Proxy Tutorial

【讨论】:

  • 因为Proxy 是JDK 的一部分并且非常简单,所以我真的推荐这个解决方案。到目前为止,所有其他提案都需要额外的库、额外的开销和很多对于初学者(该库的)额外的努力,但收益却很少。
  • 代理的好主意,看起来我仍然可以在将调用传递到调用处理程序方法时反射性地获取堆栈信息。
  • 确实可以 - 它为您节省了 LOT 的样板代码 :-)。至于动态代理与 AspectJ,我完全同意使用 AspectJ 的障碍更高,但另一方面,我认为 AspectJ 更强大,因为您不必手动创建代理。如果您只想跟踪,请坚持使用动态代理 - 如果您希望将更多的交叉切割问题从源代码中分离出来,我建议您使用 AspectJ。也许可以解决您当前使用动态代理的问题之后再看看 AspactJ。
  • 对于任何尝试代理像 GL 这样的大型类的人的说明,当我将测试代码切换到这种类型时,我遇到了方法大小的 65k 限制。为什么 (minfo.code.size() > 65535) {throw new IllegalArgumentException("code size limit exceeded");除非 ProxyGenerator 将所有内容都放在 MethodInfo 中,否则将被调用。
  • 终于回到了这个问题上,我最终提交了关于生成 65k+ 静态初始化程序的 java bug 7189284。动态代理是一个很好的解决方案,但如果您的界面碰巧有许多静态变量,则可能需要此处建议的其他方法之一。
【解决方案2】:

按照建议使用 JDK 代理,或者:使用像 EasyMockMockito 这样的 Mock 框架。

GL mock = EasyMock.createMock(GL.class);
EasyMock.expect(mock.someMethod()).andReturn(someValue);
// or, if you need to do more computing:
EasyMock.expect(mock.someOtherMethod()).andAnswer(new IAnswer<String>() {
        public String answer() throws Throwable {
            return "some value you calculate here";
        }
    });
EasyMock.replay(mock);

现在您可以将mock 对象用于您配置的所有方法。 请参阅EasyMock readme 了解更多信息。

【讨论】:

  • +1 无论如何都有 Mockito,这是让某些东西运行起来的最快方法。谢谢。
猜你喜欢
  • 1970-01-01
  • 2023-03-31
  • 2019-11-08
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-25
  • 1970-01-01
相关资源
最近更新 更多