You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring项目@Context注入UriInfo报无公共构造函数异常排查

故障原因
  • 核心问题是JAX-RS规范注解与Spring MVC注解体系混用不兼容:
    • @Context、javax.ws.rs.core.UriInfo都是JAX-RS(Jersey、RESTEasy等JAX-RS实现)的标准组件,不属于Spring MVC原生支持的注解和类型
    • 当前控制器使用@RestController、@GetMapping这类Spring MVC原生注解,Spring MVC无法识别@Context注解的注入语义,会把标注了@Context的UriInfo方法参数当成普通请求参数,尝试通过默认构造函数实例化后绑定参数值
    • 由于UriInfo是接口,没有公开的无参构造方法,就直接抛出你看到的构造函数找不到的异常,请求根本进不到控制器方法逻辑里
  • 其他未使用@Context的接口走Spring MVC原生参数解析流程,因此可以正常运行
  • 额外注意原代码存在两处会直接导致运行/编译失败的笔误:
    1. @GetMapping("/activate")的路径中没有配置{service}路径占位符,和方法上的@PathVariable("service")不匹配,就算解决注入问题也会报路径参数找不到的错
    2. 方法内定义的账户ID列表变量名为accountIdList,调用mgr.activateAccounts(accIdList)时传的变量名不存在,会直接编译失败
修复方案

优先选方案1,和现有Spring MVC技术栈完全适配,没有额外依赖冲突风险。

方案1:替换为Spring MVC原生API(推荐)

完全移除JAX-RS的@Context和UriInfo依赖,使用Spring MVC原生支持的参数注入方式:

  1. 最简单的实现:直接用Spring MVC自带的参数绑定能力接收accId,不需要自己写解析逻辑,Spring会自动处理逗号分割、类型转换:
@RestController
// 补全路径里的{service}占位符
@RequestMapping(APIConstants.API_BASE_URI + APIConstants.MYCONTROLLER + "/{service}")
public class MyController extends APIRESTResource {

   @GetMapping("/activate")
   public ResponseEntity<String> activateAccount(
         @PathVariable("service") String srvc,
         // Spring自动解析逗号分割的accId参数为Long列表,自动做类型转换
         @RequestParam("accId") List<Long> accountIdList
   ) {
      HttpStatus status = HttpStatus.OK;
      MediaType type = MediaType.TEXT_PLAIN;
      String payload = "Activated";

      try {
         String datasource = getDatasourceForService(srvc);
         AccountsServiceImpl mgr = new AccountsServiceImpl(datasource);
         // 修正原代码的变量名笔误
         mgr.activateAccounts(accountIdList);

         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(type);
         return new ResponseEntity<>(payload, headers, status);
      }
      catch (Exception ex) {
         return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
      }
   }
}
  1. 如果你确实需要保留自定义参数解析逻辑,把UriInfo替换为Spring原生的HttpServletRequest即可,类上注入的@Context UriInfo也一并替换:
// 类上注入的写法
@Autowired
private HttpServletRequest request;

// 自定义解析方法修改入参类型
private List<Long> extractAccountIdsAsList(HttpServletRequest request) throws Exception {
  String fieldName = "accId";
  // 从request对象获取查询参数
  String accIdStr = request.getParameter(fieldName);
  validateRequiredField(fieldName, accIdStr);
  // 原有解析逻辑不需要改动
  accIdStr = accIdStr.replace(" ", "");
  String[] accIds = accIdStr.contains(",") ? accIdStr.split("\\,") : new String[]{accIdStr};
  List<Long> accIdList = new ArrayList<>();
  for (String accId : accIds) {
    validateFieldValueType(fieldName, accId, Long.TYPE);
    accIdList.add(Long.parseLong(accId));
  }
  return accIdList;
}

方案2:配置JAX-RS与Spring整合(不推荐)

如果项目必须保留JAX-RS的@Context注解使用,需要引入对应JAX-RS实现与Spring的整合依赖(比如jersey-spring),并配置JAX-RS注解解析器让Spring能识别@Context的注入语义。但这种方案容易出现依赖冲突、请求处理链冲突的问题,在已经以Spring MVC为主要web栈的项目中不建议使用。

内容的提问来源于stack exchange,提问作者JackTheKnife

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:15:42