由于JSON数据格式的诸多优点,现在就数据传输这个方面已经完胜XML,成为当下比较流行数据传输格式。所以越来越多的项目采用了这种格式进行前后台数据的传送。咱公司后台主要用的是java平台相关的技术,因此在JSON字符串格式与java对象格式的转换上成为了我们平常经常要做的工作。这里给大家分享一下采用JSON-lib来转换JSON字符串与java对象的相关经验。
(一)java对象转换为JSON字符串。
这种情况用碰到的比较多的就是一个指定的java对象转换为期待的字符串格式。比如说Calendar转换为“yyyy-MM-dd HH:mm:ss”格式的字符串,或是Date转换为“yyyy-MM-dd HH:mm:ss”格式的字符串等。此处以Calendar为例说明一下转换方法。
//转换方法
public static String Object2JSONString(Object object) {
if (object == null) {
return null;
}
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Calendar.class, new CalendarJsonValueProcessor());
JSON jsonObject = JSONSerializer.toJSON(object,jsonConfig);
return jsonObject == null ? null :jsonObject.toString();
}
//定义转换所用到的内部类
private static class CalendarJsonValueProcessor implements JsonValueProcessor{
SimpleDateFormat dateFormat = new SimpleDateFormat(TaskEngineConstants.LOG_DATE_FORMAT);
@Override
public Object processArrayValue(Objectobj, JsonConfig jsonconfig){
if (obj == null){
return null;
}
return dateFormat.format(((Calendar)obj).getTime());
}
@Override
public ObjectprocessObjectValue(String s, Object obj, JsonConfig jsonconfig) {
if (obj == null){
return null;
}
return dateFormat.format(((Calendar)obj).getTime());
}
}
(二)JSON字符串转换为java对象。
在要转换的java比较简单的时候,基本上都能顺利转换。下面介绍一种比较特别的情况,也是我们在项目中所碰到的情况。
有一个WSDL的对象HotelBookingInfo, 内有子对象AgeGroup, 它是Axis2生成的一个在WSDL中表示多选一的java类,实际在java中,一般多选一都用枚举。但此处的AgeGroup并非为enum, 而是一个没有public构造函数的class, 如果你要实例化的话可采用AgeGroup.Factory.fromValue(value)方法(Axis2自动生成)。因为在JSON-lib转换字符串为java对象的时候,每碰到java对象的内部属性为新的对象的时候都会先调用其默认的public的构造函数还构造这个对象,再填充值。故在转换的时候如果不做任何处理,转换会失败,报找不到AgeGourp类public构造方法的错误。
解决办法如下:
//转换方法
public static String JSONString2Object(String jsonString){
JSONObject jsonObject = JSONObject.fromObject(jsonString);
// the key point is below
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setNewBeanInstanceStrategy(new HotelNewBeanInstanceStrategy());
jsonConfig.setRootClass(HotelBookingInfo.class);
HotelBookingInfo info = (HotelBookingInfo) JSONObject.toBean(jsonObject,jsonConfig);
}
// 定义内部类用来修改默认的对象构造方式
public static class HotelNewBeanInstanceStrategy extends NewBeanInstanceStrategy {
@Override
public Object newInstance(Classc, JSONObject jo) throws InstantiationException,
IllegalAccessException,SecurityException, NoSuchMethodException, InvocationTargetException {
Object o;
if(c.equals(AddressType.class)) {
String t = jo.get("value").toString();
o = AddressType.Factory.fromValue(t);
}
else if (c.equals(AgeGroup.class)) {
String t = jo.get("value").toString();
o = AgeGroup.Factory.fromValue(t);
}
else {
o = c.newInstance();
}
return o;
}
}
同时在这里还有一个要注意的是JSONObject.toBean(jsonObject, jsonConfig)方法有一个重载方法JSONObject.toBean(jsonObject,HotelBookingInfo.class, jsonConfig)。
如果你使用的是如下代码
JSONObject jsonObject = JSONObject.fromObject(dto.getReservationDetails());
// convert detail to info.
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setNewBeanInstanceStrategy(newHotelNewBeanInstanceStrategy());
HotelBookingInfo info = (HotelBookingInfo)JSONObject.toBean(jsonObject, HotelBookingInfo.class, jsonConfig);
(一)java对象转换为JSON字符串。
这种情况用碰到的比较多的就是一个指定的java对象转换为期待的字符串格式。比如说Calendar转换为“yyyy-MM-dd HH:mm:ss”格式的字符串,或是Date转换为“yyyy-MM-dd HH:mm:ss”格式的字符串等。此处以Calendar为例说明一下转换方法。
//转换方法
public static String Object2JSONString(Object object) {
if (object == null) {
return null;
}
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Calendar.class, new CalendarJsonValueProcessor());
JSON jsonObject = JSONSerializer.toJSON(object,jsonConfig);
return jsonObject == null ? null :jsonObject.toString();
}
//定义转换所用到的内部类
private static class CalendarJsonValueProcessor implements JsonValueProcessor{
SimpleDateFormat dateFormat = new SimpleDateFormat(TaskEngineConstants.LOG_DATE_FORMAT);
@Override
public Object processArrayValue(Objectobj, JsonConfig jsonconfig){
if (obj == null){
return null;
}
return dateFormat.format(((Calendar)obj).getTime());
}
@Override
public ObjectprocessObjectValue(String s, Object obj, JsonConfig jsonconfig) {
if (obj == null){
return null;
}
return dateFormat.format(((Calendar)obj).getTime());
}
}
(二)JSON字符串转换为java对象。
在要转换的java比较简单的时候,基本上都能顺利转换。下面介绍一种比较特别的情况,也是我们在项目中所碰到的情况。
有一个WSDL的对象HotelBookingInfo, 内有子对象AgeGroup, 它是Axis2生成的一个在WSDL中表示多选一的java类,实际在java中,一般多选一都用枚举。但此处的AgeGroup并非为enum, 而是一个没有public构造函数的class, 如果你要实例化的话可采用AgeGroup.Factory.fromValue(value)方法(Axis2自动生成)。因为在JSON-lib转换字符串为java对象的时候,每碰到java对象的内部属性为新的对象的时候都会先调用其默认的public的构造函数还构造这个对象,再填充值。故在转换的时候如果不做任何处理,转换会失败,报找不到AgeGourp类public构造方法的错误。
解决办法如下:
//转换方法
public static String JSONString2Object(String jsonString){
JSONObject jsonObject = JSONObject.fromObject(jsonString);
// the key point is below
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setNewBeanInstanceStrategy(new HotelNewBeanInstanceStrategy());
jsonConfig.setRootClass(HotelBookingInfo.class);
HotelBookingInfo info = (HotelBookingInfo) JSONObject.toBean(jsonObject,jsonConfig);
}
// 定义内部类用来修改默认的对象构造方式
public static class HotelNewBeanInstanceStrategy extends NewBeanInstanceStrategy {
@Override
public Object newInstance(Classc, JSONObject jo) throws InstantiationException,
IllegalAccessException,SecurityException, NoSuchMethodException, InvocationTargetException {
Object o;
if(c.equals(AddressType.class)) {
String t = jo.get("value").toString();
o = AddressType.Factory.fromValue(t);
}
else if (c.equals(AgeGroup.class)) {
String t = jo.get("value").toString();
o = AgeGroup.Factory.fromValue(t);
}
else {
o = c.newInstance();
}
return o;
}
}
同时在这里还有一个要注意的是JSONObject.toBean(jsonObject, jsonConfig)方法有一个重载方法JSONObject.toBean(jsonObject,HotelBookingInfo.class, jsonConfig)。
如果你使用的是如下代码
JSONObject jsonObject = JSONObject.fromObject(dto.getReservationDetails());
// convert detail to info.
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setNewBeanInstanceStrategy(newHotelNewBeanInstanceStrategy());
HotelBookingInfo info = (HotelBookingInfo)JSONObject.toBean(jsonObject, HotelBookingInfo.class, jsonConfig);
看起来和上面的写法差不多,但是这种方式下会抛异常(java.lang.ClassCastException: java.lang.Class cannot be cast tocom.telenav.ws.datatypes.hotel.v10.HotelBookingInfo)。于是反编译了一下代码,发现两个重载方法是各自写的实现,表面上得出结果应该是一样的,但是事实上这种做法存在上述问题,记得以前也碰到过。所以大家注意一下类似问题。