Skip to content

Commit e0ee90d

Browse files
committed
feat: 支持 JS 对象和数组转 Map 和 Array
1 parent 04aafc5 commit e0ee90d

File tree

5 files changed

+136
-0
lines changed

5 files changed

+136
-0
lines changed

wrapper-android/src/androidTest/java/com/whl/quickjs/wrapper/QuickJSTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,4 +1194,19 @@ public void testAsyncErrorInByteCode() {
11941194
context.destroy();
11951195
}
11961196

1197+
@Test
1198+
public void testObjectToMap() {
1199+
QuickJSContext context = createContext();
1200+
JSObject ret = (JSObject) context.evaluate("var a = {'a': '123', 'b': [1, 2]};a.c = a;;a;");
1201+
assertEquals("{a=123, b=[1, 2]}", ret.toMap().toString());
1202+
ret.release();
1203+
1204+
JSArray array = (JSArray) context.evaluate("var b = [{a: { c : 'xxx'}}, 2, 'qqq', 1.22]; b.push(b); b;");
1205+
assertEquals("[{a={c=xxx}}, 2, qqq, 1.22]", array.toArray().toString());
1206+
array.release();
1207+
1208+
assertEquals("{a={a=123, b=[1, 2]}, b=[{a={c=xxx}}, 2, qqq, 1.22], Infinity=-9223372036854775808, NaN=NaN, Math={LN2=0.6931471805599453, LN10=2.302585092994046, LOG2E=1.4426950408889634, E=2.718281828459045, SQRT2=1.4142135623730951, LOG10E=0.4342944819032518, PI=3.141592653589793, SQRT1_2=0.7071067811865476}, undefined=null}", context.getGlobalObject().toMap().toString());
1209+
context.destroy();
1210+
}
1211+
11971212
}

wrapper-java/src/main/java/com/whl/quickjs/wrapper/JSObject.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.whl.quickjs.wrapper;
22

3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
36
public interface JSObject {
47

58
void setStackTrace(Throwable trace);
@@ -51,4 +54,8 @@ public interface JSObject {
5154
* 引用计数减一,目前仅将对象返回到 JavaScript 中的场景中使用。
5255
*/
5356
void decrementRefCount();
57+
58+
HashMap<String, Object> toMap();
59+
60+
ArrayList<Object> toArray();
5461
}

wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSArray.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.whl.quickjs.wrapper;
22

3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
36
/**
47
* Created by Harlon Wang on 2024/2/13.
58
*/
@@ -26,4 +29,17 @@ public void set(Object value, int index) {
2629
checkRefCountIsZero();
2730
getContext().set(this, value, index);
2831
}
32+
33+
@Override
34+
public HashMap<String, Object> toMap() {
35+
throw new UnsupportedOperationException("Array types are not yet supported for conversion to map. You should use toArray.");
36+
}
37+
38+
@Override
39+
public ArrayList<Object> toArray() {
40+
ArrayList<Object> arrayList = new ArrayList<>(length());
41+
convertToMap(this, arrayList);
42+
circulars.clear();
43+
return arrayList;
44+
}
2945
}

wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSFunction.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.whl.quickjs.wrapper;
22

3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
36
/**
47
* Created by Harlon Wang on 2024/2/12.
58
*/
@@ -60,4 +63,13 @@ public void callVoid(Object... args) {
6063
}
6164
}
6265

66+
@Override
67+
public HashMap<String, Object> toMap() {
68+
throw new UnsupportedOperationException("JSFunction types do not support conversion to map or array.");
69+
}
70+
71+
@Override
72+
public ArrayList<Object> toArray() {
73+
throw new UnsupportedOperationException("JSFunction types do not support conversion to map or array.");
74+
}
6375
}

wrapper-java/src/main/java/com/whl/quickjs/wrapper/QuickJSObject.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import java.lang.reflect.InvocationTargetException;
44
import java.lang.reflect.Method;
5+
import java.util.ArrayList;
56
import java.util.Arrays;
7+
import java.util.HashMap;
68

79
/**
810
* Created by Harlon Wang on 2024/2/12.
@@ -13,6 +15,7 @@ public class QuickJSObject implements JSObject {
1315
private final long pointer;
1416
private int refCount;
1517
private Throwable stackTrace;
18+
protected ArrayList<Long> circulars;
1619

1720
public QuickJSObject(QuickJSContext context, long pointer) {
1821
this.context = context;
@@ -239,6 +242,89 @@ public void decrementRefCount() {
239242
refCount--;
240243
}
241244

245+
@Override
246+
public HashMap<String, Object> toMap() {
247+
HashMap<String, Object> objectMap = new HashMap<>();
248+
convertToMap(this, objectMap);
249+
circulars.clear();
250+
return objectMap;
251+
}
252+
253+
@Override
254+
public ArrayList<Object> toArray() {
255+
throw new UnsupportedOperationException("Object types are not yet supported for conversion to array. You should use toMap.");
256+
}
257+
258+
protected void convertToMap(Object target, Object map) {
259+
if (circulars == null) {
260+
circulars = new ArrayList<>();
261+
}
262+
if (circulars.contains(((JSObject) target).getPointer())) {
263+
// Circular reference objects, no processing needed.
264+
return;
265+
}
266+
267+
circulars.add(((JSObject) target).getPointer());
268+
269+
boolean isArray = target instanceof JSArray;
270+
JSArray array = isArray ? (JSArray) target : ((JSObject) target).getNames();
271+
int length = array.length();
272+
for (int i = 0; i < length; i++) {
273+
String key = null;
274+
Object value;
275+
if (isArray) {
276+
value = array.get(i);
277+
} else {
278+
key = (String) array.get(i);
279+
value = ((JSObject) target).getProperty(key);
280+
}
281+
282+
if (value instanceof JSFunction) {
283+
// Unsupported type.
284+
((JSFunction) value).release();
285+
continue;
286+
}
287+
288+
if (value instanceof JSArray) {
289+
ArrayList<Object> list = new ArrayList<>(((JSArray) value).length());
290+
convertToMap(value, list);
291+
if (!list.isEmpty()) {
292+
if (map instanceof HashMap) {
293+
((HashMap<String, Object>) map).put(key, list);
294+
} else if (map instanceof ArrayList){
295+
((ArrayList<Object>) map).add(list);
296+
}
297+
}
298+
((JSArray) value).release();
299+
continue;
300+
}
301+
302+
if (value instanceof JSObject) {
303+
HashMap<String, Object> valueMap = new HashMap<>();
304+
convertToMap(value, valueMap);
305+
if (!valueMap.isEmpty()) {
306+
if (map instanceof HashMap) {
307+
((HashMap<String, Object>) map).put(key, valueMap);
308+
} else if (map instanceof ArrayList){
309+
((ArrayList<Object>) map).add(valueMap);
310+
}
311+
}
312+
((JSObject) value).release();
313+
continue;
314+
}
315+
316+
// Primitive types.
317+
if (map instanceof HashMap) {
318+
((HashMap<String, Object>) map).put(key, value);
319+
} else if (map instanceof ArrayList){
320+
((ArrayList<Object>) map).add(value);
321+
}
322+
}
323+
if (!isArray) {
324+
array.release();
325+
}
326+
}
327+
242328
public int getRefCount() {
243329
return refCount;
244330
}

0 commit comments

Comments
 (0)