Java工作笔记:关于Java调用C库时,Json和结构体间相互转换

本文介绍如何利用Java反射机制实现结构体与JSON格式数据的相互转换,包括处理结构体中嵌套结构体及支持中文编码等问题。


Json和结构体间相互转换


这几个星期一直很忙,这篇文章本来是打算上周末发的,结果拖到了现在。


Java web中遇见把调用C库时,入参和出参的结构体转换成Json格式输出。有的结构体内含有大量属性的时候,一个一个添加手都要加断了。于是我使用了JAVA的反射机制来实现结构体和JSON格式之间的相互转换。先贴代码:

  1. /** 
  2. * @apiNot Json转结构体 
  3. */  
  4. public static Structure Json2Struct(JSONObject jsonObject, Structure structure){  
  5.   
  6.    Map<String, Object> map = jsonObject;  
  7.    //获取结构体字段  
  8.    Field[] fields = structure.getClass().getDeclaredFields();  
  9.   
  10.    int e = 0;  
  11.   
  12.    //遍历赋值  
  13.    for (Map.Entry<String, Object> entry : map.entrySet()){  
  14.   
  15.        int find = 0;  
  16.   
  17.        for(Field field : fields){  
  18.   
  19.            // 对于每个属性,获取属性名  
  20.            String varName = field.getName();  
  21.            //过滤掉结构体属性名中的前缀  
  22.            varName = varName.replace("sz","").replace("ul","");  
  23.   
  24.            //给每个结构体中的成员修改权限,使其可以人为修改其成员值(private改为public)  
  25.            boolean access = field.isAccessible();  
  26.            if(!access) field.setAccessible(true);  
  27.   
  28.            //找到和jsonde的key值相同的成员名称并赋值  
  29.            if(varName.equals(entry.getKey()))  
  30.            {  
  31.                try {  
  32.                    Object object = field.get(structure);  
  33.                    //判断结构体中成员类型(依自己情况而定)  
  34.                    if("byte[]".equals(object.getClass().getTypeName()))  
  35.                    {  
  36.                        field.set(structure, entry.getValue().toString().getBytes());  
  37.                    }  
  38.                    else  
  39.                    {  
  40.                        field.set(structure, entry.getValue());  
  41.                    }  
  42.                }catch (Exception ex){  
  43.                    ex.printStackTrace();  
  44.                }  
  45.   
  46.                find = 1;  
  47.                e++;  
  48.            }  
  49.   
  50.        }  
  51.   
  52.        if(1 != find)  
  53.        {  
  54.            SDKLogger.PrintDebug(SDKConst.loglevel.ERROR, "该结构体类型中没有Json中的"  
  55.                    + entry.getKey() + "变量");  
  56.        }  
  57.   
  58.    }  
  59.   
  60.    if(0 == e)  
  61.    {  
  62.        SDKLogger.PrintDebug(SDKConst.loglevel.ERROR, "该结构体类型与Json不匹配");  
  63.    }  
  64.   
  65.    return structure;  
  66.   
  67. }  
/**
* @apiNot Json转结构体
*/
public static Structure Json2Struct(JSONObject jsonObject, Structure structure){

   Map<String, Object> map = jsonObject;
   //获取结构体字段
   Field[] fields = structure.getClass().getDeclaredFields();

   int e = 0;

   //遍历赋值
   for (Map.Entry<String, Object> entry : map.entrySet()){

       int find = 0;

       for(Field field : fields){

           // 对于每个属性,获取属性名
           String varName = field.getName();
           //过滤掉结构体属性名中的前缀
           varName = varName.replace("sz","").replace("ul","");

		   //给每个结构体中的成员修改权限,使其可以人为修改其成员值(private改为public)
           boolean access = field.isAccessible();
           if(!access) field.setAccessible(true);

           //找到和jsonde的key值相同的成员名称并赋值
		   if(varName.equals(entry.getKey()))
           {
               try {
                   Object object = field.get(structure);
				   //判断结构体中成员类型(依自己情况而定)
                   if("byte[]".equals(object.getClass().getTypeName()))
                   {
                       field.set(structure, entry.getValue().toString().getBytes());
                   }
                   else
                   {
                       field.set(structure, entry.getValue());
                   }
               }catch (Exception ex){
                   ex.printStackTrace();
               }

               find = 1;
               e++;
           }

       }

       if(1 != find)
       {
           SDKLogger.PrintDebug(SDKConst.loglevel.ERROR, "该结构体类型中没有Json中的"
                   + entry.getKey() + "变量");
       }

   }

   if(0 == e)
   {
       SDKLogger.PrintDebug(SDKConst.loglevel.ERROR, "该结构体类型与Json不匹配");
   }

   return structure;

}
json转结构体主要注意不同的结构体成员类型的赋值方式不一样。


