Activiti 流程查询出的结果封装为 JSON 时出现的异常

本文介绍在使用Activiti框架时,如何解决查询流程定义列表返回JSON数据时出现的NullPointerException异常。通过将查询结果封装成Map集合,再转换为List返回,成功解决了返回JSON数据的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Controller

@RestController
public class ActivitiController extends BaseController {
    /**
     * Activiti 框架提供的操作 Repository 系列表的 Service
     */
    @Autowired
    private RepositoryService repositoryService;

    @RequestMapping("/activiti/findProcessListPage/{startIndex}/{pageSize}")
    public Object findProcessListPage(@PathVariable("startIndex") Integer startIndex, @PathVariable("pageSize") Integer pageSize) {
        List<ProcessDefinition> processDefinitions = repositoryService
                .createProcessDefinitionQuery()
                .listPage(startIndex, pageSize);

		System.out.println("---------------" + processDefinitions );
        return processDefinitions ;
    }
}

2、运行结果

java 控制台消息提示,可以正确的查询出 processDefinitions 结果:
在这里插入图片描述
浏览器提示错误消息如下:

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Thu Nov 21 09:27:46 CST 2019
There was an unexpected error (type=Internal Server Error, status=500).
Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl["identityLinks"])
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl["identityLinks"])
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:296)
	at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:295)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181)
	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:124)
	......
	
Caused by: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl["identityLinks"])
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
	at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
	......

Caused by: java.lang.NullPointerException
	at org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl.getIdentityLinks(ProcessDefinitionEntityImpl.java:66)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:721)
	... 108 more

3、解决方法

将查询到每条结果封装到一个 Map 中,进多条结果封装到 List 中,将封装的结果返回即可,具体如下:

@RestController
public class ActivitiController extends BaseController {

    /**
     * Activiti 框架提供的操作 Repository 系列表的 Service
     */
    @Autowired
    private RepositoryService repositoryService;

    @RequestMapping("/activiti/findProcessListPage/{startIndex}/{pageSize}")
    public Object findProcessListPage(@PathVariable("startIndex") Integer startIndex, @PathVariable("pageSize") Integer pageSize) {
        List<ProcessDefinition> processDefinitions = repositoryService
                .createProcessDefinitionQuery()
                .listPage(startIndex, pageSize);

        // ============= 对上面查询结果进行封装 ==================
        List<Map<String, Object>> pdResult = new ArrayList<>();
        for (ProcessDefinition processDefinition : processDefinitions) {
            Map<String, Object> pdMap = new HashMap<>();
            pdMap.put("id", processDefinition.getId());
            pdMap.put("key", processDefinition.getKey());
            pdMap.put("name", processDefinition.getName());
            pdMap.put("version", processDefinition.getVersion());
            pdMap.put("deploymentId", processDefinition.getDeploymentId());
            pdResult.add(pdMap);
        }
        // ================== 封装完成 =========================
        
        System.out.println("---------------" + pdResult);
        return pdResult;
    }
}

运行结果如下:

[{
	“deploymentId”:“d05c66ec-09ad-11ea-a748-4ccc6ac9b5ee”,		
	“name”:“请假审批流程”,
	“id”:“holiday:1:d07a9d4f-09ad-11ea-a748-4ccc6ac9b5ee”,	
	“version”:1,
	“key”:“holiday”
}]

4、通用的封装方法

使用反射动态获取类中的 get 方法,将方法的返回值进行封装,如下:(此封装方法也可用于activiti其他的查询返回json)

public class Util {
    public static List<Map<String, Object>> activitiResult(List<?> objs) {
        // 用于存放多个对象的集合
        List<Map<String, Object>> pdResult = new ArrayList<>();
        // 遍历方法参数中的集合
        for (Object obj : objs) {
            // 用于封装单个对象 get 方法返回值的 Map 集合
            Map<String, Object> pdMap = new HashMap<>();
            // 通过反射获取该对象的方法对象数组
            Method[] methods = obj.getClass().getMethods();
            // 遍历方法对象数组
            for (Method method : methods) {
                // 获取方法名称
                String methodName = method.getName();
                // 判断该方法是否名称不为 null ,并且名称是以 get 开头,满足条件进入 if 中
                if (methodName != null && methodName.startsWith("get")) {
                    // 设置方法的访问权限
                    method.setAccessible(true);
                    try {
                        // 将方法名的 get 前缀去掉,并增加 pd 前缀
                        String pdKey = "pb".concat(methodName.substring(3));
                        // 将 get 方法的名称作为 Map 的 key,将返回值作为 value 进行封装
                        pdMap.put(pdKey, method.invoke(obj, null));
                    } catch (Exception e) {
                        //输出异常,由于使得后台过乱,所以关掉
//                        e.printStackTrace();
                    }
                }
            }
            // 将封装好的 Map 集合添加到 List 集合中
            pdResult.add(pdMap);
        }
        return pdResult;
    }
}

在需要封装结果的方法中调用此方法即可:

public Result queryProcesses() {
        //1.得到ProcessDefinitionQuery对象,可以认为它就是一个查询器
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        //2.设置条件,并查询出当前的所有流程定义   查询条件:流程定义的key=holiday
        //orderByProcessDefinitionVersion() 设置排序方式,根据流程定义的版本号进行排序
        List<ProcessDefinition> list = processDefinitionQuery
//                .processDefinitionKey("holiday") //查询固定流程
                .orderByProcessDefinitionVersion()
                .desc().list();
        Result res=new Result();
        res.setFlag("1");
        res.setMsg("查询成功");
        //该list无法返回为json会报错,将它封装为List<Map<String, Object>>再返回,使用通用封装类Util进行封装
        res.setResult(Util.activitiResult(list));
        return res;
    }

运行结果如下:

[{
	“pbCategory”:“http://www.activiti.org/testm1574044576798”,
	“pbDeploymentId”:“d05c66ec-09ad-11ea-a748-4ccc6ac9b5ee”,
	“pbPersistentState”:{
		“suspensionState”:1,“category”:	
		“http://www.activiti.org/testm1574044576798”
		},“pbHasStartFormKey”:false,“pbSuspensionState”:1,
	“pbName”:“请假审批流程”,
	“pbDiagramResourceName”:“process/holiday.png”,
	“pbVersion”:1,
	“pbKey”:“holiday”,
	“pbResourceName”:“process/holiday.bpmn”,
	“pbTenantId”:""
}]

以上内容转载自优快云博主「yage124」的原创文章,原文链接:https://blog.youkuaiyun.com/yage124/article/details/103176405

5.原因分析

打开activiti的一个实体类org.activiti.engine.task,如下所示,并不像我们平时的实体类,get和set方法在一个类中,他是分不同种的接口,可能就是由于这个原因使得无法返回json格式数据。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值