我们都知道,Jackson JSON以高速、方便和灵活著称。之前的文章中介绍过使用注解的形式来规定如何将一个对象序列化成JSON的方法,以及如何将一个JSON数据反序列化到一个对象上。但是美中不足的一点就是对于中文的处理。当然我说的美中不足是在默认情况下,Jackson JSON不会将中文等非ASCII字符转换为\uFFFF这样的形式来显示。也就是说默认情况下会显示为{"name":"张三"}而不是{"name":"\u5F20\u4E09"}。那么为什么有这样的需求呢?在HTTP协议中,我们可以指定数据头部分的内容编码。如:“GBK”、“UTF-8”等等。如果你设置正确了,那么OK,前者所表示的数据您可以正确处理。然而如果设置错误,对于中文字符将会产生乱码。两套应用系统对接,有可能两边使用的默认编码不同,如果一方修改默认编码将会对应用造成不可预知的后果。因此若能以长远的眼光开发,那么无论您设置成什么编码方式,都不会使数据产生乱码。因为,这里用到了万国编码——Unicode。

好的,问题出来了,我们如何解决呢?使其通过实验,Jackson JSON其实在默认设置下已经具备了对Unicode编码的JSON数据进行解析。所欠缺的就是在序列化对象时缺少相应的步骤。好在Jackson JSON框架允许我们自定义序列化方法。那么我们就来写一个序列化类:

复制代码代码如下:

import java.io.IOException;

import org.codehaus.jackson.JsonGenerationException;

import org.codehaus.jackson.JsonGenerator;

import org.codehaus.jackson.JsonProcessingException;

import org.codehaus.jackson.impl.JsonWriteContext;

import org.codehaus.jackson.map.JsonSerializer;

import org.codehaus.jackson.map.SerializerProvider;

import org.codehaus.jackson.util.CharTypes;

public class StringUnicodeSerializer extends JsonSerializer {

private final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

private final int[] ESCAPE_CODES = CharTypes.get7BitOutputEscapes();

private void writeUnicodeEscape(JsonGenerator gen, char c) throws IOException {

gen.writeRaw('\\');

gen.writeRaw('u');

gen.writeRaw(HEX_CHARS[(c >> 12) & 0xF]);

gen.writeRaw(HEX_CHARS[(c >> 8) & 0xF]);

gen.writeRaw(HEX_CHARS[(c >> 4) & 0xF]);

gen.writeRaw(HEX_CHARS[c & 0xF]);

}

private void writeShortEscape(JsonGenerator gen, char c) throws IOException {

gen.writeRaw('\\');

gen.writeRaw(c);

}

@Override

public void serialize(String str, JsonGenerator gen,

SerializerProvider provider) throws IOException,

JsonProcessingException {

int status = ((JsonWriteContext) gen.getOutputContext()).writeValue();

switch (status) {

case JsonWriteContext.STATUS_OK_AFTER_COLON:

gen.writeRaw(':');

break;

case JsonWriteContext.STATUS_OK_AFTER_COMMA:

gen.writeRaw(',');

break;

case JsonWriteContext.STATUS_EXPECT_NAME:

throw new JsonGenerationException("Can not write string value here");

}

gen.writeRaw('"');//写入JSON中字符串的开头引号

for (char c : str.toCharArray()) {

if (c >= 0x80){

writeUnicodeEscape(gen, c); // 为所有非ASCII字符生成转义的unicode字符

}else {

// 为ASCII字符中前128个字符使用转义的unicode字符

int code = (c < ESCAPE_CODES.length ? ESCAPE_CODES[c] : 0);

if (code == 0){

gen.writeRaw(c); // 此处不用转义

}else if (code < 0){

writeUnicodeEscape(gen, (char) (-code - 1)); // 通用转义字符

}else {

writeShortEscape(gen, (char) code); // 短转义字符 (\n \t ...)

}

}

}

gen.writeRaw('"');//写入JSON中字符串的结束引号

}

}

这个序列化类将要对应用中所有使用Jackson JSON的地方全都用一种方法来处理字符串类型。光有了方法还不行,还要对它进行注册。让Jackson JSON在序列化对象的时候使用刚刚定义好的方法:

复制代码代码如下:

if (objectMapper== null){

objectMapper= new ObjectMapper();

//当找不到对应的序列化器时 忽略此字段

objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);

//使Jackson JSON支持Unicode编码非ASCII字符

CustomSerializerFactory serializerFactory= new CustomSerializerFactory();

serializerFactory.addSpecificMapping(String.class, new StringUnicodeSerializer());

objectMapper.setSerializerFactory(serializerFactory);

//支持结束

}

接下来我们来做一个测试用的对象,验证我们的代码:

复制代码代码如下:

import java.util.Date;

import net.csdn.blog.chaijunkun.util.DateDeserializer;

import net.csdn.blog.chaijunkun.util.DateSerializer;

import net.csdn.blog.chaijunkun.util.DateTimeDeserializer;

import net.csdn.blog.chaijunkun.util.DateTimeSerializer;

import org.codehaus.jackson.annotate.JsonPropertyOrder;

import org.codehaus.jackson.map.annotate.JsonDeserialize;

import org.codehaus.jackson.map.annotate.JsonSerialize;

@JsonPropertyOrder(alphabetic= false)

public class DemoObj {

private Integer sid;

private String stuName;

private Boolean sex;

@JsonSerialize(using= DateSerializer.class)

@JsonDeserialize(using= DateDeserializer.class)

private Date birthday;

@JsonSerialize(using= DateTimeSerializer.class)

@JsonDeserialize(using= DateTimeDeserializer.class)

private Date logTime;

//Getters and Setters

}

从代码上可以看出,我们并没有对String类型的属性强制指定用何种序列与反序列方法。然后我们来构造测试用例:

复制代码代码如下:

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.Date;

import net.csdn.blog.chaijunkun.json.DemoObj;

import net.csdn.blog.chaijunkun.util.JSONUtil;

import org.apache.log4j.Logger;

public class JSONTest {

private static Logger logger= Logger.getLogger(JSONTest.class);

private static String json= "{\"sid\":2,\"stuName\":\"\u6C5F\u5357Style\",\"sex\":true,\"birthday\":\"2012-07-15\",\"logTime\":\"2012-12-04 19:22:36\"}";

public static void main(String[] args) {

DemoObj objSrc= new DemoObj();

objSrc.setSid(1);

objSrc.setStuName("鸟叔");

objSrc.setSex(true);

Calendar calendar= Calendar.getInstance();

calendar.set(1977, Calendar.DECEMBER, 31, 0, 0, 0);

objSrc.setBirthday(calendar.getTime());

objSrc.setLogTime(new Date());

logger.info(String.format("转换为JSON后的数据:%s", JSONUtil.toJSON(objSrc)));

DemoObj objDes= JSONUtil.fromJSON(json, DemoObj.class);

if(objDes==null){

logger.info("反序列化失败");

}else{

logger.info("反序列化成功");

SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

logger.info(String.format("标识:%d", objDes.getSid()));

logger.info(String.format("姓名:%s", objDes.getStuName()));

logger.info(String.format("性别:%s", objDes.getSex()==true?"男":"女"));

logger.info(String.format("生日:%s", sdf.format(objDes.getBirthday())));

logger.info(String.format("登录日期:%s", sdf.format(objDes.getLogTime())));

}

}

}

看一下输出:

复制代码代码如下:

转换为JSON后的数据:{"sid":1,"stuName":"\u9E1F\u53D4","sex":true,"birthday":"1977-12-31","logTime":"2012-12-04 19:31:57"}

反序列化成功

标识:2

姓名:江南Style

性别:男

生日:2012-07-15 00:00:00

登录日期:2012-12-04 19:22:36

我们看到,已经成功将中文字符显示成为了Unicode编码的数据。同样,我们之前构造的Unicode编码的数据,在不经过任何修改的情况下成功显示出来了。

