简体   繁体   English

如何从JerseyTest子类访问Spring Bean

[英]How to access Spring Bean from JerseyTest subclass

Here is my abstract class which starts Jersey with given Spring context: 这是我的抽象类,它从给定的Spring上下文开始Jersey:

public abstract class AbstractJerseyTest extends JerseyTest {

public void setUp() throws Exception {
    super.setUp();
}

@AfterClass
public void destroy() throws Exception {
    tearDown();
}

@Override
protected URI getBaseUri() {
    return URI.create("http://localhost:9993");
}

@Override
protected Application configure() {
    RestApplication application = new RestApplication();

    Map<String, Object> properties = new HashMap<String, Object>();
    properties.put(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    properties.put("contextConfigLocation", "classpath:spring-context-test.xml");

    application.setProperties(properties);
    application.register(this);
    return application;
}
}

So, the problem is that I need to access Spring bean from my test to populate database with some data. 因此,问题在于我需要从测试中访问Spring bean,以使用一些数据填充数据库。

Jersey version is 2.6 球衣版本是2.6

Also I found a similar question here 我也在这里找到了类似的问题

But it's related to Jersey 1.x so it doesn't work for Jersey 2.x 但这与Jersey 1.x有关,因此不适用于Jersey 2.x

Could anyone point me in the right direction? 有人能指出我正确的方向吗?

Normally in your case, I'd just say work with mocks, but there are cases where you may need to expose the services in the test class. 通常情况下,我只是说要使用模拟,但是在某些情况下,您可能需要在测试类中公开服务。

To do this without any "ugly hacks", you will need to get a handle on the ServiceLocator (which is analogous to Spring's ApplicationContext ). 为了做到这一点而没有任何“丑陋的hack”,您将需要在ServiceLocator上获得一个句柄(类似于Spring的ApplicationContext )。 When the Jersey app boots up, all the Spring services from the ApplicationContext are put into the ServiceLocator through HK2's Spring bridge. 当Jersey应用启动时,来自ApplicationContext所有Spring服务都将通过HK2的Spring桥放入ServiceLocator

The problem is JerseyTest does not expose the ServiceLocator in any way. 问题是JerseyTest不会以任何方式公开ServiceLocator The only way I can think of to get a hold of it, is to create your own TestContainerFactory , and create the ApplicationHandler , which exposes the ServiceLocator . 我想得到它的唯一方法是创建自己的TestContainerFactory ,并创建ApplicationHandler ,从而公开ServiceLocator

Trying to implement your own TestContainerFactory is not a walk in the park, if you don't know what you're doing. 如果您不知道自己在做什么,尝试实现自己的TestContainerFactory并不是在公园里散步。 The easiest thing to do is just look at the source code for Jersey's InMemoryTestContainerFactory . 最简单的方法是查看Jersey的InMemoryTestContainerFactory的源代码。 If you look at the constructor for the inner class InMemoryTestContainer , you will see it creating the ApplicationHandler . 如果查看内部类InMemoryTestContainer的构造函数,您会看到它正在创建ApplicationHandler This is how you can expose the ServiceLocator , through the appHandler.getServiceLocator() . 这是通过appHandler.getServiceLocator()公开ServiceLocatorappHandler.getServiceLocator()

So if you copied that class, and exposed the ServiceLocator , you could create your JerseyTest extension, and call the ServiceLocator.inject(Object) method to inject the test class. 因此,如果复制了该类并公开了ServiceLocator ,则可以创建JerseyTest扩展,然后调用ServiceLocator.inject(Object)方法来注入测试类。

public abstract class AbstractServiceLocatorAwareJerseyTest extends JerseyTest {

    private final ServiceLocatorAwareInMemoryTestContainerFactory factory
            = new ServiceLocatorAwareInMemoryTestContainerFactory();
    private ServiceLocator locator;

    @Override
    public TestContainerFactory getTestContainerFactory() {
        return factory;
    }

    @Before
    @Override
    public void setUp() throws Exception {
        super.setUp();
        this.locator = factory.getServiceLocator();
        if (injectTestClass()) {
            this.locator.inject(this);
        }
    }

    public boolean injectTestClass() {
        return true;
    }

    public ServiceLocator getServiceLocator() {
        return locator;
    }
}

And if for any reason you needed it, the ServiceLocator also has the ApplicationContext , which you could also expose to your test class if needed. 并且,如果出于任何原因需要它, ServiceLocator还具有ApplicationContext ,如果需要,还可以将其公开给测试类。

I put together a GitHub project , with a complete implementation, with tests if you want to take a look at it. 如果您想看一下,我将GitHub项目和一个完整的实现一起进行了测试。


UPDATE UPDATE

Though the OP's answer to this question works, I believe the fact that it works, is a bug. 尽管OP对这个问题的回答是可行的,但我相信它可行的事实是一个错误。 I originally deleted this answer, after the OP posted their answer, but after some testing, I believe that solution is a bug, so I've undeleted this post for anyone who doesn't like the warning 1 you get when you use that solution 我最初在OP发布他们的答案后删除了这个答案,但是经过一些测试,我相信该解决方案是一个错误,因此对于那些不喜欢警告1的人,我已取消删除该帖子。


1. "WARNING: A provider SimpleTest registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider SimpleTest will be ignored." 1.“警告:在SERVER运行时中注册的提供者SimpleTest不会实现在SERVER运行时中适用的任何提供者接口。由于约束配置问题,提供者SimpleTest将被忽略。”

Solution was really simple. 解决方法非常简单。 I added: 我补充说:

@Autowired
private Repository repository;

to the AbstractJerseyTest and this field was automatically autowired during test startup. 到AbstractJerseyTest,并且该字段在测试启动过程中自动自动接线。 I don't know details about how it works, but it seems that when I register instance of the test in REST application 我不知道有关其工作原理的详细信息,但似乎当我在REST应用程序中注册测试实例时

application.register(this);

it automatically autowires all beans in the test. 它会自动为测试中的所有bean自动布线。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM