Skip to content

[FEATURE]org.bson.types.Decimal128转Double时会报错 #2558

@ocean23

Description

@ocean23

请描述您的需求或者改进建议

背景如下:
1、我们会把java对象通过fastjson转为String然后通过MQ 发送出来,在接收端会再通过fastjsonString转化JSONObject

    public void handleChannel(String data) throws PropertyMapperException {
        JSONObject jsonData = JSON.parseObject(data);
        ViewMO inputMO = jsonData.toJavaObject(ViewMO.class);
        ImportBatchDetailDO task = new ImportBatchDetailDO();
        task.setData(jsonData);
        task.setSyncImportTaskId(inputMO.getId());
        importBatchDetailRepo.save(task);
    }

2、由于fastjson缺省反序列化带小数点的数值类型为BigDecimal,所以上面jsonData这个JSONObject里面的小数都会被转为BigDecimal, 而由于我们的数据库用的是mongodb,所以存储进mongodb时这个BigDecimal又会自动被转为org.bson.types.Decimal128
3、但是当我们从MongoDB读回这个JSONObject对象时,由于java映射这个JSONObject的小数的类型是Double,这时由于fastjson代码里的ObjectReaderProvider.typeConverts并没有把org.bson.types.Decimal128转为DoubleConverts, 这时就会报can not cast to java.lang.Double, from class org.bson.types.Decimal128错误,以下是具体的代码:

@SpringBootTest
public class BigDecimalTest {

    @Autowired
    private ImportBatchDetailRepo importBatchDetailRepo;
    @Test
    public void testBigDecimal() {
        ImportBatchDetailDO importBatchDetailDO = importBatchDetailRepo.findById("64dc97577e47e340a7165e0b");
        JSONObject data = importBatchDetailDO.getData();
        ImportRefinedMO javaObject = data.toJavaObject(ImportRefinedMO.class);

    }
}

@Getter
@Setter
public class ImportBatchDetailDO {

    private String syncImportTaskId;
    private JSONObject data;

}

@Getter
@Setter
public class ImportRefinedMO {

    private Double holidayHour;
}

请描述你建议的实现方案

只要优化TypeUtils.cast这个方法,增加支持从org.bson.types.Decimal128转为Double就可以了,以下是具体的代码可能实现并不是最优美的方式,但是以下这个实现经过我的测试是可以解决我上面这个问题,在TypeUtils类的1525行增加以下代码:

        String objClassName = obj.getClass().getName();
        if (obj instanceof Number && objClassName.equals("org.bson.types.Decimal128") && targetClass == Double.class) {
            ObjectWriter objectWriter = JSONFactory
                    .getDefaultObjectWriterProvider()
                    .getObjectWriter(obj.getClass());
            if (objectWriter instanceof ObjectWriterPrimitiveImpl) {
                Function function = ((ObjectWriterPrimitiveImpl<?>) objectWriter).getFunction();
                if (function != null) {
                    Object apply = function.apply(obj);
                    Function DecimalTypeConvert = provider.getTypeConvert(apply.getClass(), targetClass);
                    if (DecimalTypeConvert != null) {
                        return (T) DecimalTypeConvert.apply(obj);
                    }
                }
            }
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions