JsonParseException: Unexpected character (‘a‘ (code 97)): Expected space separating root-level value

1. 异常场景

项目初始集成redis使用的是默认的lettuce客户端,后来因为业务需要切换成redisson客户端
使用redisson客户端后获取原先存入redis中的值出现了报错:
JsonParseException: Unexpected character (‘a’ (code 97)): Expected space separating root-level value

2. 解决方案

2.1 设置编解码格式StringCodec

获取所有数据的时候,无引号字符串无法通过JsonJacksonCodec进行解析导致后续报错,所以可以通过设置Codec的方式来进行处理

RMap<String, Object> map = redissonClient.getMap("key", StringCodec.INSTANCE);
Set<Map.Entry<String, Object>> entries = map.readAllEntrySet();

缺点:如果原始数据中value存储的是对象,通过设置StringCodec取出的值也会是字符串格式,需要额外进行序列化操作。

2.1 自定义编码格式

默认JacksonCodec编码初始化包含有对象转换设置

protected void init(ObjectMapper objectMapper) {
    objectMapper.setSerializationInclusion(Include.NON_NULL);
    objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker().withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE).withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE));
    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    objectMapper.enable(new JsonGenerator.Feature[]{Feature.WRITE_BIGDECIMAL_AS_PLAIN});
    objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    objectMapper.enable(new MapperFeature[]{MapperFeature.SORT_PROPERTIES_ALPHABETICALLY});
}

自定义Codec

public class RedissonCodec extends BaseCodec {

    protected final ObjectMapper mapObjectMapper;

    /**
     * @see
     */
    private final Encoder encoder = new Encoder() {
        @Override
        public ByteBuf encode(Object in) throws IOException {
            ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
            try {
                ByteBufOutputStream os = new ByteBufOutputStream(out);
                mapObjectMapper.writeValue((OutputStream) os, in);
                return os.buffer();
            } catch (IOException e) {
                out.release();
                throw e;
            } catch (Exception e) {
                out.release();
                throw new IOException(e);
            }
        }
    };

    private final Decoder<Object> decoder = new Decoder<Object>() {
        @Override
        public Object decode(ByteBuf buf, State state) throws IOException {
            return mapObjectMapper.readValue((InputStream) new ByteBufInputStream(buf), Object.class);
        }
    };

    public RedissonCodec(ObjectMapper mapObjectMapper) {
        this(mapObjectMapper, true);
    }

    public RedissonCodec(ObjectMapper mapObjectMapper, boolean copy) {
        if (copy) {
            this.mapObjectMapper = mapObjectMapper.copy();
        } else {
            this.mapObjectMapper = mapObjectMapper;
        }
    }

    @Override
    public Decoder<Object> getValueDecoder() {
        return decoder;
    }

    @Override
    public Encoder getValueEncoder() {
        return encoder;
    }

    @Override
    public ClassLoader getClassLoader() {
        if (mapObjectMapper.getTypeFactory().getClassLoader() != null) {
            return mapObjectMapper.getTypeFactory().getClassLoader();
        }
        return super.getClassLoader();
    }
}

自定义utils类

public final class RedisUtils {

    public static final Codec REDISSON_CODEC;

    static {
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        REDISSON_CODEC = new RedissonCodec(om);
    }

    private RedisUtils() {}
}

访问发现还存在报错:

ERROR 20964 --- [isson-netty-2-2] o.r.client.handler.CommandDecoder   : Unable to decode data. channel: [id: 0x0d57606b, L:/127.0.0.1:49377 - R:127.0.0.1/127.0.0.1:6379], reply: ReplayingDecoderByteBuf(ridx=47, widx=3583080), command: (HGETALL), promise: java.util.concurrent.CompletableFuture@6727c964[Not completed, 1 dependents], params: [SYS:USER]
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('a' (code 97)): Expected space separating root-level values
 at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 12]

还是存在拜纳姆解析问题,显示的JsonParseException解析异常,查看redis中数据,分析原因为hashkey为无引号字符串导致,因此需要额外处理一下hashkey键。

RedissonCodec中添加合适编解码对象

	private final Decoder<Object> mapKeyDecoder = new Decoder<Object>() {
	   public Object decode(ByteBuf buf, State state) {
	        String str = buf.toString(CharsetUtil.UTF_8);
	        buf.readerIndex(buf.readableBytes());
	        return str;
	    }
	};
	
	private final Encoder mapKeyEncoder = new Encoder() {
	    public ByteBuf encode(Object in) throws IOException {
	        ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
	        out.writeCharSequence(in.toString(), CharsetUtil.UTF_8);
	        return out;
	    }
	};
	
	@Override
	public Decoder<Object> getMapKeyDecoder() {
	    return mapKeyDecoder;
	}
	
	@Override
	public Encoder getMapKeyEncoder() {
	    return mapKeyEncoder;
	}

获取数据代码:

   RMap<String, Object> map = redissonClient.getMap("key", RedisUtils.REDISSON_CODEC);
   Set<Map.Entry<String, Object>> entries = map.readAllEntrySet();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值