Parcourir la source

Parse ReadableMap to JSONObject without conversion to HashMap

This should fix conversion issues found in RN 0.54
Guy Carmeli il y a 6 ans
Parent
révision
f79b3109a9

+ 85
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/parsers/JSONParser.java Voir le fichier

@@ -0,0 +1,85 @@
1
+package com.reactnativenavigation.parse.parsers;
2
+
3
+import com.facebook.react.bridge.ReadableArray;
4
+import com.facebook.react.bridge.ReadableMap;
5
+import com.facebook.react.bridge.ReadableMapKeySetIterator;
6
+
7
+import org.json.JSONArray;
8
+import org.json.JSONException;
9
+import org.json.JSONObject;
10
+
11
+public class JSONParser {
12
+    public static JSONObject parse(ReadableMap map) {
13
+        try {
14
+            ReadableMapKeySetIterator it = map.keySetIterator();
15
+            JSONObject result = new JSONObject();
16
+            while (it.hasNextKey()) {
17
+                String key = it.nextKey();
18
+                switch (map.getType(key)) {
19
+                    case String:
20
+                        result.put(key, map.getString(key));
21
+                        break;
22
+                    case Number:
23
+                        result.put(key, parseNumber(map, key));
24
+                        break;
25
+                    case Boolean:
26
+                        result.put(key, map.getBoolean(key));
27
+                        break;
28
+                    case Array:
29
+                        result.put(key, parse(map.getArray(key)));
30
+                        break;
31
+                    case Map:
32
+                        result.put(key, parse(map.getMap(key)));
33
+                        break;
34
+                    default:
35
+                        break;
36
+                }
37
+            }
38
+            return result;
39
+        } catch (JSONException e) {
40
+            throw new RuntimeException(e);
41
+        }
42
+    }
43
+
44
+    public static JSONArray parse(ReadableArray arr) {
45
+        JSONArray result = new JSONArray();
46
+        for (int i = 0; i < arr.size(); i++) {
47
+            switch (arr.getType(i)) {
48
+                case String:
49
+                    result.put(arr.getString(i));
50
+                    break;
51
+                case Number:
52
+                    result.put(parseNumber(arr, i));
53
+                    break;
54
+                case Boolean:
55
+                    result.put(arr.getBoolean(i));
56
+                    break;
57
+                case Array:
58
+                    result.put(parse(arr.getArray(i)));
59
+                    break;
60
+                case Map:
61
+                    result.put(parse(arr.getMap(i)));
62
+                    break;
63
+                default:
64
+                    break;
65
+            }
66
+        }
67
+        return result;
68
+    }
69
+
70
+    private static Object parseNumber(ReadableMap map, String key) {
71
+        try {
72
+            return map.getInt(key);
73
+        } catch (Exception e) {
74
+            return map.getDouble(key);
75
+        }
76
+    }
77
+
78
+    private static Object parseNumber(ReadableArray arr, int index) {
79
+        try {
80
+            return arr.getInt(index);
81
+        } catch (Exception e) {
82
+            return arr.getDouble(index);
83
+        }
84
+    }
85
+}

+ 8
- 9
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java Voir le fichier

@@ -13,6 +13,7 @@ import com.reactnativenavigation.NavigationApplication;
13 13
 import com.reactnativenavigation.parse.LayoutFactory;
14 14
 import com.reactnativenavigation.parse.LayoutNode;
15 15
 import com.reactnativenavigation.parse.Options;
16
+import com.reactnativenavigation.parse.parsers.JSONParser;
16 17
 import com.reactnativenavigation.parse.parsers.LayoutNodeParser;
17 18
 import com.reactnativenavigation.utils.NativeCommandListener;
18 19
 import com.reactnativenavigation.utils.Now;
@@ -23,8 +24,6 @@ import com.reactnativenavigation.viewcontrollers.Navigator;
23 24
 import com.reactnativenavigation.viewcontrollers.ViewController;
24 25
 import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator;
25 26
 
26
-import org.json.JSONObject;
27
-
28 27
 import java.util.HashMap;
29 28
 import java.util.Map;
30 29
 
