在web开发中更加富有效率的使用JSON

    此博客为javablog的同名博客,另外代码好像太多了,不知大家是否受得了

    本文一共分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’)反序列成jsonjvm中的表示,详见本文提供的下载。

前端开发的组件化是近年来web开发突飞猛进的重要特点。笔者所在的公司在最近这一两年前也完成了从jsp等模板技术到组件化开发的转变。在面向组件的web开发中(假设大家都熟悉类似于extjs之类的东西),从服务器端传递到浏览器的数据也大多是json。比如可以将将一个grid组件的数据整体encodejson化)传递给浏览器端驱动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互补的,当表达一个普通的值时jsonnull,当可以按照json解析时,strValuenull

    */

   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==nullreturn "";

         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==nullreturn "";

         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();

      //strValueundefined

      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("属性bname属性为" + 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

    在浏览器中复杂数据的表达方式直接就是jsonJvm中数据的表达方式是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==nullreturn 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==nullreturn 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==nullreturn "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 == nullcontinue;

               

                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!=nullreturn (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==nullreturn 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() == nullcontinue;

                Class  fieldClass = paramTypes[0];

                Object fieldValue = null;

                //只支持数组,简单类型和beanmap

                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实现了evalglobalEval方法,这个相当于decode方法,但始终也没有提供encode方法。这里介绍一个阿三的jquery插件https://github.com/Krinkle/jquery-json。在笔者的util2.js中做了如下封装

     

 

   eval:function(source){

       if(typeof source==='undefined' || source==nullreturn 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)).lengthreturn;

       return this.eval("var _OO="+str)[1];

    },

   

    /**

     * 对象序列化

     */

    encode:function(obj){

       return $.JSON.encode(obj);

    }

其中eval不仅可以decode json,还支持真正的javascript脚本,是组件化前端中的重要组成部分。

                 encodedecode不仅仅对json对象起左右,见如下的示例

 alert(typeof $u.decode("'老王'")+'/'+$u.decode("'老王'"))//string/老王

           alert($u.decode(null)==null)//true

           可见其对普通类型也有很好的支持。

       Jqueryajax方法,指定了返回值类型为json。这时,如果你只是返回一个null或者‘一段文字在这里’(注意要有单引号,双引号要转义为\”,jquery会报parse error错误,success方法不会再返回。使用这个decode方法自己反序列化是不会出这样问题  的,它有更广泛的适应性。同理,encode方法也是这样。

      

猜你喜欢

转载自jonenine.iteye.com/blog/2163782