alibaba / fastjson

FASTJSON 2.0.x has been released, faster and more secure, recommend you upgrade.
https://github.com/alibaba/fastjson2/wiki/fastjson_1_upgrade_cn
Apache License 2.0
25.76k stars 6.5k forks source link

对包含 BigDecimal 的对象使用多重 `BeanToArray` 特性序列化后,再使用 `SupportArrayToBean` 反序列化报错 #2835

Open qyvlik opened 5 years ago

qyvlik commented 5 years ago

fastjson 使用 BeanToArray 可以正常序列化,使用 SupportArrayToBean 反序列化却报错 fastjson 版本:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.61</version>
        </dependency>

如下是 testcase

package io.github.qyvlik.oce.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.List;

public class ComplexBeanArrayTestCase {

    private final Integer ORDER_SIDE_SELL = 1;
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Test
    public void testLevel1Change2() {
        Level1Change level1Change = new Level1Change();
        level1Change.setMarket("btc-usdt");
        level1Change.setSeqId(19L);
        level1Change.setSeqTime(1572231998359L);

        Ticker ticker = new Ticker();
        ticker.setDealId(11L);
        ticker.setMarket("btc-usdt");
        ticker.setTs(1572231998357L);
        ticker.setLatest(new BigDecimal("9730.000000000000000000"));
        ticker.setAsk1(Lists.newArrayList("9730", "0.11"));
        ticker.setBid1(Lists.newArrayList());
        level1Change.setTicker(ticker);

        level1Change.setFullDepth(true);
        level1Change.setFactor(-1);

        List<DepthItemChange> changes = Lists.newLinkedList();
        DepthItemChange change0 = new DepthItemChange();
        change0.setId(11L);
        change0.setSide(ORDER_SIDE_SELL);
        change0.setAction("update");
        change0.setPrice(new BigDecimal("9740.000000000000000000"));
        change0.setAmount(new BigDecimal("0.22"));
        changes.add(change0);

        DepthItemChange change1 = new DepthItemChange();
        change1.setId(12L);
        change1.setSide(ORDER_SIDE_SELL);
        change1.setAction("create");
        change1.setPrice(new BigDecimal("9730.000000000000000000"));
        change1.setAmount(new BigDecimal("0.11"));
        changes.add(change1);

        level1Change.setDepth(changes);

        String jsonStr = JSON.toJSONString(level1Change);

        logger.info("jsonStr:{}", jsonStr);

        String level1datajson = "[\"btc-usdt\",19,1572231998359," +
                "[11,\"btc-usdt\",1572231998357,9730.000000000000000000,[\"9730\",\"0.11\"],[]]," +
                "true," +
                "-1," +
                "[" +
                "[11,1,\"update\",9740.000000000000000000,0.22]," +
                "[12,1,\"create\",9730.000000000000000000,0.11]]" +
                "]";

        Assert.assertEquals(level1datajson, jsonStr);

        Level1Change level1ChangeObj = JSON.parseObject(level1datajson, Level1Change.class, Feature.SupportArrayToBean);
        logger.info("level1Change:{}", level1ChangeObj);
    }

    @JSONType(orders =
            {
                    "id",
                    "side",
                    "action",
                    "price",
                    "amount"
            },
            serialzeFeatures = SerializerFeature.BeanToArray,
            parseFeatures = Feature.SupportArrayToBean)
    public static class DepthItemChange {
        private Long id;
        private Integer side;
        private String action;
        private BigDecimal price;
        private BigDecimal amount;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public Integer getSide() {
            return side;
        }

        public void setSide(Integer side) {
            this.side = side;
        }

        public String getAction() {
            return action;
        }

        public void setAction(String action) {
            this.action = action;
        }

        public BigDecimal getPrice() {
            return price;
        }

        public void setPrice(BigDecimal price) {
            this.price = price;
        }

        public BigDecimal getAmount() {
            return amount;
        }

        public void setAmount(BigDecimal amount) {
            this.amount = amount;
        }
    }

