最近遇到一个错误,就是某个字段肯定是Long类型的,通过Map方式转成JSON字符串,然后存到了DB的某个字段里。
为了Json存储字,然后反序列化为Map(不是自定义的常规对象)
比如某二方为了提供通用的接口能力,将Map的数据通过JSON序列化方式缓存然后JSON反序列化拿到Map。
等情况。
用的时候就通过Key获取对象之后直接强转Long,然后类型转换异常。
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
@Test(expected = ClassCastException.class)
public void testJson() {
String id = "id";
String name = "name";
Long idValue = 3000L;
Map data = new HashMap<>(2);
data.put(id, idValue);
data.put(name, "张三");
Assert.assertEquals(idValue, (Long) data.get(id));
String jsonString = JSON.toJSONString(data);
// 反序列化时Long被转为了Integer
Map map = JSON.parseObject(jsonString, Map.class);
Object idObj = map.get(id);
Assert.assertTrue(idObj instanceof Integer);
Assert.assertEquals(idValue, (Long) idObj);
}
没用通过JSON序列化,虽然类型为Object,但是实际的类型为Long。
序列化为Json时后,Josn串是没有 Long类型的,而且反转回来也是Object接收,如果数字小于Interger的最大值,给转成了Integer!
3.1 采用JDK自带的序列化。
https://blog.csdn.net/outsanding/article/details/80963646 提到“redis工具,在存java对象的时候,需要实体实现序列化。工具这样设计肯定有理由的。”估计大家知道啥理由了吧。
public class JDKSerializeUtil {
public static byte[] serialize(Object object) {
ObjectOutputStream objectOutputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Object deserialization(byte[] binaryByte) {
ObjectInputStream objectInputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
byteArrayInputStream = new ByteArrayInputStream(binaryByte);
try {
objectInputStream = new ObjectInputStream(byteArrayInputStream);
return objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class JDKSerializeUtilTest {
private Map map = new HashMap<>();
@Before
public void init() {
map.put("id", 200L);
map.put("name", "张三");
}
@Test
public void serialize() {
}
@Test
public void unserizlize() {
byte[] serialize = JDKSerializationUtil.serialize(map);
Object deserialize = JDKSerializationUtil.deserialization(serialize);
Map map = (Map) deserialize;
Object id = map.get("id");
Assert.assertEquals(java.lang.Long.class, id.getClass());
}
}
3.2 避免使用通用的对象类型
自定义一个强类型的对象来传递数据。
3.3 使用JSON自带的转换工具
@Data
public class User {
private Long id;
private String name;
}
@Test
public void testJson2() {
String id = "id";
String name = "name";
Long idValue = 3000L;
Map data = new HashMap<>(2);
data.put(id, idValue);
data.put(name, "张三");
Assert.assertEquals(idValue, (Long) data.get(id));
String jsonString = JSON.toJSONString(data);
// 反序列化时Long被转为了Integer
Map map = JSON.parseObject(jsonString, Map.class);
// 转换成 User时 Integer 转为了Long
User user = JSON.toJavaObject(new JSONObject(map), User.class);
System.out.println(user);
}
3.4 手动转换
手动将 Map 转为目标对象,此时注意 Long 可能降级为 Integer,特殊处理即可。
总之开发中尽量不要乱用一些对象属性转换工具,导致属性漏掉或者转错。
不要滥用Map或者JSONObject来传递参数。
如果是含Object类型JSON序列化要特别小心上述问题!