summaryrefslogtreecommitdiff
path: root/platform/android/src/gson/json_element.cpp
blob: 405efe71ca47bf2c30091b75088e5cfa9f3696b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "json_element.hpp"
#include "json_array.hpp"
#include "json_object.hpp"
#include "json_primitive.hpp"
#include "../math/math.hpp"

namespace mbgl {
namespace android {
namespace gson {

jni::Local<jni::Object<JsonElement>> JsonElement::New(jni::JNIEnv& env, const mbgl::Value& value) {
    static auto& primitive = jni::Class<JsonPrimitive>::Singleton(env);
    static auto stringConstructor = primitive.GetConstructor<jni::String>(env);
    static auto numberConstructor = primitive.GetConstructor<jni::Number>(env);
    static auto booleanConstructor = primitive.GetConstructor<jni::Boolean>(env);

    return value.match(
        [&] (const mbgl::NullValue&) {
            return jni::Local<jni::Object<JsonElement>>();
        },
        [&] (const std::string& value) {
            return primitive.New(env, stringConstructor, jni::Make<jni::String>(env, value));
        },
        [&] (const double value) {
            return primitive.New(env, numberConstructor, jni::Box(env, value));
        },
        [&] (const int64_t value) {
            return primitive.New(env, numberConstructor, jni::Box(env, value));
        },
        [&] (const uint64_t value) {
            return primitive.New(env, numberConstructor, jni::Box(env, int64_t(value))); // TODO: should use BigInteger
        },
        [&] (const bool value) {
            return primitive.New(env, booleanConstructor, jni::Box(env, value ? jni::jni_true : jni::jni_false));
        },
        [&] (const std::vector<mbgl::Value>& values) {
            return JsonArray::New(env, values);
        },
        [&] (const mbgl::PropertyMap& values) {
            return JsonObject::New(env, values);
        }
    );
}

mbgl::Value JsonElement::convert(jni::JNIEnv &env, const jni::Object<JsonElement>& jsonElement) {
    if (!jsonElement) {
        return mbgl::NullValue();
    }

    static auto& elementClass = jni::Class<JsonElement>::Singleton(env);
    static auto isJsonObject = elementClass.GetMethod<jni::jboolean ()>(env, "isJsonObject");
    static auto isJsonArray = elementClass.GetMethod<jni::jboolean ()>(env, "isJsonArray");
    static auto isJsonPrimitive = elementClass.GetMethod<jni::jboolean ()>(env, "isJsonPrimitive");

    static auto& primitiveClass = jni::Class<JsonPrimitive>::Singleton(env);
    static auto isBoolean = primitiveClass.GetMethod<jni::jboolean ()>(env, "isBoolean");
    static auto isString = primitiveClass.GetMethod<jni::jboolean ()>(env, "isString");
    static auto isNumber = primitiveClass.GetMethod<jni::jboolean ()>(env, "isNumber");
    static auto getAsBoolean = primitiveClass.GetMethod<jni::jboolean ()>(env, "getAsBoolean");
    static auto getAsString = primitiveClass.GetMethod<jni::String ()>(env, "getAsString");
    static auto getAsDouble = primitiveClass.GetMethod<jni::jdouble ()>(env, "getAsDouble");
    static auto getAsInteger = primitiveClass.GetMethod<jni::jint ()>(env, "getAsInt");

    if (jsonElement.Call(env, isJsonPrimitive)) {
        auto primitive = jni::Cast(env, primitiveClass, jsonElement);
        if (primitive.Call(env, isBoolean)) {
            return bool(primitive.Call(env, getAsBoolean));
        } else if (primitive.Call(env, isNumber)) {
            auto value = primitive.Call(env, getAsDouble);
            if (value == math::Math::rint(env, value)) {
                // uint64_t
                return static_cast<uint64_t>(primitive.Call(env, getAsInteger));
            } else {
                // double
                return value;
            }
        } else if (primitive.Call(env, isString)) {
            return jni::Make<std::string>(env, primitive.Call(env, getAsString));
        } else {
            return mbgl::NullValue();
        }
    } else if (jsonElement.Call(env, isJsonObject)) {
        return JsonObject::convert(env, jni::Cast(env, jni::Class<JsonObject>::Singleton(env), jsonElement));
    } else if (jsonElement.Call(env, isJsonArray)) {
        return JsonArray::convert(env, jni::Cast(env, jni::Class<JsonArray>::Singleton(env), jsonElement));
    } else {
        return mbgl::NullValue();
    }
}

void JsonElement::registerNative(jni::JNIEnv &env) {
    jni::Class<JsonElement>::Singleton(env);
}

} // namespace gson
} // namespace android
} // namespace mbgl