如何将 @Context 注释字段注入 RestEasy @Provider?

Posted

技术标签:

【中文标题】如何将 @Context 注释字段注入 RestEasy @Provider?【英文标题】:How can I inject an @Context-annotated field into a RestEasy @Provider? 【发布时间】:2019-08-31 20:21:09 【问题描述】:

在 JBoss 容器中使用 RestEasy,我有一个带有 @Provider 注释的 ExceptionMapper,它可以通过 @Context 注释访问 HttpServletRequestHttpServletResponse,如下所示:

@Provider
public class MyExceptionMapper implements ExceptionMapper<Throwable> 
  @Context
  private HttpServletRequest httpServletRequest;

  @Context
  private HttpServletResponse httpServletResponse;

  @Override
  public Response toResponse(final Throwable exception) 
    ...
    return response;
  

我是 RestEasy 的新手,来自 Spring 背景,所以天真地以为我能够注入这两个字段并在单元测试中模拟它们,但这似乎比我预期的要难!

如果模拟框架是相关的,我正在使用 JMockit,而且我也是新手。到目前为止,我已经能够成功地将我对 Mockito 的知识应用到它上面。

除了在我的单元测试中运行嵌入式容器的许多建议外,我没有通过搜索该主题找到太多东西。我并不完全反对,但是当我只是想写一个简单的单元测试时,感觉有点矫枉过正。

我在测试中尝试了几件事,最近是这样的:

public class MyExceptionMapperTest 
  @Injectable
  private HttpServletRequest httpServletRequest;

  @Injectable
  private HttpServletResponse httpServletResponse;

  @Tested
  private MyExceptionMapper exceptionMapper;

  @Test
  public void test() 
    exceptionMapper.toResponse(new Throwable());
  

但这会在我第一次引用@Context 字段之一时导致MyExceptionMapper 中的NullPointerException,这告诉我它们没有被注入。

我也试过了:

使用@Mocked 代替@Injectable; 直接实例化MyExceptionMapper 有和没有@Tested 注释; 在我的测试中创建Expectations;和 上述的每一个排列

在所有情况下,@Context-annotated 字段都是null

希望我只是遗漏了一些非常明显的东西吗?

【问题讨论】:

你使用-javaagent参数初始化JMockit了吗? @Rogério - 不知情。我只是在 IntelliJ 中将测试作为普通 JUnit 测试运行,并且在 Maven POM 中看不到对 -javaagent 的任何引用。我应该使用它吗? 如果您使用的是最新版本的 JMockit,那么可以。 【参考方案1】:

在没有更好的答案的情况下,我最终在测试中使用反射来为这两个属性注入值。不理想,但它有效:

public class MyExceptionMapperTest 
  @Mocked
  private HttpServletRequest mockHttpServletRequest;

  @Mocked
  private HttpServletResponse mockHttpServletResponse;

  private MyExceptionMapper exceptionMapper = new MyExceptionMapper();

  @Before
  public void setup() 
    Field httpServletRequest = exceptionMapper.getClass().getDeclaredField("httpServletRequest");
    httpServletRequest.setAccessible(true);
    httpServletRequest.set(exceptionMapper, mockHttpServletRequest);

    Field httpServletResponse = exceptionMapper.getClass().getDeclaredField("httpServletResponse");
    httpServletResponse.setAccessible(true);
    httpServletResponse.set(exceptionMapper, mockHttpServletResponse);
  

然后在我的测试中,我可以正常设置两个 @Mocked 值的期望和验证。

我不是反思方面的专家,所以这可能不是最好/最有效的方法,但它足以满足我的需求。

【讨论】:

以上是关于如何将 @Context 注释字段注入 RestEasy @Provider?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 context.xml 注入值

如何将属性值注入使用注释配置的 Spring Bean?

在测试期间注入@Autowired 私有字段

从弹簧配置中初始化或将字符串注入静态字段 beforeClass (JUNIT) 的优雅方法?

将变量注入到 websocket 注释 @ServerEndpoint("/myVar")

如何使弹簧将值注入静态字段