android 从jobject、jclass获取类名(API>19)(一)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 从jobject、jclass获取类名(API>19)(一)相关的知识,希望对你有一定的参考价值。

参考技术A 用途在Art中Hook JNI相关函数。存在jobject jclass 参数时需要得到具体的类名。

在Art虚拟机中:

jobject在内存中表现为:art::mirror::Object,可从GetObjectClass方法中分析得到(art/runtime/jni_internal.cc)

jclass在内存中表现为:art::mirror::Class,可从GetSuperclass方法中分析得到(art/runtime/jni_internal.cc)

获取类名重点在art::mirror::Class类中,通过分析Class 类发现在art/runtime/mirror/class-inl.h头文件中存在一个获取类名的方法

上述方法存在两个问题:

综上所述,GetName不适合获取类名

在dalvik虚拟机中存在一个方法dvmDecodeIndirectRef,可以将jobject、jclass转为对应的内存结构指针。

经过查找发现在/art/runtime/thread.cc中存在一个方法DecodeJObject可以将jobject、jclass转换为对应的内存结构指针

DecodeJObject是Thread类的一个方法,通过dlsym拿到方法地址后,其表现形式如下:

第一个参数表示this即当前对象。可以通过如下方法获取Thread对象的实例

同时发现/art/runtime/mirror/class.cc中存在GetDescriptor方法可以获取art::mirror::Class的类名

GetDescriptor是Class类的一个方法,通过dlsym拿到方法地址后,其表现形式如下:

第一个参数表示this即当前对象。可以通过DecodeJObject获取Class对象的实例,

在最终可以整理得到获取jclass类名的方法:

获取jobject方法就简单一点其内存结构可以精简如下:

其中klass就是Class对象的指针,最终整理后的方法如下:

上述方法太过于麻烦,后面给出一个简单的方法,可以模拟dalvik解析dex拿到类名。不早了,睡了

如何在不添加新 JObject 键/名称的情况下将 JArray 添加到 JObject 中?

【中文标题】如何在不添加新 JObject 键/名称的情况下将 JArray 添加到 JObject 中?【英文标题】:How would you add a JArray into a JObject without adding a new JObject key/name? 【发布时间】:2021-12-18 19:20:11 【问题描述】:

使用 .NET C#,我正在尝试从 JArray 创建一个新的 JObject。我有一个 FetchData JObject,我想返回一个数据 JObject 以进行数据驱动测试。这是我目前所拥有的:

public static JObject FetchData(string testMethodName)
        
            using (StreamReader r = new StreamReader("PathToJsonfile"))
            
                string jsonstring = r.ReadToEnd();
                JObject obj = JObject.Parse(jsonstring);
                JArray jsonArray = JArray.Parse(obj[testMethodName].ToString());

                JObject jObject = new JObject(new JProperty("test",jsonArray));

                return jObject;
            

        

我想返回一个与正在运行的 testMethod 相关的测试数据的 JObject。当我运行这段代码时,jObject 返回:

"test": [
    
      "loginId": "testuser1",
      "userCase": "verify for user"
    ,
    
      "loginId": "testuser2",
      "userCase": "verify for user"
    
  ]

我的问题是我只想在 JObject 中返回以下数组:

"loginId":"testuser1","userCase":"verify for user"

我研究了一段时间,如果不向新的 JObject 添加密钥,则无法找到解决方案,在这种情况下,密钥是“测试”。

这在 C# 中是否可行?

我也尝试将 JArray 直接添加到 JObject:

JObject jObject = new JObject(new JObject(jsonArray));

但出现错误:System.ArgumentException: '无法将 Newtonsoft.Json.Linq.JArray 添加到 Newtonsoft.json.Linq.JObject

我也尝试过像这样将数组添加到 JObject:

for (int i = 0; i < jsonArray.Count; i++)
                
                    jObject[i] = jsonArray[i];
                

但出现错误:System.ArgumentException:使用无效键值设置 JObject 值:0。应为对象属性名称。

fwiw 这就是我这样做的方式,它是 Java,它就像一个魅力,但我无法在 C# 中弄清楚。 Java 代码:

JSONObject[] jsonObject = new JSONObject[jsonArray.length()];
        for (int i = 0; i < jsonArray.length(); i++) 
            jsonObject[i] = jsonArray.getJSONObject(i);
        

【问题讨论】:

JArray.FromObject(myObject); "loginId":"testuser1","userCase":"verify for user" 不是数组而是对象。你能澄清一下你到底想返回什么 - json数组的第一个元素吗?还是将所有元素作为单独的JObjects?或者只是一个JArray 嗨@GuruStron,感谢您的回复。我想将所有元素的 JObject 作为单独的对象返回,如下所示: ["loginId":"testuser1","userCase":"verify for user","loginId":"testuser2","userCase":"验证用户"] 那不是json对象,是json数组,所以需要将返回类型改为JArray,返回jsonArray 你是对的@GuruStron。我意识到我现在没有问正确的问题。我想返回数组第一个元素的 JObject,像这样:"loginId":"testuser1","userCase":"verify for user",你知道我会怎么做吗? 【参考方案1】:

要获取数组的第一个元素,您可以执行以下操作:

var json = @"
""test"": [
    
      ""loginId"": ""testuser1"",
      ""userCase"": ""verify for user""
    ,
    
      ""loginId"": ""testuser2"",
      ""userCase"": ""verify for user""
    ]
";
var testMethodName = "test";
var jObject = JObject.Parse(json);
var first = (JObject)jObject[testMethodName][0]; // note that this can throw for multiple reasons

你的 java 代码的模拟是:

// parse jObject as earlier
var jArr = (JArray)jObject[testMethodName];
var jsonObjectArr = new JObject[jArr.Count];
for (int i = 0; i < jArr.Count; i++)

    jsonObjectArr[i] = (JObject)jArr[i];

或者你可以使用LINQ to JSON:

// parse jObject as earlier
var jsonObjectArr = jObject[testMethodName]
    .Children<JObject>()
    .ToArray();

【讨论】:

【参考方案2】:

为什么不像这样只返回数组的第一个对象:

public static JToken FetchOneDatum(string testMethodName)

  string jsonString = GetFileContent("sampleTest.txt");
  JObject obj = JObject.Parse(jsonString);
  JArray jsonArray = JArray.Parse(obj[testMethodName].ToString());
  return jsonArray[0];

您可以在此处找到整个 Visual Studio 解决方案: solution on GitHub

【讨论】:

【参考方案3】:

C# 方法 ;)

public class Test

    public string loginId  get; set; 
    public string userCase  get; set; 


public class Scenario

    public Test[] tests  get; set; 


// Usage
public static Test FetchData(string testMethodName)

    using (var reader = new StreamReader("PathToJsonfile"))
    
        var json = reader.ReadToEnd();
        var scenario = JsonConvert.DeserializeObject<Scenario>(json);

        return scenario.tests.First();
    

【讨论】:

以上是关于android 从jobject、jclass获取类名(API>19)(一)的主要内容,如果未能解决你的问题,请参考以下文章

Android jni/ndk编程三:native访问java

如何以编程方式从动态 JObject 获取属性

从 JSON 检索项目时获取“无法将 Newtonsoft.Json.Linq.JObject 转换为 Newtonsoft.Json.Linq.JToken”

NDK:JNI 的数据结构

JObject对象如何获取深度属性值&不判断key是否存在获取值&获取含有特殊字符的key值

Delphi XE5 Android 调用手机震动(通过JObject测试是否支持震动)