结构体转Json相对要简单一些,不需要Json入参,便利每个结构体属性再把他们的成员名和值一个一个构建成json就可以了:

  1. /** 
  2. * @apiNot 结构体转Json 
  3. */  
  4. public static JSONObject Struct2Json(Structure structure){  
  5.   
  6.    JSONObject jsonObject = new JSONObject();  
  7.   
  8.    // 获取对象obj的所有属性域  
  9.    Field[] fields = structure.getClass().getDeclaredFields();  
  10.   
  11.    for (Field field : fields)  
  12.    {  
  13.        // 对于每个属性,获取属性名  
  14.        String varName = field.getName();  
  15.        //过滤掉属性名中的前缀  
  16.        varName = varName.replace("sz","").replace("ul","");  
  17.   
  18.        try  
  19.        {  
  20.            boolean access = field.isAccessible();  
  21.            if(!access) field.setAccessible(true);  
  22.   
  23.            //从obj中获取field变量  
  24.            Object obj = field.get(structure);  
  25.            if("byte[]".equals(obj.getClass().getTypeName()))  
  26.            {  
  27.                jsonObject.put(varName, new String((byte[])obj));  
  28.            }  
  29.            else  
  30.            {  
  31.                jsonObject.put(varName, obj);  
  32.            }  
  33.   
  34.            if(!access) field.setAccessible(false);  
  35.        }  
  36.        catch (Exception ex)  
  37.        {  
  38.            ex.printStackTrace();  
  39.        }  
  40.    }  
  41.   
  42.    return jsonObject;  
  43. }  
/**
* @apiNot 结构体转Json
*/
public static JSONObject Struct2Json(Structure structure){

   JSONObject jsonObject = new JSONObject();

   // 获取对象obj的所有属性域
   Field[] fields = structure.getClass().getDeclaredFields();

   for (Field field : fields)
   {
       // 对于每个属性,获取属性名
       String varName = field.getName();
       //过滤掉属性名中的前缀
       varName = varName.replace("sz","").replace("ul","");

       try
       {
           boolean access = field.isAccessible();
           if(!access) field.setAccessible(true);

           //从obj中获取field变量
           Object obj = field.get(structure);
           if("byte[]".equals(obj.getClass().getTypeName()))
           {
               jsonObject.put(varName, new String((byte[])obj));
           }
           else
           {
               jsonObject.put(varName, obj);
           }

           if(!access) field.setAccessible(false);
       }
       catch (Exception ex)
       {
           ex.printStackTrace();
       }
   }

   return jsonObject;
}

注:代码注释中去掉属性名中的前缀是因为公司restful规范和C语言编程规范做的特殊处理。

还有就是在结构体中包含的结构体无法转换成Json,反过来也是。这个问题暂时没有进行优化,待后续改进。

如果有哪位过客有什么修改意见,欢迎提出来哈,不,一定要提出来哈。


———————————————————————————————————————————————————