@@ -57,7 +56,7 @@ public class NavigationModule extends ReactContextBaseJavaModule {
57 56
 
58 57
 	@ReactMethod
59 58
 	public void setRoot(String commandId, ReadableMap rawLayoutTree, Promise promise) {
60
-		final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.getMap("root").toHashMap()));
59
+		final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree).optJSONObject("root"));
61 60
 		handle(() -> {
62 61
             final ViewController viewController = newLayoutFactory().create(layoutTree);
63 62
             navigator().setRoot(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
@@ -66,19 +65,19 @@ public class NavigationModule extends ReactContextBaseJavaModule {
66 65
 
67 66
 	@ReactMethod
68 67
 	public void setDefaultOptions(ReadableMap options) {
69
-        final Options defaultOptions = Options.parse(new TypefaceLoader(activity()), new JSONObject(options.toHashMap()));
68
+        final Options defaultOptions = Options.parse(new TypefaceLoader(activity()), JSONParser.parse(options));
70 69
         handle(() -> navigator().setDefaultOptions(defaultOptions));
71 70
     }
72 71
 
73 72
 	@ReactMethod
74 73
 	public void mergeOptions(String onComponentId, ReadableMap options) {
75
-		final Options navOptions = Options.parse(new TypefaceLoader(activity()), new JSONObject(options.toHashMap()));
74
+		final Options navOptions = Options.parse(new TypefaceLoader(activity()), JSONParser.parse(options));
76 75
 		handle(() -> navigator().mergeOptions(onComponentId, navOptions));
77 76
 	}
78 77
 
79 78
 	@ReactMethod
80 79
 	public void push(String commandId, String onComponentId, ReadableMap rawLayoutTree, Promise promise) {
81
-		final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.toHashMap()));
80
+		final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
82 81
 		handle(() -> {
83 82
             final ViewController viewController = newLayoutFactory().create(layoutTree);
84 83
             navigator().push(onComponentId, viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
@@ -87,7 +86,7 @@ public class NavigationModule extends ReactContextBaseJavaModule {
87 86
 
88 87
     @ReactMethod
89 88
     public void setStackRoot(String commandId, String onComponentId, ReadableMap rawLayoutTree, Promise promise) {
90
-        final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.toHashMap()));
89
+        final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
91 90
         handle(() -> {
92 91
             final ViewController viewController = newLayoutFactory().create(layoutTree);
93 92
             navigator().setStackRoot(onComponentId, viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
@@ -111,7 +110,7 @@ public class NavigationModule extends ReactContextBaseJavaModule {
111 110
 
112 111
 	@ReactMethod
113 112
 	public void showModal(String commandId, ReadableMap rawLayoutTree, Promise promise) {
114
-		final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.toHashMap()));
113
+		final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
115 114
 		handle(() -> {
116 115
             final ViewController viewController = newLayoutFactory().create(layoutTree);
117 116
             navigator().showModal(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
@@ -130,7 +129,7 @@ public class NavigationModule extends ReactContextBaseJavaModule {
130 129
 
131 130
 	@ReactMethod
132 131
 	public void showOverlay(String commandId, ReadableMap rawLayoutTree, Promise promise) {
133
-        final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.toHashMap()));
132
+        final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
134 133
         handle(() -> {
135 134
             final ViewController viewController = newLayoutFactory().create(layoutTree);
136 135
             navigator().showOverlay(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));

+ 64
- 0
lib/android/app/src/test/java/com/reactnativenavigation/parse/parsers/JSONParserTest.java Voir le fichier

@@ -0,0 +1,64 @@
1
+package com.reactnativenavigation.parse.parsers;
2
+
3
+import com.facebook.react.bridge.JavaOnlyArray;
4
+import com.facebook.react.bridge.JavaOnlyMap;
5
+import com.reactnativenavigation.BaseTest;
6
+
7
+import org.json.JSONArray;
8
+import org.json.JSONObject;
9
+import org.junit.Test;
10
+
11
+import static org.assertj.core.api.Java6Assertions.assertThat;
12
+
13
+public class JSONParserTest extends BaseTest {
14
+    @Test
15
+    public void parsesMap() throws Exception {
16
+        JavaOnlyMap input = new JavaOnlyMap();
17
+        input.putString("keyString", "stringValue");
18
+        input.putInt("keyInt", 123);
19
+        input.putDouble("keyDouble", 123.456);
20
+        input.putBoolean("keyBoolean", true);
21
+        input.putArray("keyArray", new JavaOnlyArray());
22
+        input.putMap("keyMap", new JavaOnlyMap());
23
+        input.putNull("bla");
24
+
25
+        JSONObject result = JSONParser.parse(input);
26
+
27
+
28
+        assertThat(result.keys()).containsOnly(
29
+                "keyString",
30
+                "keyInt",
31
+                "keyDouble",
32
+                "keyBoolean",
33
+                "keyMap",
34
+                "keyArray");
35
+
36
+        assertThat(result.get("keyString")).isEqualTo("stringValue");
37
+        assertThat(result.get("keyInt")).isEqualTo(123);
38
+        assertThat(result.get("keyDouble")).isEqualTo(123.456);
39
+        assertThat(result.get("keyBoolean")).isEqualTo(true);
40
+        assertThat(result.getJSONObject("keyMap").keys()).isEmpty();
41
+        assertThat(result.getJSONArray("keyArray").length()).isZero();
42
+    }
43
+
44
+    @Test
45
+    public void parsesArrays() throws Exception {
46
+        JavaOnlyArray input = new JavaOnlyArray();
47
+        input.pushString("Hello");
48
+        input.pushInt(123);
49
+        input.pushDouble(123.456);
50
+        input.pushBoolean(true);
51
+        input.pushArray(new JavaOnlyArray());
52
+        input.pushMap(new JavaOnlyMap());
53
+        input.pushNull();
54
+
55
+        JSONArray result = JSONParser.parse(input);
56
+        assertThat(result.length()).isEqualTo(6);
57
+        assertThat(result.get(0)).isEqualTo("Hello");
58
+        assertThat(result.get(1)).isEqualTo(123);
59
+        assertThat(result.get(2)).isEqualTo(123.456);
60
+        assertThat(result.get(3)).isEqualTo(true);
61
+        assertThat(result.getJSONArray(4).length()).isZero();
62
+        assertThat(result.getJSONObject(5).keys()).isEmpty();
63
+    }
64
+}