問題場景
在使用java的Long類型過程中,當(dāng)這個Long類型數(shù)值超過 1^0+1^1+1^2+...1^58的范圍后就會引發(fā)精度丟失, 詳見JS[IEEE754規(guī)范](https://en.wikipedia.org/wiki/IEEE_754)
常見的現(xiàn)象就是比如:1000967854800048128,通過js轉(zhuǎn)換成Number類型成為了:1000967854800048100, 由此會引發(fā)一系列問題,比如當(dāng)年著名的愛國者導(dǎo)彈.
因為精度缺失造成問題,大多數(shù)情況發(fā)生在前后端交互過程中,那么下面就分別說說處理方法
普通場景的處理方法
簡單的處理方法忱详,jackson,gson等json工具包已經(jīng)包含了Long類型處理方法了,基本上都是轉(zhuǎn)String.
gson處理方法
GsonBuilder builder = new GsonBuilder();
//默認將所有的Long轉(zhuǎn)換成String
builder.setLongSerializationPolicy(LongSerializationPolicy.STRING);
jackson處理方法
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Long.class, ToStringSerializer.instance);
module.addSerializer(Long.TYPE, ToStringSerializer.instance);
高級場景處理
為了避免將其他無需轉(zhuǎn)換成String的Long類型轉(zhuǎn)換,這里提供一個高級的用法戈抄,
思路很簡單就是定義一個Id類型,通過實現(xiàn)Id類型的序列化和反序列化功能即可進行實現(xiàn).
下面就用Gson和jackson來演示
核心代碼
//Gson
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Id.class, (JsonSerializer<Id>) (src, typeOfSrc, context) ->
new JsonPrimitive(src.getVal()));
builder.registerTypeAdapter(Id.class, (JsonDeserializer<Id>) (json, typeOfT, context) ->
new Id(json.getAsLong()));
Gson gson = builder.create();
User user = new User();
user.setUserId(new Id(11111L));
user.setUserName("youkale.github.io");
String s = gson.toJson(user);
System.out.println(s);
User user1 = gson.fromJson(s, User.class);
System.out.println("gson " + user1);
//Jackson
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Id.class, new IdJacksonSerializer(Id.class));
module.addDeserializer(Id.class, new IdJacksonDeserializer(Id.class));
objectMapper.registerModule(module);
String s1 = objectMapper.writeValueAsString(user);
System.out.println(s1);
User user2 = objectMapper.readValue(s1, User.class);
System.out.println("jackson " + user2);
定義類User
public static class User {
private Id userId;
private String userName;
public Id getUserId() {
return userId;
}
public void setUserId(Id userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
'}';
}
}
定義Id類
public static class Id {
private final Long val;
public Long getVal() {
return val;
}
public Id(Long val) {
this.val = val;
}
@Override
public String toString() {
return String.valueOf(val);
}
}
jackson序列反序列實現(xiàn)
public static class IdJacksonDeserializer extends StdDeserializer<Id> {
public IdJacksonDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Id deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return new Id(p.getValueAsLong());
}
}
public static class IdJacksonSerializer extends StdSerializer<Id> {
public IdJacksonSerializer(Class<Id> t) {
super(t);
}
@Override
public void serialize(Id value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(String.valueOf(value.getVal()));
}
}
總結(jié)
從Gson和jackson的API看出這類的功能老早就由大神們想到了,有時候總在感嘆,自己多渺小.