diff options
author | Marcel Admiraal <madmiraal@users.noreply.github.com> | 2020-12-29 18:12:33 +0000 |
---|---|---|
committer | Marcel Admiraal <madmiraal@users.noreply.github.com> | 2021-06-19 08:01:40 +0100 |
commit | 2bafcd3422bea8baf2282f5de87538a59f0bb254 (patch) | |
tree | 7c9d09df5f4d8d0a575f53724eb95b02521fb5e8 | |
parent | df170c8af05c7e81a83ddae4e4d62c65d7086bc3 (diff) |
Consolidate JSON, JSONParseResults and JSONParser into JSON
Renames JSON.parse_string() to parse()
Renames JSON.decode_data() to stringify()
25 files changed, 186 insertions, 428 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 60759cd71c..67e9192930 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -35,7 +35,6 @@ #include "core/debugger/engine_debugger.h" #include "core/io/file_access_compressed.h" #include "core/io/file_access_encrypted.h" -#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" @@ -2137,80 +2136,6 @@ void _Engine::_bind_methods() { _Engine *_Engine::singleton = nullptr; -////// _JSON ////// - -void JSONParseResult::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_error"), &JSONParseResult::get_error); - ClassDB::bind_method(D_METHOD("get_error_string"), &JSONParseResult::get_error_string); - ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParseResult::get_error_line); - ClassDB::bind_method(D_METHOD("get_result"), &JSONParseResult::get_result); - - ClassDB::bind_method(D_METHOD("set_error", "error"), &JSONParseResult::set_error); - ClassDB::bind_method(D_METHOD("set_error_string", "error_string"), &JSONParseResult::set_error_string); - ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line); - ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result"); -} - -void JSONParseResult::set_error(Error p_error) { - error = p_error; -} - -Error JSONParseResult::get_error() const { - return error; -} - -void JSONParseResult::set_error_string(const String &p_error_string) { - error_string = p_error_string; -} - -String JSONParseResult::get_error_string() const { - return error_string; -} - -void JSONParseResult::set_error_line(int p_error_line) { - error_line = p_error_line; -} - -int JSONParseResult::get_error_line() const { - return error_line; -} - -void JSONParseResult::set_result(const Variant &p_result) { - result = p_result; -} - -Variant JSONParseResult::get_result() const { - return result; -} - -void _JSON::_bind_methods() { - ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys", "full_precision"), &_JSON::print, DEFVAL(String()), DEFVAL(false), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse); -} - -String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys, bool p_full_precision) { - return JSON::print(p_value, p_indent, p_sort_keys, p_full_precision); -} - -Ref<JSONParseResult> _JSON::parse(const String &p_json) { - Ref<JSONParseResult> result; - result.instance(); - - result->error = JSON::parse(p_json, result->result, result->error_string, result->error_line); - - if (result->error != OK) { - ERR_PRINT(vformat("Error parsing JSON at line %s: %s", result->error_line, result->error_string)); - } - return result; -} - -_JSON *_JSON::singleton = nullptr; - ////// _EngineDebugger ////// void _EngineDebugger::_bind_methods() { diff --git a/core/core_bind.h b/core/core_bind.h index b161effe95..8127ed56bc 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -656,54 +656,6 @@ public: _Engine() { singleton = this; } }; -class _JSON; - -class JSONParseResult : public RefCounted { - GDCLASS(JSONParseResult, RefCounted); - - friend class _JSON; - - Error error; - String error_string; - int error_line = -1; - - Variant result; - -protected: - static void _bind_methods(); - -public: - void set_error(Error p_error); - Error get_error() const; - - void set_error_string(const String &p_error_string); - String get_error_string() const; - - void set_error_line(int p_error_line); - int get_error_line() const; - - void set_result(const Variant &p_result); - Variant get_result() const; - - JSONParseResult() {} -}; - -class _JSON : public Object { - GDCLASS(_JSON, Object); - -protected: - static void _bind_methods(); - static _JSON *singleton; - -public: - static _JSON *get_singleton() { return singleton; } - - String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false, bool p_full_precision = false); - Ref<JSONParseResult> parse(const String &p_json); - - _JSON() { singleton = this; } -}; - class _EngineDebugger : public Object { GDCLASS(_EngineDebugger, Object); diff --git a/core/io/json.cpp b/core/io/json.cpp index 82ef2a6894..b3a2498212 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -45,7 +45,7 @@ const char *JSON::tk_name[TK_MAX] = { "EOF", }; -static String _make_indent(const String &p_indent, int p_size) { +String JSON::_make_indent(const String &p_indent, int p_size) { String indent_text = ""; if (!p_indent.is_empty()) { for (int i = 0; i < p_size; i++) { @@ -55,7 +55,7 @@ static String _make_indent(const String &p_indent, int p_size) { return indent_text; } -String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) { +String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) { String colon = ":"; String end_statement = ""; @@ -100,7 +100,7 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); + s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "]"; p_markers.erase(a.id()); @@ -126,9 +126,9 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers); + s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers); s += colon; - s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); + s += _stringify(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "}"; @@ -140,11 +140,6 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ } } -String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { - Set<const void *> markers; - return _print_var(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); -} - Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) { while (p_len > 0) { switch (p_str[index]) { @@ -499,7 +494,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, return ERR_PARSE_ERROR; } -Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { +Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { const char32_t *str = p_json.ptr(); int idx = 0; int len = p_json.length(); @@ -530,34 +525,24 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int & return err; } -Error JSONParser::parse_string(const String &p_json_string) { - return JSON::parse(p_json_string, data, err_text, err_line); -} -String JSONParser::get_error_text() const { - return err_text; -} -int JSONParser::get_error_line() const { - return err_line; -} -Variant JSONParser::get_data() const { - return data; +String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { + Set<const void *> markers; + return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); } -Error JSONParser::decode_data(const Variant &p_data, const String &p_indent, bool p_sort_keys) { - string = JSON::print(p_data, p_indent, p_sort_keys); - data = p_data; - return OK; +Error JSON::parse(const String &p_json_string) { + Error err = _parse_string(p_json_string, data, err_str, err_line); + if (err == Error::OK) { + err_line = 0; + } + return err; } -String JSONParser::get_string() const { - return string; -} +void JSON::_bind_methods() { + ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); -void JSONParser::_bind_methods() { - ClassDB::bind_method(D_METHOD("parse_string", "json_string"), &JSONParser::parse_string); - ClassDB::bind_method(D_METHOD("get_error_text"), &JSONParser::get_error_text); - ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParser::get_error_line); - ClassDB::bind_method(D_METHOD("get_data"), &JSONParser::get_data); - ClassDB::bind_method(D_METHOD("decode_data", "data", "indent", "sort_keys"), &JSONParser::decode_data, DEFVAL(""), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_string"), &JSONParser::get_string); + ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data); + ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line); + ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message); } diff --git a/core/io/json.h b/core/io/json.h index 5be8cc1e86..f20c97f540 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -33,7 +33,10 @@ #include "core/object/ref_counted.h" #include "core/variant/variant.h" -class JSON { + +class JSON : public RefCounted { + GDCLASS(JSON, RefCounted); + enum TokenType { TK_CURLY_BRACKET_OPEN, TK_CURLY_BRACKET_CLOSE, @@ -60,39 +63,30 @@ class JSON { Variant value; }; - static const char *tk_name[TK_MAX]; + Variant data; + String err_str; + int err_line = 0; - static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false); + static const char *tk_name[]; + static String _make_indent(const String &p_indent, int p_size); + static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false); static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); - -public: - static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); - static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); -}; - -class JSONParser : public RefCounted { - GDCLASS(JSONParser, RefCounted); - - Variant data; - String string; - String err_text; - int err_line = 0; + static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); protected: static void _bind_methods(); public: - Error parse_string(const String &p_json_string); - String get_error_text() const; - int get_error_line() const; - Variant get_data() const; + String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); + Error parse(const String &p_json_string); - Error decode_data(const Variant &p_data, const String &p_indent = "", bool p_sort_keys = true); - String get_string() const; + inline Variant get_data() const { return data; } + inline int get_error_line() const { return err_line; } + inline String get_error_message() const { return err_str; } }; #endif // JSON_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index f67d615418..fc8ab72e1a 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -86,7 +86,6 @@ static _OS *_os = nullptr; static _Engine *_engine = nullptr; static _ClassDB *_classdb = nullptr; static _Marshalls *_marshalls = nullptr; -static _JSON *_json = nullptr; static _EngineDebugger *_engine_debugger = nullptr; static IP *ip = nullptr; @@ -199,7 +198,7 @@ void register_core_types() { ClassDB::register_class<_Semaphore>(); ClassDB::register_class<XMLParser>(); - ClassDB::register_class<JSONParser>(); + ClassDB::register_class<JSON>(); ClassDB::register_class<ConfigFile>(); @@ -212,8 +211,6 @@ void register_core_types() { ClassDB::register_class<EncodedObjectAsID>(); ClassDB::register_class<RandomNumberGenerator>(); - ClassDB::register_class<JSONParseResult>(); - ClassDB::register_virtual_class<ResourceImporter>(); ip = IP::create(); @@ -227,7 +224,6 @@ void register_core_types() { _engine = memnew(_Engine); _classdb = memnew(_ClassDB); _marshalls = memnew(_Marshalls); - _json = memnew(_JSON); _engine_debugger = memnew(_EngineDebugger); } @@ -256,7 +252,6 @@ void register_core_singletons() { ClassDB::register_class<TranslationServer>(); ClassDB::register_virtual_class<Input>(); ClassDB::register_class<InputMap>(); - ClassDB::register_class<_JSON>(); ClassDB::register_class<Expression>(); ClassDB::register_class<_EngineDebugger>(); ClassDB::register_class<Time>(); @@ -274,7 +269,6 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("TranslationServer", TranslationServer::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton())); } @@ -286,7 +280,6 @@ void unregister_core_types() { memdelete(_engine); memdelete(_classdb); memdelete(_marshalls); - memdelete(_json); memdelete(_engine_debugger); memdelete(_geometry_2d); diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 4e45862fd3..badb5ba103 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -32,6 +32,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" +#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/io/resource.h" #include "core/math/math_funcs.h" @@ -1838,6 +1839,11 @@ String Variant::stringify(List<const void *> &stack) const { return ""; } +String Variant::to_json_string() const { + JSON json; + return json.stringify(*this); +} + Variant::operator Vector2() const { if (type == VECTOR2) { return *reinterpret_cast<const Vector2 *>(_data._mem); diff --git a/core/variant/variant.h b/core/variant/variant.h index 75316da63f..125173ea5c 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -645,6 +645,7 @@ public: bool hash_compare(const Variant &p_variant) const; bool booleanize() const; String stringify(List<const void *> &stack) const; + String to_json_string() const; void static_assign(const Variant &p_variant); static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 552fc41318..fa118bec54 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1066,11 +1066,13 @@ <description> Returns the internal type of the given Variant object, using the [enum Variant.Type] values. [codeblock] - p = parse_json('["a", "b", "c"]') - if typeof(p) == TYPE_ARRAY: - print(p[0]) # Prints a + var json = JSON.new() + json.parse('["a", "b", "c"]') + var result = json.get_data() + if typeof(result) == TYPE_ARRAY: + print(result[0]) # Prints a else: - print("unexpected results") + print("Unexpected result") [/codeblock] </description> </method> @@ -1211,9 +1213,6 @@ <member name="InputMap" type="InputMap" setter="" getter=""> The [InputMap] singleton. </member> - <member name="JSON" type="JSON" setter="" getter=""> - The [JSON] singleton. - </member> <member name="JavaClassWrapper" type="JavaClassWrapper" setter="" getter=""> The [JavaClassWrapper] singleton. [b]Note:[/b] Only implemented on Android. diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 7baff7aa39..b95aaed143 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -1,45 +1,88 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="JSON" inherits="Object" version="4.0"> +<class name="JSON" inherits="RefCounted" version="4.0"> <brief_description> - Helper class for parsing JSON data. + Helper class for creating and parsing JSON data. </brief_description> <description> - Helper class for parsing JSON data. For usage example and other important hints, see [JSONParseResult]. + The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network. + [method stringify] is used to convert any data type into a JSON string. + [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. + [b]Example[/b] + [codeblock] + var data_to_send = ["a", "b", "c"] + var json = JSON.new() + var json_string = json.stringify(data_to_send) + # Save data + # ... + # Retrieve data + var error = json.parse(json_string) + if error == OK: + var data_received = json.get_data() + if typeof(data_received) == TYPE_ARRAY: + print(data_received) # Prints array + else: + print("Unexpected data") + else: + print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line()) + [/codeblock] </description> <tutorials> </tutorials> <methods> + <method name="get_data" qualifiers="const"> + <return type="Variant"> + </return> + <description> + Returns the [Variant] containing the data of a successful [method parse]. + [b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called. + </description> + </method> + <method name="get_error_line" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns [code]0[/code] if the last call to [method parse] was successful, or the line number where the parse failed. + </description> + </method> + <method name="get_error_message" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns an empty string if the last call to [method parse] was successful, or the error message if it failed. + </description> + </method> <method name="parse"> - <return type="JSONParseResult"> + <return type="int" enum="Error"> </return> - <argument index="0" name="json" type="String"> + <argument index="0" name="json_string" type="String"> </argument> <description> - Parses a JSON-encoded string and returns a [JSONParseResult] containing the result. + Attempts to parse the [code]json_string[/code] provided. + Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. </description> </method> - <method name="print"> + <method name="stringify"> <return type="String"> </return> - <argument index="0" name="value" type="Variant"> + <argument index="0" name="data" type="Variant"> </argument> <argument index="1" name="indent" type="String" default=""""> </argument> - <argument index="2" name="sort_keys" type="bool" default="false"> + <argument index="2" name="sort_keys" type="bool" default="true"> </argument> <argument index="3" name="full_precision" type="bool" default="false"> </argument> <description> Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network. [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types. - [b]Note:[/b] If [code]full_precision[/code] is true, when printing floats, the unreliable digits are printed in addition to the reliable digits to guarantee exact decoding. - Use [code]indent[/code] parameter to pretty print the output. + [b]Note:[/b] If [code]full_precision[/code] is true, when stringifying floats, the unreliable digits are stringified in addition to the reliable digits to guarantee exact decoding. + Use [code]indent[/code] parameter to pretty stringify the output. [b]Example output:[/b] [codeblock] - ## JSON.print(my_dictionary) + ## JSON.stringify(my_dictionary) {"name":"my_dictionary","version":"1.0.0","entities":[{"name":"entity_0","value":"value_0"},{"name":"entity_1","value":"value_1"}]} - ## JSON.print(my_dictionary, "\t") + ## JSON.stringify(my_dictionary, "\t") { "name": "my_dictionary", "version": "1.0.0", diff --git a/doc/classes/JSONParseResult.xml b/doc/classes/JSONParseResult.xml deleted file mode 100644 index 7311343b68..0000000000 --- a/doc/classes/JSONParseResult.xml +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="JSONParseResult" inherits="RefCounted" version="4.0"> - <brief_description> - Data class wrapper for decoded JSON. - </brief_description> - <description> - Returned by [method JSON.parse], [JSONParseResult] contains the decoded JSON or error information if the JSON source wasn't successfully parsed. You can check if the JSON source was successfully parsed with [code]if json_result.error == OK[/code]. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <members> - <member name="error" type="int" setter="set_error" getter="get_error" enum="Error"> - The error type if the JSON source was not successfully parsed. See the [enum Error] constants. - </member> - <member name="error_line" type="int" setter="set_error_line" getter="get_error_line" default="-1"> - The line number where the error occurred if the JSON source was not successfully parsed. - </member> - <member name="error_string" type="String" setter="set_error_string" getter="get_error_string" default=""""> - The error message if the JSON source was not successfully parsed. See the [enum Error] constants. - </member> - <member name="result" type="Variant" setter="set_result" getter="get_result"> - A [Variant] containing the parsed JSON. Use [method @GlobalScope.typeof] or the [code]is[/code] keyword to check if it is what you expect. For example, if the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] will be returned. If the JSON source starts with brackets ([code][][/code]), an [Array] will be returned. - [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types. - [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: - [codeblocks] - [gdscript] - var p = JSON.parse('["hello", "world", "!"]') - if typeof(p.result) == TYPE_ARRAY: - print(p.result[0]) # Prints "hello" - else: - push_error("Unexpected results.") - [/gdscript] - [csharp] - JSONParseResult p = JSON.Parse("[\"hello\"], \"world\", \"!\"]"); - if (p.Result is Godot.Collections.Array) - { - GD.Print((p.Result as Godot.Collections.Array)[0]); // Prints "hello" - } - else - { - GD.PushError("Unexpected results."); - } - [/csharp] - [/codeblocks] - </member> - </members> - <constants> - </constants> -</class> diff --git a/doc/classes/JSONParser.xml b/doc/classes/JSONParser.xml deleted file mode 100644 index 991629f255..0000000000 --- a/doc/classes/JSONParser.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="JSONParser" inherits="RefCounted" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <methods> - <method name="decode_data"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="data" type="Variant"> - </argument> - <argument index="1" name="indent" type="String" default=""""> - </argument> - <argument index="2" name="sort_keys" type="bool" default="true"> - </argument> - <description> - </description> - </method> - <method name="get_data" qualifiers="const"> - <return type="Variant"> - </return> - <description> - </description> - </method> - <method name="get_error_line" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> - <method name="get_error_text" qualifiers="const"> - <return type="String"> - </return> - <description> - </description> - </method> - <method name="get_string" qualifiers="const"> - <return type="String"> - </return> - <description> - </description> - </method> - <method name="parse_string"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="json_string" type="String"> - </argument> - <description> - </description> - </method> - </methods> - <constants> - </constants> -</class> diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 51c6b473ad..4151c51b26 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -161,21 +161,21 @@ String EditorFeatureProfile::get_feature_description(Feature p_feature) { } Error EditorFeatureProfile::save_to_file(const String &p_path) { - Dictionary json; - json["type"] = "feature_profile"; + Dictionary data; + data["type"] = "feature_profile"; Array dis_classes; for (Set<StringName>::Element *E = disabled_classes.front(); E; E = E->next()) { dis_classes.push_back(String(E->get())); } dis_classes.sort(); - json["disabled_classes"] = dis_classes; + data["disabled_classes"] = dis_classes; Array dis_editors; for (Set<StringName>::Element *E = disabled_editors.front(); E; E = E->next()) { dis_editors.push_back(String(E->get())); } dis_editors.sort(); - json["disabled_editors"] = dis_editors; + data["disabled_editors"] = dis_editors; Array dis_props; @@ -185,7 +185,7 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) { } } - json["disabled_properties"] = dis_props; + data["disabled_properties"] = dis_props; Array dis_features; for (int i = 0; i < FEATURE_MAX; i++) { @@ -194,12 +194,13 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) { } } - json["disabled_features"] = dis_features; + data["disabled_features"] = dis_features; FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE); ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); - String text = JSON::print(json, "\t"); + JSON json; + String text = json.stringify(data, "\t"); f->store_string(text); f->close(); return OK; @@ -212,26 +213,24 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) { return err; } - String err_str; - int err_line; - Variant v; - err = JSON::parse(text, v, err_str, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(err_line) + ": " + err_str); + ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(json.get_error_line()) + ": " + json.get_error_message()); return ERR_PARSE_ERROR; } - Dictionary json = v; + Dictionary data = json.get_data(); - if (!json.has("type") || String(json["type"]) != "feature_profile") { + if (!data.has("type") || String(data["type"]) != "feature_profile") { ERR_PRINT("Error parsing '" + p_path + "', it's not a feature profile."); return ERR_PARSE_ERROR; } disabled_classes.clear(); - if (json.has("disabled_classes")) { - Array disabled_classes_arr = json["disabled_classes"]; + if (data.has("disabled_classes")) { + Array disabled_classes_arr = data["disabled_classes"]; for (int i = 0; i < disabled_classes_arr.size(); i++) { disabled_classes.insert(disabled_classes_arr[i]); } @@ -239,8 +238,8 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) { disabled_editors.clear(); - if (json.has("disabled_editors")) { - Array disabled_editors_arr = json["disabled_editors"]; + if (data.has("disabled_editors")) { + Array disabled_editors_arr = data["disabled_editors"]; for (int i = 0; i < disabled_editors_arr.size(); i++) { disabled_editors.insert(disabled_editors_arr[i]); } @@ -248,16 +247,16 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) { disabled_properties.clear(); - if (json.has("disabled_properties")) { - Array disabled_properties_arr = json["disabled_properties"]; + if (data.has("disabled_properties")) { + Array disabled_properties_arr = data["disabled_properties"]; for (int i = 0; i < disabled_properties_arr.size(); i++) { String s = disabled_properties_arr[i]; set_disable_class_property(s.get_slice(":", 0), s.get_slice(":", 1), true); } } - if (json.has("disabled_features")) { - Array disabled_features_arr = json["disabled_features"]; + if (data.has("disabled_features")) { + Array disabled_features_arr = data["disabled_features"]; for (int i = 0; i < FEATURE_MAX; i++) { bool found = false; String f = feature_identifiers[i]; diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 76c6fcc3d3..dd4ce74406 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -242,10 +242,8 @@ void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code, response_json.parse_utf8((const char *)r, p_data.size()); } - Variant response; - String errs; - int errline; - Error err = JSON::parse(response_json, response, errs, errline); + JSON json; + Error err = json.parse(response_json); if (err != OK) { EditorNode::get_singleton()->show_warning(TTR("Error parsing JSON with the list of mirrors. Please report this issue!")); is_refreshing_mirrors = false; @@ -260,7 +258,7 @@ void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code, mirrors_available = false; - Dictionary data = response; + Dictionary data = json.get_data(); if (data.has("mirrors")) { Array mirrors = data["mirrors"]; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 93bb170128..f0254e5639 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -1098,11 +1098,9 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const Dictionary d; { - Variant js; - String errs; - int errl; - JSON::parse(str, js, errs, errl); - d = js; + JSON json; + json.parse(str); + d = json.get_data(); } RequestType requested = requesting; diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h index 6c15eb7e12..906a721045 100644 --- a/modules/fbx/tools/validation_tools.h +++ b/modules/fbx/tools/validation_tools.h @@ -34,8 +34,7 @@ #ifdef TOOLS_ENABLED #include "core/io/file_access.h" -#include "core/io/json.h" -#include "core/string/ustring.h" +#include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/map.h" diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 15236d900d..f817964a3c 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -32,7 +32,6 @@ #include "../gdscript.h" #include "../gdscript_analyzer.h" -#include "core/io/json.h" #include "gdscript_language_protocol.h" #include "gdscript_workspace.h" @@ -183,7 +182,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p symbol.detail += ": " + m.get_datatype().to_string(); } if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) { - symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value); + symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string(); } symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line)); @@ -224,10 +223,10 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } if (!value_text.is_empty()) { symbol.detail += " = " + value_text; @@ -353,8 +352,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN parameters += ": " + parameter->get_datatype().to_string(); } if (parameter->default_value != nullptr) { - String value = JSON::print(parameter->default_value->reduced_value); - parameters += " = " + value; + parameters += " = " + parameter->default_value->reduced_value.to_json_string(); } } r_symbol.detail += parameters + ")"; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index c16a7fa889..42ff8bb5b3 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -31,7 +31,6 @@ #include "gdscript_language_protocol.h" #include "core/config/project_settings.h" -#include "core/io/json.h" #include "editor/doc_tools.h" #include "editor/editor_log.h" #include "editor/editor_node.h" @@ -194,7 +193,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id)); Ref<LSPeer> peer = clients.get(latest_client_id); if (peer != nullptr) { - String msg = JSON::print(request); + String msg = Variant(request).to_json_string(); msg = format_output(msg); (*peer)->res_queue.push_back(msg.utf8()); } @@ -280,7 +279,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia ERR_FAIL_COND(peer == nullptr); Dictionary message = make_notification(p_method, p_params); - String msg = JSON::print(message); + String msg = Variant(message).to_json_string(); msg = format_output(msg); peer->res_queue.push_back(msg.utf8()); } diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp index 21b4bb75fb..5f220a9e57 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor_scene_importer_gltf.cpp @@ -30,7 +30,6 @@ #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" -#include "core/io/json.h" #include "core/math/disjoint_set.h" #include "core/math/math_defs.h" #include "core/os/os.h" diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h index af1a885f2b..566d5cfd34 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor_scene_importer_gltf.h @@ -32,7 +32,6 @@ #define EDITOR_SCENE_IMPORTER_GLTF_H #include "core/config/project_settings.h" -#include "core/io/json.h" #include "core/object/object.h" #include "core/templates/vector.h" #include "editor/import/resource_importer_scene.h" diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 988a75ac93..40f2116676 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -238,15 +238,13 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { String text; text.parse_utf8((const char *)array.ptr(), array.size()); - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); + _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT); return err; } - state->json = v; + state->json = json.get_data(); return OK; } @@ -299,16 +297,14 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { String text; text.parse_utf8((const char *)json_data.ptr(), json_data.size()); - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); + _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT); return err; } - state->json = v; + state->json = json.get_data(); //data? @@ -6584,7 +6580,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V(!f, FAILED); - String json = JSON::print(state->json); + String json = Variant(state->json).to_json_string(); const uint32_t magic = 0x46546C67; // GLTF const int32_t header_size = 12; @@ -6625,7 +6621,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { ERR_FAIL_COND_V(!f, FAILED); f->create(FileAccess::ACCESS_RESOURCES); - String json = JSON::print(state->json); + String json = Variant(state->json).to_json_string(); f->store_string(json); f->close(); } diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp index 306c0ff087..3d0759d83e 100644 --- a/modules/jsonrpc/jsonrpc.cpp +++ b/modules/jsonrpc/jsonrpc.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "jsonrpc.h" + #include "core/io/json.h" JSONRPC::JSONRPC() { @@ -156,19 +157,17 @@ String JSONRPC::process_string(const String &p_input) { } Variant ret; - Variant input; - String err_message; - int err_line; - if (OK != JSON::parse(p_input, input, err_message, err_line)) { - ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error"); + JSON json; + if (json.parse(p_input) == OK) { + ret = process_action(json.get_data(), true); } else { - ret = process_action(input, true); + ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error"); } if (ret.get_type() == Variant::NIL) { return ""; } - return JSON::print(ret); + return ret.to_json_string(); } void JSONRPC::set_scope(const String &p_scope, Object *p_obj) { diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index bd02ec0eac..25193a1352 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -240,7 +240,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE); ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'."); - f->store_string(JSON::print(classes_dict, /*indent: */ "\t")); + JSON json; + f->store_string(json.stringify(classes_dict, "\t")); f->close(); print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 576256b6ec..b54340a7bc 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -38,7 +38,6 @@ #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" #include "core/io/file_access.h" -#include "core/io/json.h" #include "core/os/mutex.h" #include "core/os/os.h" #include "core/os/thread.h" diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 7e49feee61..823f9b8281 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -29,7 +29,6 @@ /*************************************************************************/ #include "core/io/image_loader.h" -#include "core/io/json.h" #include "core/io/stream_peer_ssl.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" @@ -465,7 +464,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re } // Replaces HTML string - const String str_config = JSON::print(config); + const String str_config = Variant(config).to_json_string(); const String custom_head_include = p_preset->get("html/head_include"); Map<String, String> replaces; replaces["$GODOT_URL"] = p_name + ".js"; @@ -518,7 +517,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & replaces["@GODOT_NAME@"] = name; replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html"; Array files; - replaces["@GODOT_OPT_CACHE@"] = JSON::print(files); + replaces["@GODOT_OPT_CACHE@"] = Variant(files).to_json_string(); files.push_back(name + ".html"); files.push_back(name + ".js"); files.push_back(name + ".wasm"); @@ -537,7 +536,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & files.push_back(p_shared_objects[i].path.get_file()); } } - replaces["@GODOT_CACHE@"] = JSON::print(files); + replaces["@GODOT_CACHE@"] = Variant(files).to_json_string(); const String sw_path = dir.plus_file(name + ".service.worker.js"); Vector<uint8_t> sw; @@ -605,7 +604,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & } manifest["icons"] = icons_arr; - CharString cs = JSON::print(manifest).utf8(); + CharString cs = Variant(manifest).to_json_string().utf8(); err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json")); if (err != OK) { return err; diff --git a/tests/test_json.h b/tests/test_json.h index f1cb4799dc..60c4991a57 100644 --- a/tests/test_json.h +++ b/tests/test_json.h @@ -45,75 +45,65 @@ TEST_CASE("[JSON] Parsing single data types") { // Parsing a single data type as JSON is valid per the JSON specification. JSON json; - Variant result; - String err_str; - int err_line; - json.parse("null", result, err_str, err_line); + json.parse("null"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing `null` as JSON should parse successfully."); CHECK_MESSAGE( - result == Variant(), + json.get_data() == Variant(), "Parsing a double quoted string as JSON should return the expected value."); - json.parse("true", result, err_str, err_line); + json.parse("true"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing boolean `true` as JSON should parse successfully."); CHECK_MESSAGE( - result, + json.get_data(), "Parsing boolean `true` as JSON should return the expected value."); - json.parse("false", result, err_str, err_line); + json.parse("false"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing boolean `false` as JSON should parse successfully."); CHECK_MESSAGE( - !result, + !json.get_data(), "Parsing boolean `false` as JSON should return the expected value."); - // JSON only has a floating-point number type, no integer type. - // This is why we use `is_equal_approx()` for the comparison. - json.parse("123456", result, err_str, err_line); + json.parse("123456"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing an integer number as JSON should parse successfully."); CHECK_MESSAGE( - (int)result == 123'456, + (int)(json.get_data()) == 123456, "Parsing an integer number as JSON should return the expected value."); - json.parse("0.123456", result, err_str, err_line); + json.parse("0.123456"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing a floating-point number as JSON should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(result, 0.123456), + Math::is_equal_approx(json.get_data(), 0.123456), "Parsing a floating-point number as JSON should return the expected value."); - json.parse("\"hello\"", result, err_str, err_line); + json.parse("\"hello\""); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing a double quoted string as JSON should parse successfully."); CHECK_MESSAGE( - result == "hello", + json.get_data() == "hello", "Parsing a double quoted string as JSON should return the expected value."); } TEST_CASE("[JSON] Parsing arrays") { JSON json; - Variant result; - String err_str; - int err_line; // JSON parsing fails if it's split over several lines (even if leading indentation is removed). - json.parse( - R"(["Hello", "world.", "This is",["a","json","array.",[]], "Empty arrays ahoy:", [[["Gotcha!"]]]])", - result, err_str, err_line); + json.parse(R"(["Hello", "world.", "This is",["a","json","array.",[]], "Empty arrays ahoy:", [[["Gotcha!"]]]])"); - const Array array = result; + const Array array = json.get_data(); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing a JSON array should parse successfully."); CHECK_MESSAGE( array[0] == "Hello", @@ -136,15 +126,10 @@ TEST_CASE("[JSON] Parsing arrays") { TEST_CASE("[JSON] Parsing objects (dictionaries)") { JSON json; - Variant result; - String err_str; - int err_line; - json.parse( - R"({"name": "Godot Engine", "is_free": true, "bugs": null, "apples": {"red": 500, "green": 0, "blue": -20}, "empty_object": {}})", - result, err_str, err_line); + json.parse(R"({"name": "Godot Engine", "is_free": true, "bugs": null, "apples": {"red": 500, "green": 0, "blue": -20}, "empty_object": {}})"); - const Dictionary dictionary = result; + const Dictionary dictionary = json.get_data(); CHECK_MESSAGE( dictionary["name"] == "Godot Engine", "The parsed JSON should contain the expected values."); |