alibaba / fastjson2

🚄 FASTJSON2 is a Java JSON library with excellent performance.
Apache License 2.0
3.69k stars 478 forks source link

[BUG]JSONB开启FieldBased和NotWriteHashMapArrayListClassName序列化后再反序列化时存在问题 #2691

Closed rowstop closed 2 months ago

rowstop commented 3 months ago

当存在一个默认值是不可变的 List 字段时存在问题(使用场景:dubbo 响应了一个 mybatis plus分页结果的Page对象)

public class Page<T> implements IPage<T> {
    /**
     * 查询数据列表
     */
    protected List<T> records = Collections.emptyList();
}
java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)
    at com.alibaba.fastjson2.reader.ORG_1_1_UnmodifiableList.readJSONBObject(Unknown Source)
    at com.alibaba.fastjson2.JSONB.parseObject(JSONB.java:799)
    at com.alibaba.fastjson2.issues_2600.MybatisPlusPageTest.writeReade(MybatisPlusPageTest.java:70)
    at com.alibaba.fastjson2.issues_2600.MybatisPlusPageTest.testUnmodifiableList(MybatisPlusPageTest.java:46)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at java.util.ArrayList.forEach(ArrayList.java:1259)

经检查是这段代码取了默认值,后面调用了它的 add 方法 com.alibaba.fastjson2.reader.ObjectReaderCreatorASM:3737 image 复现代码

package com.alibaba.fastjson2.issues_2600;

import com.alibaba.fastjson2.JSONB;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.internal.asm.MethodWriter;
import com.alibaba.fastjson2.reader.FieldReader;
import com.alibaba.fastjson2.reader.ObjectReaderCreatorASM;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.dubbo.common.serialize.fastjson2.FastJson2ObjectInput;
import org.apache.dubbo.common.serialize.fastjson2.FastJson2ObjectOutput;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Type;
import java.util.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
 * @author 张治保
 * @since 2024/6/12
 */
public class Issue2691 {

    /**
     *  failed
     * @see Page#records
     * @see FastJson2ObjectOutput#writeObject(Object)
     * @see FastJson2ObjectInput#readObject(Class)
     * @see ObjectReaderCreatorASM#genReadFieldValueList(FieldReader, String, MethodWriter, int, int, int, int, int, Map, int, int, int, boolean, boolean, Class, Class, Type, long, Type, String, Integer)
     */
    @Test
    void testUnmodifiableList() {
        UnmodifiableList list = new UnmodifiableList();
        ArrayList<String> strings = new ArrayList<>();
        strings.add("1");
        list.setList(strings);
        writeReade(list);
    }

    /**
     * passed
     */
    @Test
    void testUnmodifiableMap(){
        UnmodifiableMap map = new UnmodifiableMap();
        Map<String,String> stringMap = new HashMap<>();
        stringMap.put("1","1");
        map.setMap(stringMap);
        writeReade(map);
    }

    /**
     * passed
     */
    @Test
    void testUnmodifiableSet(){
        UnmodifiableSet set = new UnmodifiableSet();
        Set<String> stringSet = new HashSet<>();
        stringSet.add("1");
        set.setSet(stringSet);
        writeReade(set);
    }

    void writeReade(Object value){
        byte[] bytes = JSONB.toBytes(
                value,
                JSONWriter.Feature.WriteClassName,
                JSONWriter.Feature.FieldBased,
                JSONWriter.Feature.NotWriteHashMapArrayListClassName
        );

        // readObject
        Object result = JSONB.parseObject(
                bytes,
                value.getClass(),
                JSONReader.Feature.FieldBased);
        assertNotNull(result);
        assertEquals(result,value);
    }

    @Getter
    @Setter
    @EqualsAndHashCode
    @Accessors(chain = true)
    private static class UnmodifiableList {
        private List<String> list = Collections.emptyList();
    }
    @Getter
    @Setter
    @EqualsAndHashCode
    @Accessors(chain = true)
    private static class UnmodifiableSet {
        private Set<String> set = Collections.emptySet();
    }

    @Getter
    @Setter
    @EqualsAndHashCode
    @Accessors(chain = true)
    private static class UnmodifiableMap {
        private  Map<String,String> map = Collections.emptyMap();
    }
}
wenshao commented 2 months ago

https://github.com/alibaba/fastjson2/releases/tag/2.0.52 问题已修复,请用新版本