更新一下,上面的代码bug比较多,哈哈,下面这个是经过后来修改后已经用了很久的代码,贴出来对比一下。

  1. /**  
  2.  * @apiNot Json转结构体 
  3.  */   
  4. public static Structure Json2Struct(JSONObject jsonObject, Structure structure){   
  5.   
  6.     Map<String, Object> map = jsonObject;   
  7.     //获取结构体字段   
  8.     Field[] fields = structure.getClass().getDeclaredFields();   
  9.   
  10.     int e = 0;   
  11.     //遍历赋值   
  12.     for (Map.Entry<String, Object> entry : map.entrySet()){   
  13.   
  14.         int find = 0;   
  15.   
  16.         for(Field field : fields){   
  17.   
  18.             // 对于每个属性,获取属性名   
  19.             String varName = field.getName();   
  20.             //过滤掉结构体属性名中的前缀(这是我自己写的方法)   
  21.             varName = StringHandler.removLowerHaed(varName);   
  22.   
  23.             boolean access = field.isAccessible();   
  24.             if(!access) field.setAccessible(true);   
  25.   
  26.             if(varName.equals(entry.getKey()))   
  27.             {   
  28.                 try {   
  29.                     Object object = field.get(structure);   
  30.                     if("byte[]".equals(object.getClass().getTypeName()) || object instanceof byte[])   
  31.                     {   
  32.                         //字符串拷贝,也是我自己封装的一个方法,添加了中文编码支持  
  33.    StringHandler.ArrayCopy((byte[])object, entry.getValue().toString().getBytes("utf-8"));   
  34.                     }   
  35.         //结构体中包含结构体时的情况  
  36.                     else if(object.getClass().getName().contains("Structure"))   
  37.                     {   
  38.                         //出现数组的情况  
  39.             if(object.getClass().isArray())   
  40.                         {   
  41.                             JSONArray array = (JSONArray)entry.getValue();   
  42.                             int length = Array.getLength(object);   
  43.                             for(int i=0;i<length;i++)   
  44.                             {   
  45.                                 Json2Struct((JSONObject)array.get(i), (Structure)Array.get(object,i));   
  46.                             }   
  47.                         }   
  48.                         else   
  49.                         {   
  50.                             Json2Struct((JSONObject)entry.getValue(), (Structure)object);   
  51.                         }   
  52.                     }   
  53.                     else   
  54.                     {   
  55.                         field.set(structure, entry.getValue());   
  56.                     }   
  57.                 }catch (Exception ex){   
  58.                     ex.printStackTrace();   
  59.                 }   
  60.   
  61.                 find = 1;   
  62.                 e++;   
  63.             }   
  64.   
  65.         }   
  66.   
  67.         if(1 != find)   
  68.         {   
  69.             logger.debug("该结构体类型中没有Json中的" + entry.getKey() + "变量");   
  70.         }   
  71.   
  72.     }   
  73.   
  74.     if(0 == e)   
  75.     {   
  76.         logger.error("该结构体类型与Json不匹配");   
  77.     }   
  78.   
  79.     return structure;   
  80.   
  81. }   
  82.   
  83. /**  
  84.  * @apiNot 结构体转Json  
  85.  */   
  86. public static JSONObject Struct2Json(Structure structure){   
  87.   
  88.     JSONObject jsonObject = new JSONObject();   
  89.   
  90.     // 获取对象obj的所有属性域   
  91.     Field[] fields = structure.getClass().getDeclaredFields();   
  92.   
  93.     for (Field field : fields) {   
  94.         // 对于每个属性,获取属性名   
  95.         String varName = field.getName();   
  96.         //过滤掉属性名中的前缀(这个是根据需求加的)   
  97.         varName = StringHandler.removLowerHaed(varName);   
  98.         if(varName.equals("Reserv")){   
  99.             //预留字段不必传给客户端(我们的C++代码中很多结构体会留有预留字段)   
  100.             continue;   
  101.         }   
  102.   
  103.         try {   
  104.             //打开修改权限   
  105.             boolean access = field.isAccessible();   
  106.             if(!access) field.setAccessible(true);   
  107.   
  108.             //从obj中获取field变量   
  109.             Object obj = field.get(structure);   
  110.             if("byte[]".equals(obj.getClass().getTypeName()))   
  111.             {   
  112.                 String str = StringHandler.bytesToString((byte[])obj);   
  113.   
  114.                 jsonObject.put(varName, str);   
  115.             }   
  116.             else if(obj.getClass().getName().contains("Structure"))   
  117.             {   
  118.                 if(obj.getClass().isArray())   
  119.                 {   
  120.                     JSONArray array = new JSONArray();   
  121.                     int length = Array.getLength(obj);   
  122.                     for(int i=0;i<length;i++)   
  123.                     {   
  124.                         array.add(i, Struct2Json((Structure)Array.get(obj,i)));   
  125.                     }   
  126.                     jsonObject.put(varName, array);   
  127.                 }   
  128.                 else   
  129.                 {   
  130.                     jsonObject.put(varName, Struct2Json((Structure)obj));   
  131.                 }   
  132.             }   
  133.             else   
  134.             {   
  135.                 jsonObject.put(varName, obj);   
  136.             }   
  137.   
  138.         } catch (Exception ex) {   
  139.             ex.printStackTrace();   
  140.         }   
  141.     }   
  142.   
  143.     return jsonObject;   
  144. }   
    /** 
     * @apiNot Json转结构体
     */ 
    public static Structure Json2Struct(JSONObject jsonObject, Structure structure){ 

        Map<String, Object> map = jsonObject; 
        //获取结构体字段 
        Field[] fields = structure.getClass().getDeclaredFields(); 

        int e = 0; 
        //遍历赋值 
        for (Map.Entry<String, Object> entry : map.entrySet()){ 

            int find = 0; 

            for(Field field : fields){ 

                // 对于每个属性,获取属性名 
                String varName = field.getName(); 
                //过滤掉结构体属性名中的前缀(这是我自己写的方法) 
                varName = StringHandler.removLowerHaed(varName); 

                boolean access = field.isAccessible(); 
                if(!access) field.setAccessible(true); 

                if(varName.equals(entry.getKey())) 
                { 
                    try { 
                        Object object = field.get(structure); 
                        if("byte[]".equals(object.getClass().getTypeName()) || object instanceof byte[]) 
                        { 
                            //字符串拷贝,也是我自己封装的一个方法,添加了中文编码支持
			    StringHandler.ArrayCopy((byte[])object, entry.getValue().toString().getBytes("utf-8")); 
                        } 
						//结构体中包含结构体时的情况
                        else if(object.getClass().getName().contains("Structure")) 
                        { 
                            //出现数组的情况
							if(object.getClass().isArray()) 
                            { 
                                JSONArray array = (JSONArray)entry.getValue(); 
                                int length = Array.getLength(object); 
                                for(int i=0;i<length;i++) 
                                { 
                                    Json2Struct((JSONObject)array.get(i), (Structure)Array.get(object,i)); 
                                } 
                            } 
                            else 
                            { 
                                Json2Struct((JSONObject)entry.getValue(), (Structure)object); 
                            } 
                        } 
                        else 
                        { 
                            field.set(structure, entry.getValue()); 
                        } 
                    }catch (Exception ex){ 
                        ex.printStackTrace(); 
                    } 

                    find = 1; 
                    e++; 
                } 

            } 

            if(1 != find) 
            { 
                logger.debug("该结构体类型中没有Json中的" + entry.getKey() + "变量"); 
            } 

        } 

        if(0 == e) 
        { 
            logger.error("该结构体类型与Json不匹配"); 
        } 

        return structure; 

    } 

    /** 
     * @apiNot 结构体转Json 
     */ 
    public static JSONObject Struct2Json(Structure structure){ 

        JSONObject jsonObject = new JSONObject(); 

        // 获取对象obj的所有属性域 
        Field[] fields = structure.getClass().getDeclaredFields(); 

        for (Field field : fields) { 
            // 对于每个属性,获取属性名 
            String varName = field.getName(); 
            //过滤掉属性名中的前缀(这个是根据需求加的) 
            varName = StringHandler.removLowerHaed(varName); 
            if(varName.equals("Reserv")){ 
                //预留字段不必传给客户端(我们的C++代码中很多结构体会留有预留字段) 
                continue; 
            } 

            try { 
                //打开修改权限 
                boolean access = field.isAccessible(); 
                if(!access) field.setAccessible(true); 

                //从obj中获取field变量 
                Object obj = field.get(structure); 
                if("byte[]".equals(obj.getClass().getTypeName())) 
                { 
                    String str = StringHandler.bytesToString((byte[])obj); 

                    jsonObject.put(varName, str); 
                } 
                else if(obj.getClass().getName().contains("Structure")) 
                { 
                    if(obj.getClass().isArray()) 
                    { 
                        JSONArray array = new JSONArray(); 
                        int length = Array.getLength(obj); 
                        for(int i=0;i<length;i++) 
                        { 
                            array.add(i, Struct2Json((Structure)Array.get(obj,i))); 
                        } 
                        jsonObject.put(varName, array); 
                    } 
                    else 
                    { 
                        jsonObject.put(varName, Struct2Json((Structure)obj)); 
                    } 
                } 
                else 
                { 
                    jsonObject.put(varName, obj); 
                } 

            } catch (Exception ex) { 
                ex.printStackTrace(); 
            } 
        } 

        return jsonObject; 
    } 
可以看出来,这段代码和之前的比,添加了处理结构体中包含结构体的状况,还有添加了中文编码。这些事后来遇到问题时修改的。

前一段代码中还有个大bug就是在遇到byte[]数组的时候我竟然用了put方法直接赋值,简直被自己蠢哭了。

学无止境,害得继续加油啊。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值