项目场景:
最近在做多数据源相关产品,在测试使用mysql的时候是没有任何问题的,但是当使用oracle的时候问题就出来了,,,
问题描述
当我从service层取得List<Map>数据返回给controller的时候,mysql是没有问题的,会正常转换json对象,但是当使用oracle查询数据返回的时候抛异常了!!!而且有两个异常~~因为是多数据源,所以根本没法确定要映射的实体类,所以没有办法使用@JSONIGNORE注解
异常1:com.fasterxml.jackson.databind.JsonMappingException: "Direct self-reference leading to cycle (through reference chain: java.util.HashMap["options"]->java.util.HashMap["JSKH006_N"]->com.alibaba.druid.proxy.jdbc.ClobProxyImpl["connectionWrapper"]->com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl["DATA_"]->oracle.jdbc.driver.OracleDatabaseMetaData["DATA_"]->oracle.jdbc.driver.T4CConnection["wrapper"]
异常2: com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.xinping.crm.platform.mybatis.DatatablesPage["data"]->java.util.ArrayList[0]->java.util.HashMap["CREATE_TIME_"]->oracle.sql.TIMESTAMP["stream"])
@ApiOperation("预览数据视图") @GetMapping("dataview/preview") public AjaxResult preview(PreviewDataViewQuery query) { return AjaxResult.data(dataviewReportBuilder.previewReportDataview(query)); } public List<Map<String, Object>> previewReportDataview(PreviewDataViewQuery query) { ReportDvDataview dataview = this.dataviewService.findById(query.getDatasourceId()); DataviewConfig dvCfg = JSON.parseObject(dataview.getConfig(), DataviewConfig.class); genPreviewSql(dataview, dvCfg); String sql = dataview.getSqlPreview(); List<Map<String,Object>> dataList=DvReportHelper.getPreviewData(dataview.getDatasourceId(), sql, query.getPageSize()); return dataList; }
原因分析及解决:
上网查找了一下相关问题,有个博主说可以先使用fastjson进行转换,然后就不会出问题了,我试了下发现,还是不行,也会抛出fastjson的异常!!!简直了,人都要崩溃了。
这时候就只能从sql语句上去做文章了。
之后我一个一个字段去测试,发现oracle中有一个blob类型的字段,这个大字段存储大文件,原来第一个异常就是因为这个类型json转换不出来,会曝自引用的异常。后来只能给要查找的字段就行裁剪并转换成string类型,对字段进行裁剪使用dbms_lob.substr(字段名,裁剪大小,裁剪初始值),这个方法有个问题就是能裁剪的大小有上限,不过目前也能用。
之后使用UTL_RAW.CAST_TO_VARCHAR2()转成字符串,注意一定要给转换后的字段起别名,不然的话最后映射出来的数据,会是每个函数都是一个对象,对象里面加对象。例子如下:
return "UTL_RAW.CAST_TO_VARCHAR2(dbms_lob.substr(" + field.getField() + ",1000,1)) as " + field.getField();第二个异常就比较简单了,Jackson不是转换 oracle 的TimeStamp类型,这个时候就需要我们把这个类型的字段进行转换,可以转换成String类型to_char(),也可以转换为date类型to_date(),例子如下:
return "to_date(to_char(\"" + field.getField() + "\",'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss') as " + field.getField();