/Files/jonenine/blog.rar本文一共分3个部分,介绍了在web中如何灵活而高效使用json,并同大家分享了实际的代码,希望大家喜欢。
(一) 在jvm中使用json
json的使用在当下已经普及起来了,作者使用json也已经有很长的时间了,早在它普及之前就尝试着在项目中应用它。今天给大家介绍的代码都是实际项目中真实的代码,虽然不尽完美,但却禁得住实际的考验。
Json的意义
(1) 在浏览器和服务器之间传递复杂结构的数据
传统表单提交或是ajax请求,向服务器提交的表单都是“平的”非结构化数据,这种能力早已不能满足现代web项目需求的复杂性。然而,从浏览器收集来的复杂数据通过序列化为json的方式,进而整体提交到服务端是非常合理的解决方案。举例如下:
比如在一个项目中,要将人员编排的情况提交给服务器(这是08年给Sinopec做项目时的实际需求)
var postData = [
{
group1 : {
name : '第一组',
teams:[
{
name:'西部小队',
mamber:[{name:'老王',age:46},
{name:'老李',age:50}]
},
{
name:'突击小分队',
mamber:[]
}
]
}
}
]
$.post("someServlet", {params:$u.encode(postData)},function(){
….
});
在服务器端只需要将HttpServletRequest.getParameter(‘params’)反序列成json在jvm中的表示,详见本文提供的下载。
前端开发的组件化是近年来web开发突飞猛进的重要特点。笔者所在的公司在最近这一两年前也完成了从jsp等模板技术到组件化开发的转变。在面向组件的web开发中(假设大家都熟悉类似于extjs之类的东西),从服务器端传递到浏览器的数据也大多是json。比如可以将将一个grid组件的数据整体encode(json化)传递给浏览器端驱动js脚本框架生成动态dom。
(2)作为数据模型,表达或存储松散的半结构化数据
使用过xml作为数据模型的同学知道,xml虽然可读性强,但编辑解析xml文件都不是一件容易的事情。有的开源框架已经开始从xml转向json,比如avro在配置的部分即是如此。
另外,既然作为数据模型来传递和保存半结构化数据,就应该允许对json对象进行增删改查等操作。浏览器端使用javascript实现不是一件难事,在服务器端也有几种开源框架支持。比如笔者使用的jsonlib (http://sourceforge.net/projects/json-lib/)以及最近比较流行的jackson等。这些框架都提供开箱即用的序列化及反序列化支持。但在jvm中对json数据进行增删改查及属性遍历等操作还是比较麻烦的。下面是笔者在实际项目中使用的类,其封装了jsonlib,可以方便的对json数据进行各种操作,在项目中已经作为核心代码而存在。
package xs.util;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import net.sf.json.util.JSONUtils;
/**
*
* 此类形成一种比较灵活的动态数据模型
*/
public class Json {
public static enum TYPE{
//对象类型
object,
//数组类型
array,
//其他基本类型都为字符串类型,由业务层去打理
string,
//null
nvl
}
//内部封装值
protected JSON json;
/**
* 值---这个值实际上是和json互补的,当表达一个普通的值时json为null,当可以按照json解析时,strValue为null
*/
protected String strValue;
/**
* 类型
*/
private TYPE type;
public TYPE getType() {
return type;
}
//当是对象或数组类型时,可判断是否empty
public Boolean isEmpty(){
if(this.type.equals(TYPE.object) || this.type.equals(TYPE.array)) return json.isEmpty();
//返回null,表示不支持这种类型
return null;
}
private static final SimpleDateFormat dateFm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
{
//要么将时区设置为标准格林威治时区,并调整时间,要么在下面修改为东8区,麻烦
//dateFm.setTimeZone(TimeZone.getTimeZone("GMT+8"));
}
private static final JsonConfig defaultJC=new JsonConfig();
private static final JsonValueProcessor defaultDateValueProcessor=new JsonValueProcessor(){
/**
* 当作为数组或集合的元素时,应如何解析
*/
public Object processArrayValue(Object arg0, JsonConfig arg1) {
Timestamp timeStamp = new java.sql.Timestamp(((java.util.Date)arg0).getTime());
return dateFm.format(timeStamp);
}
/**
* 当作为对象的属性时应该如何解析
*/
public Object processObjectValue(String arg0, Object arg1, JsonConfig arg2) {
if(arg1==null) return "";
Timestamp timeStamp = new java.sql.Timestamp(((java.util.Date)arg1).getTime());
return dateFm.format(timeStamp);
}
};
private static JsonValueProcessor jsonProcessor=new JsonValueProcessor(){
public Object processArrayValue(Object arg0, JsonConfig arg1) {
return ((Json)arg0).toString();
}
public Object processObjectValue(String arg0, Object arg1, JsonConfig arg2) {
if(arg1==null) return "";
return ((Json)arg1).toString();
}
};
static {
/**
* 修改时间类型的序列化方式
*/
defaultJC.registerJsonValueProcessor(java.sql.Timestamp.class,defaultDateValueProcessor);
defaultJC.registerJsonValueProcessor(java.sql.Time.class, defaultDateValueProcessor);
defaultJC.registerJsonValueProcessor(java.sql.Date.class, defaultDateValueProcessor);
defaultJC.registerJsonValueProcessor(java.util.Date.class, defaultDateValueProcessor);
defaultJC.registerJsonValueProcessor(Json.class, jsonProcessor);
}
public class NoUse{
Object object;
public Object getObject() {return object;}
public void setObject(Object object) {this.object = object;}
}
public Json(){
new Json(null);
}
public Json(Object target){
//
if(target==null){
this.strValue="null";
this.type=TYPE.nvl;
this.json=JSONNull.getInstance();
}else if(JSONObject.class.isAssignableFrom(target.getClass())) {
this.json =(JSON)target;
this.type=TYPE.object;
}else if(JSONArray.class.isAssignableFrom(target.getClass())) {
this.json =(JSON)target;
this.type=TYPE.array;
}else if(JSONNull.class.isAssignableFrom(target.getClass())) {
this.json =(JSON)target;
this.type=TYPE.nvl;
}else if(JSONUtils.isArray(target)){//大概凡是可以被认同为"数组"而被json化的比如set,list,emuration等
json=JSONArray.fromObject(target,defaultJC);
this.type=TYPE.array;
}else if(JSONUtils.isObject(target)){//可以被认为是对象的
NoUse nu=new NoUse();
nu.setObject(target);
Object object=JSONObject.fromObject(nu,defaultJC).get("object");
if(object instanceof JSONObject){
json=(JSONObject)object;
this.type=TYPE.object;
}else if(object instanceof JSONNull){//字符串"null"属于这里
this.strValue="null";
this.type=TYPE.nvl;
this.json=JSONNull.getInstance();
}else if(object instanceof String){//时间类型会在这里
this.strValue=(String)object;
this.type=TYPE.string;
}
}else{
//其他均按字符串处理
this.strValue=target.toString();
this.type=TYPE.string;
}
}
/**
* 反序列化接口
*/
public static Json decode(String jsString){
String _temp="{OO:"+jsString+"}";
Object target=JSONObject.fromObject(_temp,defaultJC).get("OO");
return new Json(target);
}
/**
* 如果是数组类型,得到长度
* @return
*/
public int length(){
if(this.type.equals(TYPE.array)){
return ((JSONArray)json).size();
}
//返回-1表示不是数组
return -1;
}
public List<Json> asList(){
if(this.type.equals(TYPE.nvl)) return new ArrayList<Json>(0);
List<Json> re=new LinkedList<Json>();
if(this.type.equals(TYPE.array)){
for(int i=0;i<length();i++) re.add(this.find(""+i));
}else{
re.add(this);
}
return re;
}
public static interface TravelCallback{
void process(String id,Json jso,Json parent,int layer);
}
public void travelAllLayer(TravelCallback tCallBack){
travel(tCallBack,0,-1);
}
public void travelLimitLayer(TravelCallback tCallBack,int limitLayer){
travel(tCallBack,0,limitLayer);
}
/**
* 遍历这种树状结构
* @param tCallBack
* @param layer
*/
private synchronized void travel(TravelCallback tCallBack,int layer,int limitLayer){
if(this.type.equals(TYPE.object)){
for(String id:((Map<String, Object>)this.json).keySet()){
Json value=new Json(((Map<String, Object>)this.json).get(id));
tCallBack.process(id, value ,this ,layer);
//子一级继续遍历
if(limitLayer<0 || limitLayer>layer) value.travel(tCallBack,layer+1,limitLayer);
}
}else if(this.type.equals(TYPE.array)){
Iterator it = ((Iterable)this.json).iterator();
int i=0;
while(it.hasNext()){
Json value=new Json(it.next());
tCallBack.process(""+(i++), value,this,layer);
//子一级继续遍历
if(limitLayer<0 || limitLayer>layer) value.travel(tCallBack,layer+1,limitLayer);
}
}else if(this.type.equals(TYPE.string) || this.type.equals(TYPE.nvl)){
return;
}
}
/**
* 调试用方法
*/
public synchronized void debug(){
this.travel(new TravelCallback(){
public void process(String id, Json jso, Json parent, int layer) {
for(int i=0;i<layer;i++) System.out.print(" ");
System.out.println(id+":("+jso.type+")"+jso.toString());
}
},0,-1);
}
/*----------------作为数据模型,要具备增删改查的能力----------------*/
/**
* 查找属性支持深入的查询
* @param idPath id的寻找路径使用.分隔,实际是由属性名称和索引拼起来的
* @return
*/
public Json find(String idPath){
//去掉所有空白,转换数组的[i]为对象形式
idPath=idPath.replaceAll("\\s", "").replaceAll("\\]", "").replaceAll("\\[", ".");
Json current=this;
//当前已经解析哦的id,给异常使用
StringBuffer alreadyIdPath=new StringBuffer();
String[] ids = idPath.split("\\.");
for(int i=0,_length=ids.length;i<_length;i++){
String id=ids[i];
alreadyIdPath.append((i>0?",":"")+id);
try {
if(current.type.equals(TYPE.object)) current=new Json(((JSONObject)current.json).get(id));
else if(current.type.equals(TYPE.array)) current=new Json(((JSONArray)current.json).get(Integer.parseInt(id)));
else throw new RuntimeException("can't get value from object that not belong to Object or Array type!");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("can't find property "+id+" in path:"+alreadyIdPath+"\n current:"+current+"\n this: "+this);
}
}
return current;
}
/**
* 删除属性,注意不会将作为空集合的父删掉,如果删除属性不存在,将不会抛出异常,但数组索引不能越界
* @param idPath
* @param propId 要删除的属性索引或名称
*/
public synchronized Json remove(String idPath,String propId){
Json target=find(idPath);
if(target.type.equals(TYPE.object)) return new Json(((JSONObject)target.json).remove(propId));
else if(target.type.equals(TYPE.array)) return new Json(((JSONArray)target.json).remove(Integer.parseInt(propId)));
else throw new RuntimeException("can't find property "+propId+" in path:"+idPath+"\n current:"+target+"\n this: "+this);
}
/**
* 添加或更新属性
*/
public synchronized void addOrUpadte(String idPath,String propId,Json value){
Json target=find(idPath);
if(target.type.equals(TYPE.object)){
//当是一个可以json化的值时
if(value.json!=null) ((JSONObject)target.json).element(propId,value.json);
//当是一个普通值时
else ((JSONObject)target.json).element(propId,value.strValue);
}else if(target.type.equals(TYPE.array)){
if(value.json!=null) ((JSONArray)target.json).element(Integer.parseInt(propId),value.json);
else ((JSONArray)target.json).element(Integer.parseInt(propId),value.strValue);
}else throw new RuntimeException("can't find property "+propId+" in path:"+idPath+"\n current:"+target+"\n this: "+this);
}
/**
* 可以判断是否为null
*/
public String stringValue(){
if(type.equals(TYPE.nvl)) return null;
if(strValue!=null && !strValue.equals("undefined")) return strValue;
else if(json!=null) return json.toString();
//当strValue为undefined时
return null;
}
/**
*
*/
public String toString(){
String value=stringValue();
return value==null?"null":value;
}
/**
* 同toString
*/
public String encode(){
return this.toString();
}
}
测试代码详见下载
/**
* 从字符串构造json对象
*/
Json as = Json.decode("[1,2,3,4]");
System.out.println("类型" + as.getType());
System.out.println("下标为1的元素" + as.find("1"));
Json obj = Json
.decode("{a:1,b:{name:'john',sex:'男',hobby:['cook','read']}}");
System.out.println("类型" + obj.getType());
System.out.println("属性b为" + obj.find("b"));
System.out.println("属性b中name属性为" + obj.find("b.name"));
/**
* 添加或修改一些属性
*/
as.addOrUpadte(".", "2", Json.decode("{food:'nut'}"));
System.out.println("在索引2的位置插入元素" + as);
obj.addOrUpadte("b", "name", new Json("Jack"));
System.out.println("修改b属性中的name属性" + obj);
obj.addOrUpadte("b.hobby", "2", new Json("movie"));
System.out.println("更加深度的修改数据:" + obj + ",修改后数组大小"
+ obj.find("b.hobby").asList().size());
/**
* 从java对象构造json对象
*/
Json map = new Json(new HashMap() {
{
put("a", 1);
put("b", 2);
put("c", 3);
}
});
System.out.println("查看从java构造的对象对象:" + map);
try {
/**
* 来一些工具方法来简化这个例子
*/
InputStream in = getResourceInBundle(Tester.class,"date.js");
byte[] bytes= getFileContent(in);
String str = new String(bytes,"utf-8");
Json fromWeb = Json.decode(str);
System.out.println();
System.out.println("从浏览器传回来的数据:"+fromWeb);
System.out.println("遍历json对象");
fromWeb.travelAllLayer(new TravelCallback() {
public void process(String id, Json jso, Json parent, int layer) {
System.out.println("属性名:" + id + ":属性值" + jso.toString()
+ ",层次:" + layer);
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
笔者在tester中提供了一些例子,希望对大家有所帮助
(一) 更进一步的convertor
在浏览器中复杂数据的表达方式直接就是json,Jvm中数据的表达方式是javabean,那么很自然的从json直接转化到javabean的需求变就得很急迫,这是一个框架师不得不去面对的问题。另外使用jackson之类的东西去序列化javabean,要先转化为这些框架内部数据模型,再生成json字符串。当序列化很大的数据的时候,比如一个几千行的grid数据,或一个巨大的树状结构数据的时候就会变得很慢。序列化工作还是应该自己做的。
下面一个代码是笔者写的convertor,这些工具类实际是构建灵活而强大的web框架的基石。
package xs.util;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import xs.util.Json.TravelCallback;
/**
*
* @author tj.sgcc.cn
*
*/
public class JsonConvertor {
private static Class[] simpleTypes=new Class[]{String.class,Long.class,long.class,
Integer.class,int.class,Double.class,double.class,Float.class,float.class,Boolean.class,boolean.class,
java.util.Date.class,java.sql.Date.class,java.sql.Time.class,java.sql.Timestamp.class,Json.class};
public static boolean isSimpleType(Class targetClass){
for(Class simpleType:simpleTypes){
if(targetClass.equals(simpleType)) return true;
}
return false;
}
public static boolean isArrayType(Class targetClass){
if(targetClass.isArray()) return true;
return false;
}
public static boolean isCollection(Class targetClass){
if(Collection.class.isAssignableFrom(targetClass)) return true;
return false;
}
public static boolean isMap(Class targetClass){
if(Map.class.isAssignableFrom(targetClass)) return true;
return false;
}
/**
* 这个判断并不严格和准确
*/
public static boolean isBeanType(Class targetClass){
if(isSimpleType(targetClass)) return false;
if(targetClass.getName().startsWith("java.")) return false;
if(isArrayType(targetClass) || isCollection(targetClass)) return false;
return true;
}
/**
* 更加尽可能的匹配时间
*/
public static java.util.Date adaptDate(String dateStr){
if(dateStr==null) return null;
dateStr=dateStr.trim();
String[] datainfo=dateStr.split("-|\\s|:|,");
int length=datainfo.length;
Calendar cal=new GregorianCalendar();
//处理年月日
if(length>=3){
cal.set(Calendar.YEAR, Integer.parseInt(datainfo[0]));
cal.set(Calendar.MONTH, Integer.parseInt(datainfo[1])-1);
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(datainfo[2]));
}else{return null;}
//处理时
int hour=0;
if(length>=4){
hour=Integer.parseInt(datainfo[3]);
}
cal.set(Calendar.HOUR_OF_DAY, hour);
//处理分
int minute=0;
if(length>=5){
minute=Integer.parseInt(datainfo[4]);
}
cal.set(Calendar.MINUTE, minute);
//处理秒
int second=0;
if(length>=6){
second=Integer.parseInt(datainfo[5]);
}
cal.set(Calendar.SECOND, second);
//处理毫秒
long milSecondAdded=0;
if(length>=7){
milSecondAdded=Integer.parseInt(datainfo[6]);
}
return new java.util.Date(cal.getTime().getTime()+milSecondAdded);
}
/**
* 注意number型有大小类型之分,如果是小类型,当str值为null的时候会赋值为0
*/
public static Object deserializeSimpleType(Class targetClass,String value){
if(value==null) return null;
try {
if(String.class.equals(targetClass)){
if(value!=null && value.length()==0) value=null;
return value;
}if(Long.class.equals(targetClass) || long.class.equals(targetClass)){
return Long.parseLong(value);
}else if(Integer.class.equals(targetClass) || int.class.equals(targetClass)){
return Integer.parseInt(value);
}else if(Double.class.equals(targetClass) || double.class.equals(targetClass)){
return Double.parseDouble(value);
}else if(Float.class.equals(targetClass) || float.class.equals(targetClass)){
return Float.parseFloat(value);
}else if(Boolean.class.equals(targetClass) || boolean.class.equals(targetClass)){//对boolean型的转换比较特殊
value=value.trim().toLowerCase();
if(value.length()==0 || value.equals("false")) return false;
return true;
}else if(java.util.Date.class.equals(targetClass)){//以下四个是不是能合并啊
return adaptDate(value);
}else if(java.sql.Date.class.equals(targetClass)){
java.util.Date date=(Date) deserializeSimpleType(java.util.Date.class,value);
return new java.sql.Date(date.getTime());
}else if(java.sql.Time.class.equals(targetClass)){
java.util.Date date=(Date) deserializeSimpleType(java.util.Date.class,value);
return new java.sql.Time(date.getTime());
}else if(java.sql.Timestamp.class.equals(targetClass)){
java.util.Date date=(Date) deserializeSimpleType(java.util.Date.class,value);
return new java.sql.Timestamp(date.getTime());
}else if(Json.class.equals(targetClass)){
return Json.decode(value);
}
} catch (Exception e) {}
return null;
}
private static final SimpleDateFormat dateFm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static String esacpeSimpleType(Object value){
if(value==null){
return "null";
}else{
if(java.util.Date.class.isAssignableFrom(value.getClass())){
return dateFm.format((java.util.Date)value);
}else{
String v = value.toString();
v = v.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\\\"");
return v;
}
}
}
/**
* 序列化为json的表示形式
* @param target
*/
public static String serialize(Object target) throws Exception{
if(target==null) return "null";
Class targetClass=target.getClass();
if(isArrayType(targetClass)){
StringBuffer jsonString=new StringBuffer("[");
for(int i=0,l=Array.getLength(target);i<l;i++){
jsonString.append((i==0?"":",")+serialize(Array.get(target, i)));
}
return jsonString.append("]").toString();
}else if(isCollection(targetClass)){
Collection collection=(Collection)target;
StringBuffer jsonString=new StringBuffer("[");
if(!collection.isEmpty()){
int i=0;
Iterator it = collection.iterator();
while(it.hasNext()){
jsonString.append((i==0?"":",")+serialize(it.next()));
i++;
}
}
return jsonString.append("]").toString();
}else if(isSimpleType(targetClass)){
//ajax返回时,会以对象方式被识别
return "\""+esacpeSimpleType(target)+"\"";
}else if(isMap(targetClass)){
Map map = (Map)target;
StringBuffer jsonString=new StringBuffer("{");
for(Object key:map.keySet()){
Object value = map.get(key);
jsonString.append((jsonString.length()>1?",":"")+serialize(key.toString())+":\""+serialize(value)+"\"");
}
return jsonString.append("}").toString();
}else if(isBeanType(targetClass)){
StringBuffer jsonString=new StringBuffer("{");
for(Method method:targetClass.getMethods() ){
String methodName=method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
if(methodName.startsWith("set") && paramTypes.length==1){
//得到表单的名称
String inputName;
inputName=methodName.substring(3);
inputName=inputName.substring(0,1).toLowerCase()+inputName.substring(1);
//得到getter,确定返回类型
Method getter = null;
try {
getter = targetClass.getMethod("get"+methodName.substring(3), new Class[0]);
} catch (RuntimeException e) {}
if(getter == null) continue;
Object returnValue=getter.invoke(target, new Object[0]);
jsonString.append((jsonString.length()>1?",":"")+"\""+inputName+"\":"+serialize(returnValue));
}
}
//添加类型属性
jsonString.append((jsonString.length()>1?",":"")+"\"class\":"+serialize(serialize(target.getClass().getName())));
return jsonString.append("}").toString();
}
return "null";
}
public static <T> T deserialize(Json json,Class<T> targetClass) throws Exception{
/*-----------反序列化null,类似于{editValue:""}对象也返回null------*/
if(json.stringValue()==null || json.stringValue().length()==0) return null;
/*-----------反序列化基本类型---*/
Object simpleObject = deserializeSimpleType(targetClass, json.stringValue());
if(simpleObject!=null) return (T)simpleObject;
/*-----------对象类型----------*/
//如果json中定义了类型
String className = json.find("class").stringValue();
if(className!=null){
//有时类中属性的定义是父类,而实际的赋值是子类
Class subClass = Thread.currentThread().getContextClassLoader().loadClass(className);
if(targetClass==null || targetClass.isAssignableFrom(subClass)) targetClass = subClass;
}
if(targetClass==null) return null;
//默认构造器
Object object = targetClass.getConstructor(new Class[0]).newInstance(new Object[0]);
Method[] methods = targetClass.getMethods();
if(methods!=null && methods.length>0){
for(Method method:methods){
String methodName=method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
//得到所有的setter
if(methodName.startsWith("set") && paramTypes.length==1){
//得到属性名称
String _fieldName=methodName.substring(3);
String fieldName=_fieldName.substring(0,1).toLowerCase()+_fieldName.substring(1);
//转换值---这里有一个小漏洞,先按照首字母小写的方式取,再按照不小写的形式取(不规范的bean prop name)
Json _fieldJson = json.find(fieldName);
if(_fieldJson.stringValue() == null) _fieldJson = json.find(_fieldName);
if(_fieldJson.stringValue() == null) continue;
Class fieldClass = paramTypes[0];
Object fieldValue = null;
//只支持数组,简单类型和bean和map
if(isArrayType(fieldClass)){
Class componentClass = fieldClass.getComponentType();
List<Json> list = _fieldJson.asList();
int length = list.size();
fieldValue = Array.newInstance(componentClass, length);
for(int i=0;i<length;i++){
Array.set(fieldValue, i, deserialize(list.get(i),componentClass));
}
}else if(isSimpleType(fieldClass) || isBeanType(fieldClass)){
fieldValue = deserialize(_fieldJson,fieldClass);
}
//以下两个类型的说明必须在json中
else if(isMap(fieldClass)){
final Map<String,Object> map = (Map<String,Object>) fieldClass.getConstructor(new Class[0]).newInstance(new Object[0]);
json.travelLimitLayer(new TravelCallback(){
public void process(String id, Json _elementJson, Json parent, int layer) {
if(layer==0){
Object element = null;
try {
element = deserialize(_elementJson,null);
} catch (Exception e) {}
if(element!=null) map.put(id, element);
}
}
},0);
fieldValue = map;
}else if(isCollection(fieldClass)){
Collection col = (Collection)fieldClass.getConstructor(new Class[0]).newInstance(new Object[0]);
for(Json _elementJson:_fieldJson.asList()){
Object element = deserialize(_elementJson,null);
if(element!=null) col.add(element);
}
fieldValue = col;
}
//设置这个setter
if(fieldValue!=null) method.invoke(object, fieldValue);
}
}
}
return (T)object;
}
}
代码是简单而易读的,没有多余的部分。读者可以修改用看来适应自己的项目,实际上,这个原型也是项目中实际使用代码。
在代码中可以看到,在反序列化时大量使用java反射操作,当遇到大json string的时候还是会存在效率低下的问题。希望将来可以看到基于动态字节码技术进行转换及对json字符串真正进行流式解析的框架出现。
(三) 在浏览器端使用json
虽然浏览中对象(姑且称作jsbean)的初始化时可以使用json语法,但从服务器端flush出去的数据却都是字符串形式。Jquery实现了eval和globalEval方法,这个相当于decode方法,但始终也没有提供encode方法。这里介绍一个阿三的jquery插件https://github.com/Krinkle/jquery-json。在笔者的util2.js中做了如下封装
eval:function(source){
if(typeof source==='undefined' || source==null) return null;
var str=$.trim(''+source);
if(str.length==0) return null;
if(str.indexOf('var ')==0) str=str.substring(3);//去掉var
var equalIndex=str.indexOf('='),varName=$.trim(''+str.substring(0,equalIndex));
/**
* 可能会重新运行script中的其他脚本,所以用varName判断一下,确定是一个定义
* 这样仍然可能会出现莫名其妙的状况,比如在定义后面写一段$(document).ready()这类的
*/
if(varName && $.trim(varName).length>0){
try{
//jquery1.6.4
$.globalEval(source);
return [varName,window[varName]];
}finally{
window[varName]=null;
}
}
},
/**
* 字符串反序列化为对象
*/
decode:function(str){
if(!str || !(str=$.trim(str)).length) return;
return this.eval("var _OO="+str)[1];
},
/**
* 对象序列化
*/
encode:function(obj){
return $.JSON.encode(obj);
}
其中eval不仅可以decode json,还支持真正的javascript脚本,是组件化前端中的重要组成部分。
encode和decode不仅仅对json对象起左右,见如下的示例
alert(typeof $u.decode("'老王'")+'/'+$u.decode("'老王'"))//string/老王
alert($u.decode(null)==null)//true
可见其对普通类型也有很好的支持。
Jquery的ajax方法,指定了返回值类型为json。这时,如果你只是返回一个null或者‘一段文字在这里…’(注意要有单引号,双引号要转义为\”),jquery会报parse error错误,success方法不会再返回。使用这个decode方法自己反序列化是不会出这样问题 的,它有更广泛的适应性。同理,encode方法也是这样。
下载