本文介绍了AspectJ可以替换"new X"吗?与"new 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 OurSubclassOfX"简单地将"new X"替换为"new X",但是我对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可以替换"new X"吗?与"new SubclassOfX"一起使用;在第三方库代码中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-03 14:38