AspectJ 能否替代“新 X"?使用“新的 SubclassOfX"在第三方库代码中? [英] Can AspectJ replace "new X" with "new SubclassOfX" in third-party library code?

查看:22
本文介绍了AspectJ 能否替代“新 X"?使用“新的 SubclassOfX"在第三方库代码中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究 AspectJ,看看我们是否可以在我们的测试套件中使用它.

I am looking at AspectJ to see if perhaps we can use it in our test suite.

我们有一个相当大的第三方 Java 通信库,硬连线使用它自己的类(不实现任何接口),这反过来意味着我们需要一个物理后端存在并正确配置以能够运行测试.

We have a rather large third party Java communications library hardwired to use its own classes (which do not implement any interfaces) which in turn mean that we need a physical backend present and correctly configured to be able to run tests.

我正在考虑取消此限制的选项.一种可能性是创建麻烦类的子类,然后在加载第三方库时要求 AspectJ 简单地将new X"替换为new OurSubclassOfX",但我是 AspectJ 的新手,并且从我对文档的简要浏览来看不是典型的用例.

I am looking at our options for removing this restriction. A possibility would be to create a subclass of the troublesome classes and then ask AspectJ to simply replace "new X" with "new OurSubclassOfX" when loading the third party library, but I am new to AspectJ and from my brief skimming of the documentation this is not a typical use case.

AspectJ 能做到吗?配置片段是什么?

Can AspectJ do this? What would the configuration snippet be?

推荐答案

是的,这是可能的.让我们假设您有一个硬接线类,可能从数据库中获取某些内容,并希望通过方面来模拟它:

Yes, this is possible. Let us assume you have a hard-wired class, possibly fetching something from a database, and want to mock it via an aspect:

package de.scrum_master.aop.app;

public class HardWired {
    private int id;
    private String name;

    public HardWired(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public void doSomething() {
        System.out.println("Fetching values from database");
    }

    public int getSomething() {
        return 11;
    }

    @Override
    public String toString() {
        return "HardWired [id=" + id + ", name=" + name + "]";
    }
}

然后有一个使用该类(不是接口)的小驱动程序应用程序:

Then there is a little driver application using that very class (not an interface):

package de.scrum_master.aop.app;

public class Application {
    public static void main(String[] args) {
        HardWired hw = new HardWired(999, "My object");
        System.out.println(hw);
        hw.doSomething();
        System.out.println(hw.getSomething());
    }
}

输出如下:

HardWired [id=999, name=My object]
Fetching values from database
11

现在你定义你的派生模拟类,为了测试目的,它应该替换原来的:

Now you define your derived mock class which should replace the original for testing purposes:

package de.scrum_master.aop.mock;

import de.scrum_master.aop.app.HardWired;

public class HardWiredMock extends HardWired {
    public HardWiredMock(int id, String name) {
        super(id, name);
    }

    @Override
    public void doSomething() {
        System.out.println("Mocking database values");
    }

    @Override
    public int getSomething() {
        return 22;
    }

    @Override
    public String toString() {
        return "Mocked: " + super.toString();
    }
}

最后你用一个简单的切入点和建议定义一个方面,以在每次构造函数调用期间替换原始值:

And finally you define an aspect with a simple pointcut and advice to replace the original value during each constructor call:

package de.scrum_master.aop.aspect;

import de.scrum_master.aop.app.HardWired;
import de.scrum_master.aop.mock.HardWiredMock;


public aspect MockInjector {
    HardWired around(int p1, String p2) : call(HardWired.new(int, String)) && args(p1, p2) {
        return new HardWiredMock(p1, p2);
    }
}

输出根据需要改变:

Mocked: HardWired [id=999, name=My object]
Mocking database values
22

您对每个类和构造函数都执行一次,就可以了.为了概括该方法,您需要连接点属性,并且根据您想要走多远,可能是反射,但这在这里非常简单.享受!

You do that once per class and constructor and are fine. In order to generalise the approach you would need joinpoint properties and, depending on how far you want to go, maybe reflection, but this here is pretty straightforward. Enjoy!

这篇关于AspectJ 能否替代“新 X"?使用“新的 SubclassOfX"在第三方库代码中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