Browse Source

Parse ReadableMap to JSONObject without conversion to HashMap

This should fix conversion issues found in RN 0.54
Guy Carmeli 6 years ago
parent
commit
f79b3109a9

+ 85
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/parsers/JSONParser.java View File

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 View File

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

+ 64
- 0
lib/android/app/src/test/java/com/reactnativenavigation/parse/parsers/JSONParserTest.java View File

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
+}