使用Base64编解码时,Long.valueOf(stateMap.get("time"))为何抛出ClassCastException
问题根源
咱们先拆解下代码里的核心矛盾:
在
jsonBase64Encode方法中,你把Map里的Long值转成了String存入JSONObject:jsonObject.put(key, stateMap.get(key).toString());这就导致最终生成的JSON里,所有原本的Long数值都变成了字符串格式——比如
"time":"1699999999999",而不是预期的数字类型"time":1699999999999。到了解码环节,你用Gson把JSON字符串解析成
HashMap<String, Object>,却直接返回Map<String, Long>。这时候Map里的"time"值实际是String类型,当你执行Long.valueOf(decodedMap.get("time"))时,相当于把String对象强行传给需要Long参数的方法,自然触发了ClassCastException。
解决方案
这里有两种靠谱的修复方式,你可以根据实际场景选择:
方案1:统一编码解码的类型逻辑(推荐)
直接修改编码逻辑,保留Long的数值类型存入JSONObject,这样解码时Gson能自动解析成Long,彻底避免类型不匹配问题:
@SuppressWarnings("unchecked") public static String jsonBase64Encode(Map<String, Long> stateMap){ if(stateMap == null) return ""; JSONObject jsonObject = new JSONObject(); for( String key : stateMap.keySet() ){ // 去掉toString(),直接存入Long类型值 jsonObject.put(key, stateMap.get(key)); } byte[] jsonBytes = jsonObject.toString().getBytes(); try { return Base64.getEncoder().encodeToString(jsonBytes); } catch (Exception e) { return ""; } }
同时把解码方法的TypeToken泛型改成HashMap<String, Long>,让Gson直接解析出Long类型的Map:
public static Map<String, Long> jsonBase64Decode(String state) { if(StringUtils.isBlank(state)) return null; String decodedStr = null; try { byte[] decodedBytes = Base64.getDecoder().decode(state); decodedStr = new String(decodedBytes); } catch (Exception e) { return null; } if(StringUtils.isEmpty(decodedStr)) return null; // 修改泛型为<String, Long>,匹配原始Map的类型 Map<String, Long> stateMap = new Gson().fromJson(decodedStr, new TypeToken<HashMap<String, Long>>() {}.getType()); return stateMap; }
之后主方法里直接取值即可,不需要额外转换:
long tokenTime = decodedMap.get("time");
方案2:如果必须保留编码时转String的逻辑
如果因为特殊需求不能修改编码逻辑,那就在取值时手动把String转成Long:
// 替换原有的报错行 long tokenTime = Long.parseLong(decodedMap.get("time").toString());
不过这种方式需要确保"time"对应的字符串一定是合法的数字,否则会抛出NumberFormatException,不如方案1稳妥。
额外小建议
尽量保持编码和解码的类型一致,减少不必要的类型转换,既能降低出错概率,也能让代码更易维护。如果需要更严谨,还可以在解码方法中加入类型校验,提前处理不符合预期的情况。
内容的提问来源于stack exchange,提问作者surendrapanday