细心的朋友也许观察到了,在测试用的对象定义代码中,针对同样Date类型的属性“birthday”和“logTime”,我们指定了不同的序列化与反序列化方法。让我们来看烂这两个有什么不同:

复制代码代码如下:

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;

import org.codehaus.jackson.JsonGenerator;

import org.codehaus.jackson.JsonProcessingException;

import org.codehaus.jackson.map.JsonSerializer;

import org.codehaus.jackson.map.SerializerProvider;

public class DateTimeSerializer extends JsonSerializer {

@Override

public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)

throws IOException, JsonProcessingException {

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

String formattedDate= sdf.format(date);

gen.writeString(formattedDate);

}

}

复制代码代码如下:

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.Date;

import org.codehaus.jackson.JsonParser;

import org.codehaus.jackson.JsonProcessingException;

import org.codehaus.jackson.map.DeserializationContext;

import org.codehaus.jackson.map.JsonDeserializer;

public class DateTimeDeserializer extends JsonDeserializer {

@Override

public Date deserialize(JsonParser parser, DeserializationContext context)

throws IOException, JsonProcessingException {

String dateFormat= "yyyy-MM-dd HH:mm:ss";

SimpleDateFormat sdf= new SimpleDateFormat(dateFormat);

try{

String fieldData= parser.getText();

return sdf.parse(fieldData);

}catch (Exception e) {

Calendar ca= Calendar.getInstance();

ca.set(1970, Calendar.JANUARY, 1, 0, 0, 0);

return ca.getTime();

}

}

}

复制代码代码如下:

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;

import org.codehaus.jackson.JsonGenerator;

import org.codehaus.jackson.JsonProcessingException;

import org.codehaus.jackson.map.JsonSerializer;

import org.codehaus.jackson.map.SerializerProvider;

public class DateSerializer extends JsonSerializer {

@Override

public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)

throws IOException, JsonProcessingException {

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

String formattedDate= sdf.format(date);

gen.writeString(formattedDate);

}

}

复制代码代码如下:

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.Date;

import org.codehaus.jackson.JsonParser;

import org.codehaus.jackson.JsonProcessingException;

import org.codehaus.jackson.map.DeserializationContext;

import org.codehaus.jackson.map.JsonDeserializer;

public class DateDeserializer extends JsonDeserializer {

@Override

public Date deserialize(JsonParser parser, DeserializationContext context)

throws IOException, JsonProcessingException {

String dateFormat= "yyyy-MM-dd";

SimpleDateFormat sdf= new SimpleDateFormat(dateFormat);

try{

String fieldData= parser.getText();

return sdf.parse(fieldData);

}catch (Exception e) {

Calendar ca= Calendar.getInstance();

ca.set(1970, Calendar.JANUARY, 1, 0, 0, 0);

return ca.getTime();

}

}

}

从代码我们可以看出,DateTimeSerializer和DateTimeDeserializer比DateSerializer和DateDeserializer细粒度更加高,加入了具体时间的属性。这在应用开发中是很常见的,生日信息我们往往知道年月日就可以了,而登陆时间往往需要得比较详细。从实例中我们可以知道,即便是同一类型,通过制定不同的序列与反序列方法,可以灵活地得到我们想要的数据形态。以上测试用例已经打包。

补充:

最近有一个需求,需要在序列化与反序列化对象的时候对数据进行修改,当发现数据源值为空时需要让生成的JSON显示改字段为“游客”。可是我无论如何指定序列化器与反序列化器都无效。程序根本走不到指定的代码中去。后来我得出结论,Jackson JSON在反序列化对象的时候,若JSON数据中对应属性为null,则不会走自定义的反序列化器;同样地,当你设置对象的某个属性值为null时,在将其序列化成JSON时,也不会走自定义的序列化器。因此若有类似的需求,请在序列化与反序列化之前通过硬代码形式判断和修改,千万不要什么事都指望着序列化器与反序列化器。