    @JSONType(orders =
            {
                    "dealId",
                    "market",
                    "ts",
                    "latest",
                    "ask1",
                    "bid1"
            },
            serialzeFeatures = SerializerFeature.BeanToArray,
            parseFeatures = Feature.SupportArrayToBean)
    public static class Ticker {
        private Long dealId;            // 最后成交 id
        private String market;          // 交易对
        private Long ts;                // 时间戳
        private BigDecimal latest;      // 最后成交价
        private List<String> ask1;      // 卖一
        private List<String> bid1;      // 买一

        public Long getDealId() {
            return dealId;
        }

        public void setDealId(Long dealId) {
            this.dealId = dealId;
        }

        public String getMarket() {
            return market;
        }

        public void setMarket(String market) {
            this.market = market;
        }

        public Long getTs() {
            return ts;
        }

        public void setTs(Long ts) {
            this.ts = ts;
        }

        public BigDecimal getLatest() {
            return latest;
        }

        public void setLatest(BigDecimal latest) {
            this.latest = latest;
        }

        public List<String> getAsk1() {
            return ask1;
        }

        public void setAsk1(List<String> ask1) {
            this.ask1 = ask1;
        }

        public List<String> getBid1() {
            return bid1;
        }

        public void setBid1(List<String> bid1) {
            this.bid1 = bid1;
        }
    }

    @JSONType(orders =
            {
                    "market",
                    "seqId",
                    "seqTime",
                    "ticker",
                    "fullDepth",
                    "factor",
                    "depth"
            },
            serialzeFeatures = SerializerFeature.BeanToArray,
            parseFeatures = Feature.SupportArrayToBean)
    public static class Level1Change {
        private String market;
        private Long seqId;
        private Long seqTime;
        private Ticker ticker;
        private Boolean fullDepth;
        private Integer factor;
        private List<DepthItemChange> depth;

        public String getMarket() {
            return market;
        }

        public void setMarket(String market) {
            this.market = market;
        }

        public Long getSeqId() {
            return seqId;
        }

        public void setSeqId(Long seqId) {
            this.seqId = seqId;
        }

        public Long getSeqTime() {
            return seqTime;
        }

        public void setSeqTime(Long seqTime) {
            this.seqTime = seqTime;
        }

        public Ticker getTicker() {
            return ticker;
        }

        public void setTicker(Ticker ticker) {
            this.ticker = ticker;
        }

        public Boolean getFullDepth() {
            return fullDepth;
        }

        public void setFullDepth(Boolean fullDepth) {
            this.fullDepth = fullDepth;
        }

        public Integer getFactor() {
            return factor;
        }

        public void setFactor(Integer factor) {
            this.factor = factor;
        }

        public List<DepthItemChange> getDepth() {
            return depth;
        }

        public void setDepth(List<DepthItemChange> depth) {
            this.depth = depth;
        }
    }
}

报错输出:

12:10:33.228 [main] INFO io.github.qyvlik.oce.utils.ComplexBeanArrayTestCase - jsonStr:["btc-usdt",19,1572231998359,[11,"btc-usdt",1572231998357,9730.000000000000000000,["9730","0.11"],[]],true,-1,[[11,1,"update",9740.000000000000000000,0.22],[12,1,"create",9730.000000000000000000,0.11]]]

com.alibaba.fastjson.JSONException: syntax error, expect [, actual [

    at com.alibaba.fastjson.parser.DefaultJSONParser.throwException(DefaultJSONParser.java:1508)
    at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseArray(JavaBeanDeserializer.java:1620)
    at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_1_Level1Change.deserialzeArrayMapping(Unknown Source)
    at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_1_Level1Change.deserialze(Unknown Source)
    at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:284)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:682)
    at com.alibaba.fastjson.JSON.parseObject(JSON.java:383)
    at com.alibaba.fastjson.JSON.parseObject(JSON.java:287)
    at io.github.qyvlik.oce.utils.ComplexBeanArrayTestCase.testLevel1Change2(ComplexBeanArrayTestCase.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
qyvlik commented 5 years ago

临时解决方案如下,将 DepthItemChange 中的 BigDecimal 类型都修改为 String 类型。

    @JSONType(orders =
            {
                    "id",
                    "side",
                    "action",
                    "price",
                    "amount"
            },
            serialzeFeatures = SerializerFeature.BeanToArray,
            parseFeatures = Feature.SupportArrayToBean)
    public static class DepthItemChange {
        private Long id;
        private Integer side;
        private String action;
        private String price;
        private String amount;
}