Direct self-reference leading to cycle

问题描述

后台添加新菜单后,mvn test运行单元测试,WebAppMenuControllerTest.java报了如下错误。

org.springframework.web.util.NestedServletException: Request processing failed; 
nested exception is org.springframework.http.converter.HttpMessageNotWritableException: 
Could not write JSON document: 
Direct self-reference leading to cycle 
(through reference chain: java.util.ArrayList[98]
->com.mengyunzhi.measurement.entity.WebAppMenu["parentWebAppMenu"]); 

起初,还是怀着对控制台错误信息惧怕的原理,自己倒腾了半天也没有什么结果。

翻译这行错误:不能写入JSON文档,直接引用导致循环。

去看抛出错误的测试代码:

public class WebAppMenuControllerTest extends ControllerTest {
    @Test
    public void getAll() throws Exception {
        MvcResult mvcResult = this.mockMvc.perform(get("/WebAppMenu/")
                .header("x-auth-token", xAuthToken)
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andDo(document("WebAppMenu",  preprocessResponse(prettyPrint())))
                .andExpect(status().isOk())
                .andReturn();
        String content = mvcResult.getResponse().getContentAsString();
        JSONArray jsonArray = JSONArray.fromObject(content);
        assertThat(jsonArray.size()).isGreaterThan(8);
        return;
    }
}

测试映射GetMapping("/WebAppMenu/")出现了错误,找到这个映射对应的方法:

@Api(tags = "WebAppMenu 前台菜单", description = "前台菜单 用于前台注册路由及显示左侧菜单")
@RequestMapping("/WebAppMenu")
@RestController
public class WebAppMenuController {
    // 前台菜单
    @Autowired
    private WebAppMenuService webAppMenuService;

    @ApiOperation(value = "/ 获取所有菜单列表", notes = "获取所有的前台菜单", nickname = "WebAppMenu")
    @GetMapping("/")
    public List getAll() {
        return webAppMenuService.getAll();
    }
}

该方法调用了我们的MWebAppMenuService中的getAll方法,我们去查看该方法。

@Service
public class WebAppMenuServiceImpl implements WebAppMenuService {
    @Autowired
    private WebAppMenuRepository webAppMenuRepository;

    @Override
    public List getAll() {
        List list = new ArrayList();
        // 按权重进行排序,权重越小越靠前
        list = (List)webAppMenuRepository.findAll(new Sort("weight"));
        return list;
    }
}

这里返回了一个List,在此打一个断点,然后debug我们刚刚的测试文件。

Direct self-reference leading to cycle_第1张图片
image.png

我们展开看一下返回的list有没有问题。

Direct self-reference leading to cycle_第2张图片
image.png

展开,发现第98条记录(检定能力覆盖率统计)栈溢出,找到初始化菜单的代码,找到生成检定能力覆盖率统计菜单的代码。

logger.info("检定能力覆盖率统计");
WebAppMenu checkAbilityCoverageRate = new WebAppMenu();
checkAbilityCoverageRate.setName("检定能力覆盖率统计");
checkAbilityCoverageRate.setDescription("强检器具统计管理-检定能力覆盖率统计");
checkAbilityCoverageRate.setRouteName("coverageRate");
checkAbilityCoverageRate.setParentWebAppMenu(checkAbilityCoverageRate);
checkAbilityCoverageRate.setParentRouteWebAppMenu(checkAbilityCoverageRate);
checkAbilityCoverageRate.setTemplateUrl("views/forceInstrumentStatistics/coverageRate/index.html");
webAppMenus.add(checkAbilityCoverageRate);

这里,误将该菜单的父菜单设置为自己,所以获取数据时就会无限循环,也就是报错信息中给我们的提示:直接引用导致循环。

修正代码,再次运行单元测试。

总结

遇到cycle关键字,可能就是对象之间的关系设置错误,导致一直循环。

你可能感兴趣的:(Direct self-reference leading to cycle)