• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package io.flutter.plugin.common;
6 
7 import java.nio.ByteBuffer;
8 import org.json.JSONArray;
9 import org.json.JSONException;
10 import org.json.JSONObject;
11 
12 /**
13  * A {@link MethodCodec} using UTF-8 encoded JSON method calls and result envelopes.
14  *
15  * <p>This codec is guaranteed to be compatible with the corresponding
16  * <a href="https://docs.flutter.io/flutter/services/JSONMethodCodec-class.html">JSONMethodCodec</a>
17  * on the Dart side. These parts of the Flutter SDK are evolved synchronously.</p>
18  *
19  * <p>Values supported as methods arguments and result payloads are those supported by
20  * {@link JSONMessageCodec}.</p>
21  */
22 public final class JSONMethodCodec implements MethodCodec {
23     // This codec must match the Dart codec of the same name in package flutter/services.
24     public static final JSONMethodCodec INSTANCE = new JSONMethodCodec();
25 
JSONMethodCodec()26     private JSONMethodCodec() {
27     }
28 
29     @Override
encodeMethodCall(MethodCall methodCall)30     public ByteBuffer encodeMethodCall(MethodCall methodCall) {
31        try {
32           final JSONObject map = new JSONObject();
33           map.put("method", methodCall.method);
34           map.put("args", JSONUtil.wrap(methodCall.arguments));
35           return JSONMessageCodec.INSTANCE.encodeMessage(map);
36        } catch (JSONException e) {
37           throw new IllegalArgumentException("Invalid JSON", e);
38        }
39     }
40 
41     @Override
decodeMethodCall(ByteBuffer message)42     public MethodCall decodeMethodCall(ByteBuffer message) {
43         try {
44             final Object json = JSONMessageCodec.INSTANCE.decodeMessage(message);
45             if (json instanceof JSONObject) {
46                 final JSONObject map = (JSONObject) json;
47                 final Object method = map.get("method");
48                 final Object arguments = unwrapNull(map.opt("args"));
49                 if (method instanceof String) {
50                     return new MethodCall((String) method, arguments);
51                 }
52             }
53             throw new IllegalArgumentException("Invalid method call: " + json);
54         } catch (JSONException e) {
55             throw new IllegalArgumentException("Invalid JSON", e);
56         }
57     }
58 
59     @Override
encodeSuccessEnvelope(Object result)60     public ByteBuffer encodeSuccessEnvelope(Object result) {
61         return JSONMessageCodec.INSTANCE
62             .encodeMessage(new JSONArray().put(JSONUtil.wrap(result)));
63     }
64 
65     @Override
encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails)66     public ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage,
67         Object errorDetails) {
68         return JSONMessageCodec.INSTANCE.encodeMessage(new JSONArray()
69             .put(errorCode)
70             .put(JSONUtil.wrap(errorMessage))
71             .put(JSONUtil.wrap(errorDetails)));
72     }
73 
74     @Override
decodeEnvelope(ByteBuffer envelope)75     public Object decodeEnvelope(ByteBuffer envelope) {
76         try {
77             final Object json = JSONMessageCodec.INSTANCE.decodeMessage(envelope);
78             if (json instanceof JSONArray) {
79                 final JSONArray array = (JSONArray) json;
80                 if (array.length() == 1) {
81                     return unwrapNull(array.opt(0));
82                 }
83                 if (array.length() == 3) {
84                     final Object code = array.get(0);
85                     final Object message = unwrapNull(array.opt(1));
86                     final Object details = unwrapNull(array.opt(2));
87                     if (code instanceof String && (message == null || message instanceof String)) {
88                         throw new FlutterException((String) code, (String) message, details);
89                     }
90                 }
91             }
92             throw new IllegalArgumentException("Invalid envelope: " + json);
93         } catch (JSONException e) {
94             throw new IllegalArgumentException("Invalid JSON", e);
95         }
96     }
97 
unwrapNull(Object value)98     Object unwrapNull(Object value) {
99       return (value == JSONObject.NULL) ? null : value;
100     }
101 }
102