java jackson unicode_如何让Jackson JSON生成的数据包含的中文以unicode方式编码相关推荐

  1. 让Jackson JSON生成的数据包含的中文以unicode方式编码

    本文出处:http://blog.csdn.net/chaijunkun/article/details/8257209,转载请注明.由于本人不定期会整理相关博文,会对相应内容作出完善.因此强烈建议在 ...

  2. Spring MVC--接收JSON格式的数据

    Spring mvc使用开源的Jackson包来处理JSON格式的请求或相应消息. index.jsp <%@ page language="java" contentTyp ...

  3. swagger mock文档服务器,通过 Swagger 定义自动生成 Mock 数据

    我最近的在做的项目是一个前后端分离的项目,前后端由不同的团队分别开发,并且前端的进度经常领先后端.这就意味着,当前端在开发一个新功能时,API 可能还没有准备好.不过,我们会先和后端先商议好 API ...

  4. java中的jackson_Java中的JSON数据绑定框架Jackson使用介绍

    Jackson Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象.在项目中如果要引入Jackson,可以直接利用Maven或者Gra ...

  5. java.lang.NoClassDefFoundError: org/codehaus/jackson/JsonProcessingException(Spring使用json的异常处理)

    java.lang.NoClassDefFoundError: org/codehaus/jackson/JsonProcessingException(Spring使用json的异常处理) 参考文章 ...

  6. java hashmap 实现 序列化_java – Jackson JSON对象映射器反序列化为LinkedHashMap而不是HashMap...

    我有一个有内部地图的POJO.我希望从我的 JSON反序列化为HashMap,但Jackson将内部映射从JSON反序列化为LinkedHashMap.我可以通过将Map的类型从"Map&q ...

  7. Jsonschema2pojo从JSON生成Java类(Maven)

    1.说明 jsonschema2pojo工具可以从JSON Schema(或示例JSON文件)生成Java类型, 并且可以配置生成Jackson 1.x,Jackson 2.x, Moshi 1.x或 ...

  8. 1. 初识Jackson -- 世界上最好的JSON库

    生命太短暂,不要去做一些根本没有人想要的东西.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习 ...

  9. 7. Jackson用树模型处理JSON是必备技能,不信你看

    每棵大树,都曾只是一粒种子.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[BA ...

最新文章

  1. mysql workbench ssh_通过MySQL Workbench进行SSH隧道
  2. javascript写计数器
  3. 文献记录(part57)--半监督学习方法
  4. java8新特性(2)--接口的默认方法
  5. libjson文档翻译
  6. 转载 2012年游戏行业人才需求预测
  7. 比ISA更简单的监管利器,谈谈关于公司上网监管的一点事儿
  8. vnc连接linux颜色灰色,关于vnc登录界面为灰色解决办法【p13】.pdf
  9. 高等数学——常用不定积分公式
  10. 水处理过滤器运行特性及选择原则浅谈
  11. 【转载】树莓派 Raspberry Pi Pico windows7 串口驱动
  12. wordpress安全_保持WordPress网站安全的48种方法
  13. deepin[idea添加桌面]
  14. MarkDownPad2实用教程及MarkDown常用语法
  15. XBL绑定组建的实例
  16. 数字PAM信号功率谱密度推导
  17. Java中将Map转换为JSON
  18. 阿里云将在2018云栖大会·重庆峰会上推出重磅物联网平台
  19. 香港科技大学计算机实验室,香港科技大学机器人实验室科研项目
  20. 字符串存储的可修改性

热门文章

  1. springboot + shiro之登录人数限制、登录判断重定向、session时间设置
  2. 英特尔放出Linux微代码以修复Meltdown和Spectre漏洞
  3. 第二sprint总结
  4. js scrollTop, 滚动条操作
  5. 黑马程序员_面向对象的三大特征
  6. kali安装步骤失败 选择并安装软件_PhotoShop CS5中文版软件下载+安装详细步骤
  7. 一个服务器启动2套mysql_一个服务器启动两个mysql实例
  8. bom csv java_Java系列化与反系列化
  9. risc 服务器 操作系统,数据中心系统用RISC还是CISC?
  10. 帝国7.5标签+在PHP7.0,帝国CMS7.5支持PHP7.*系列,兼容性更好