diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index dbc0eaf5f9..1b0333d3d0 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -1,6 +1,34 @@ JUCE breaking changes ===================== +Develop Branch +============= + +Change +------ +The writeAsJSON virtual method of the DynamicObject class requires an +additional parameter, maximumDecimalPlaces, to specify the maximum precision of +floating point numbers. + +Possible Issues +--------------- +Classes which inherit from DynamicObject and override this method will need to +update their method signature. + +Workaround +---------- +Your custom DynamicObject class can choose to ignore the additional parameter +if you don't wish to support this behaviour. + +Rationale +--------- +When serialising the results of calculations to JSON the rounding of floating +point numbers can result in numbers with 17 significant figures where only a +few are required. This change to DynamicObject is required to support +truncating those numbers. + + + Version 5.1.0 ============= diff --git a/modules/juce_core/containers/juce_DynamicObject.cpp b/modules/juce_core/containers/juce_DynamicObject.cpp index 56713d3fb4..697205bfa8 100644 --- a/modules/juce_core/containers/juce_DynamicObject.cpp +++ b/modules/juce_core/containers/juce_DynamicObject.cpp @@ -91,7 +91,7 @@ DynamicObject::Ptr DynamicObject::clone() return d; } -void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine) +void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine, int maximumDecimalPlaces) { out << '{'; if (! allOnOneLine) @@ -107,7 +107,7 @@ void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const out << '"'; JSONFormatter::writeString (out, properties.getName (i)); out << "\": "; - JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine); + JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine, maximumDecimalPlaces); if (i < numValues - 1) { diff --git a/modules/juce_core/containers/juce_DynamicObject.h b/modules/juce_core/containers/juce_DynamicObject.h index 1a8d7af4de..20c4e7608b 100644 --- a/modules/juce_core/containers/juce_DynamicObject.h +++ b/modules/juce_core/containers/juce_DynamicObject.h @@ -113,14 +113,14 @@ public: never need to call it directly, but it's virtual so that custom object types can stringify themselves appropriately. */ - virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine); + virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine, int maximumDecimalPlaces); private: //============================================================================== NamedValueSet properties; #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // These methods have been deprecated - use var::invoke instead + // This method has been deprecated - use var::invoke instead virtual void invokeMethod (const Identifier&, const var*, int) {} #endif diff --git a/modules/juce_core/javascript/juce_JSON.cpp b/modules/juce_core/javascript/juce_JSON.cpp index fcaace7629..749d1067c2 100644 --- a/modules/juce_core/javascript/juce_JSON.cpp +++ b/modules/juce_core/javascript/juce_JSON.cpp @@ -323,7 +323,8 @@ class JSONFormatter { public: static void write (OutputStream& out, const var& v, - const int indentLevel, const bool allOnOneLine) + const int indentLevel, const bool allOnOneLine, + int maximumDecimalPlaces) { if (v.isString()) { @@ -343,14 +344,18 @@ public: { out << (static_cast (v) ? "true" : "false"); } + else if (v.isDouble()) + { + out << String (static_cast (v), maximumDecimalPlaces); + } else if (v.isArray()) { - writeArray (out, *v.getArray(), indentLevel, allOnOneLine); + writeArray (out, *v.getArray(), indentLevel, allOnOneLine, maximumDecimalPlaces); } else if (v.isObject()) { if (DynamicObject* object = v.getDynamicObject()) - object->writeAsJSON (out, indentLevel, allOnOneLine); + object->writeAsJSON (out, indentLevel, allOnOneLine, maximumDecimalPlaces); else jassertfalse; // Only DynamicObjects can be converted to JSON! } @@ -420,7 +425,8 @@ public: } static void writeArray (OutputStream& out, const Array& array, - const int indentLevel, const bool allOnOneLine) + const int indentLevel, const bool allOnOneLine, + int maximumDecimalPlaces) { out << '['; @@ -434,7 +440,7 @@ public: if (! allOnOneLine) writeSpaces (out, indentLevel + indentSize); - write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine); + write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine, maximumDecimalPlaces); if (i < array.size() - 1) { @@ -493,16 +499,16 @@ Result JSON::parse (const String& text, var& result) return JSONParser::parseObjectOrArray (text.getCharPointer(), result); } -String JSON::toString (const var& data, const bool allOnOneLine) +String JSON::toString (const var& data, const bool allOnOneLine, int maximumDecimalPlaces) { MemoryOutputStream mo (1024); - JSONFormatter::write (mo, data, 0, allOnOneLine); + JSONFormatter::write (mo, data, 0, allOnOneLine, maximumDecimalPlaces); return mo.toUTF8(); } -void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine) +void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine, int maximumDecimalPlaces) { - JSONFormatter::write (output, data, 0, allOnOneLine); + JSONFormatter::write (output, data, 0, allOnOneLine, maximumDecimalPlaces); } String JSON::escapeString (StringRef s) diff --git a/modules/juce_core/javascript/juce_JSON.h b/modules/juce_core/javascript/juce_JSON.h index 29affb9956..1cbe1a1d62 100644 --- a/modules/juce_core/javascript/juce_JSON.h +++ b/modules/juce_core/javascript/juce_JSON.h @@ -90,10 +90,12 @@ public: /** Returns a string which contains a JSON-formatted representation of the var object. If allOnOneLine is true, the result will be compacted into a single line of text with no carriage-returns. If false, it will be laid-out in a more human-readable format. + The maximumDecimalPlaces parameter determines the precision of floating point numbers. @see writeToStream */ static String toString (const var& objectToFormat, - bool allOnOneLine = false); + bool allOnOneLine = false, + int maximumDecimalPlaces = 20); /** Parses a string that was created with the toString() method. This is slightly different to the parse() methods because they will reject primitive @@ -105,11 +107,13 @@ public: /** Writes a JSON-formatted representation of the var object to the given stream. If allOnOneLine is true, the result will be compacted into a single line of text with no carriage-returns. If false, it will be laid-out in a more human-readable format. + The maximumDecimalPlaces parameter determines the precision of floating point numbers. @see toString */ static void writeToStream (OutputStream& output, const var& objectToFormat, - bool allOnOneLine = false); + bool allOnOneLine = false, + int maximumDecimalPlaces = 20); /** Returns a version of a string with any extended characters escaped. */ static String escapeString (StringRef); diff --git a/modules/juce_core/javascript/juce_Javascript.cpp b/modules/juce_core/javascript/juce_Javascript.cpp index c04c051bf5..72b059de27 100644 --- a/modules/juce_core/javascript/juce_Javascript.cpp +++ b/modules/juce_core/javascript/juce_Javascript.cpp @@ -827,7 +827,7 @@ struct JavascriptEngine::RootObject : public DynamicObject DynamicObject::Ptr clone() override { return new FunctionObject (*this); } - void writeAsJSON (OutputStream& out, int /*indentLevel*/, bool /*allOnOneLine*/) override + void writeAsJSON (OutputStream& out, int /*indentLevel*/, bool /*allOnOneLine*/, int /*maximumDecimalPlaces*/) override { out << "function " << functionCode; }