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

Json和结构体间相互转换


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


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

/**
* @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就可以了:

/**
* @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比较多,哈哈,下面这个是经过后来修改后已经用了很久的代码,贴出来对比一下。

    /** 
     * @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方法直接赋值,简直被自己蠢哭了。

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





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值