class AbstractJsonEncoder extends AbstractValueEncoder {
    public AbstractJsonEncoder(boolean useIdentityNumber) {
        super(useIdentityNumber);
    }

    protected abstract byte[] encodeSingleValue(Object value);

    @Override
    public byte[] apply(Object value) {
        try {
            JsonData[] data = encode(value);
            int len = len(data);
            byte[] buffer = useIdentityNumber ? new byte[len + 4] : new byte[len];
            int index = 0;
            if (useIdentityNumber) {
                index = writeInt(buffer, index, SerialPolicy.IDENTITY_NUMBER_FASTJSON2);
            }
            if (data == null) {
                writeShort(buffer, index, -1);
            } else {
                index = writeShort(buffer, index, data.length);
                for (JsonData d : data) {
                    if (d == null) {
                        index = writeShort(buffer, index, -1);
                    } else {
                        index = writeShort(buffer, index, d.getClassName().length);
                        index = writeBytes(buffer, index, d.getClassName());
                        index = writeInt(buffer, index, d.getData().length);
                        index = writeBytes(buffer, index, d.getData());
                    }
                }
            }
            return buffer;
        } catch (Throwable e) {
            StringBuilder sb = new StringBuilder("Fastjson Encode error. ");
            sb.append("msg=").append(e.getMessage());
            throw new CacheEncodeException(sb.toString(), e);
        }
    }

    private int len(JsonData[] data) {
        if (data == null) {
            return 2;
        }
        int x = 2;
        for (JsonData d : data) {
            if (d == null) {
                x += 2;
            } else {
                x += 2 + d.getClassName().length + 4 + d.getData().length;
            }
        }
        return x;
    }

    private int writeInt(byte[] buf, int index, int value) {
        buf[index] = (byte) (value >> 24 & 0xFF);
        buf[index + 1] = (byte) (value >> 16 & 0xFF);
        buf[index + 2] = (byte) (value >> 8 & 0xFF);
        buf[index + 3] = (byte) (value & 0xFF);
        return index + 4;
    }

    private int writeShort(byte[] buf, int index, int value) {
        buf[index] = (byte) (value >> 8 & 0xFF);
        buf[index + 1] = (byte) (value & 0xFF);
        return index + 2;
    }

    private int writeBytes(byte[] buf, int index, byte[] data) {
        System.arraycopy(data, 0, buf, index, data.length);
        return index + data.length;
    }

    private JsonData[] encode(Object value) {<FILL_FUNCTION_BODY>}

    private JsonData encodeJsonData(Object value) {
        if (value == null) {
            return null;
        }
        JsonData jsonData = new JsonData();
        jsonData.setClassName(value.getClass().getName().getBytes(StandardCharsets.UTF_8));
        jsonData.setData(encodeSingleValue(value));
        return jsonData;
    }

    private static class JsonData {
        private byte[] className;
        private byte[] data;

        public byte[] getClassName() {
            return className;
        }

        public void setClassName(byte[] className) {
            this.className = className;
        }

        public byte[] getData() {
            return data;
        }

        public void setData(byte[] data) {
            this.data = data;
        }
    }
}

        if (value == null) {
            return null;
        }
        if (value instanceof CacheValueHolder) {
            CacheValueHolder h = (CacheValueHolder) value;
            Object bizObject = h.getValue();
            h.setValue(null);
            JsonData[] result = new JsonData[2];
            result[0] = encodeJsonData(h);
            result[1] = encodeJsonData(bizObject);
            h.setValue(bizObject);
            return result;
        } else if (value instanceof CacheMessage) {
            CacheMessage cm = (CacheMessage) value;
            Object[] keys = cm.getKeys();
            cm.setKeys(null);
            JsonData[] result = keys == null ? new JsonData[1] : new JsonData[keys.length + 1];
            result[0] = encodeJsonData(cm);
            if (keys != null) {
                for (int i = 0; i < keys.length; i++) {
                    result[i + 1] = encodeJsonData(keys[i]);
                }
            }
            cm.setKeys(keys);
            return result;
        } else {
            return new JsonData[]{encodeJsonData(value)};
        }
    
<methods>public void <init>(boolean) ,public boolean isUseIdentityNumber() <variables>protected boolean useIdentityNumber