Flowable部署Jackson序列化异常:CommandContextUtil.getResourceEntityManager()为空
调用代码
public IPage<Deployment> deploymentPage(Query query, String key, String name, String tenantId) { DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery(); if (StringUtil.isNotBlank(key)) { deploymentQuery.deploymentKeyLike(StringPool.PERCENT + key + StringPool.PERCENT); } if (StringUtil.isNotBlank(name)) { deploymentQuery.deploymentNameLike(StringPool.PERCENT + name + StringPool.PERCENT); } if (StringUtil.isNotBlank(tenantId)) { deploymentQuery.deploymentTenantId(tenantId); } IPage<Deployment> page = Condition.getPage(query); long count = deploymentQuery.count(); List<Deployment> deployments = deploymentQuery.orderByTenantId().orderByDeploymentTime().desc().listPage((query.getCurrent() - 1) * query.getSize(), query.getSize()); page.setRecords(deployments); page.setTotal(count); return page; }
错误信息
Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: org.springblade.core.tool.api.R["data"]->com.baomidou.mybatisplus.extension.plugins.pagination.Page["records"]->java.util.ArrayList[0]->org.flowable.engine.impl.persistence.entity.DeploymentEntityImpl["resources"])
问题定位
序列化时触发DeploymentEntityImpl.getResources()方法,其中CommandContextUtil.getResourceEntityManager()返回null,导致空指针异常:
@Override public Map<String, EngineResource> getResources() { if (resources == null && id != null) { List<ResourceEntity> resourcesList = CommandContextUtil.getResourceEntityManager().findResourcesByDeploymentId(id); resources = new HashMap<>(); for (ResourceEntity resource : resourcesList) { resources.put(resource.getName(), resource); } } return resources; }
解决方案
方案1:序列化时排除懒加载的resources字段
getResources()是懒加载逻辑,且依赖Flowable的命令上下文,序列化触发时上下文已不存在,导致空指针。可以通过两种方式处理:
- 若能修改Flowable相关类,给
DeploymentEntityImpl.getResources()方法添加@JsonIgnore注解,直接忽略该字段的序列化; - 自定义
DeploymentDTO,仅包含需要返回的业务字段(如id、name、key、tenantId、deploymentTime等),将查询到的Deployment对象转换为DTO后再返回,避免触发resources的懒加载逻辑。
方案2:在Flowable命令上下文内预加载资源
Flowable的CommandContextUtil仅在Flowable命令执行流程中有效,可通过ManagementService执行命令来预加载资源,确保上下文存在:
List<Deployment> deployments = deploymentQuery.orderByTenantId().orderByDeploymentTime().desc().listPage((query.getCurrent() - 1) * query.getSize(), query.getSize()); // 在命令上下文内预加载resources,避免后续序列化时触发懒加载 managementService.executeCommand((Command<Void>) commandContext -> { deployments.forEach(Deployment::getResources); return null; });
方案3:手动查询资源并封装
绕过Flowable的懒加载逻辑,手动查询Deployment对应的资源并封装:
List<Deployment> deployments = deploymentQuery.orderByTenantId().orderByDeploymentTime().desc().listPage((query.getCurrent() - 1) * query.getSize(), query.getSize()); // 手动查询每个Deployment的资源并处理 for (Deployment deployment : deployments) { List<String> resourceNames = repositoryService.getDeploymentResourceNames(deployment.getId()); // 可选:将资源信息封装到自定义DTO,或者通过反射设置到Deployment的resources字段(如果允许) }
内容的提问来源于stack exchange,提问作者lei qin

