-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
utility: new utility method to convert proto value to string (#36334)
Commit Message: utility: new utility method to convert proto value to string Additional Description: New utility method to convert the proto value to json. This could work even the `ENVOY_ENABLE_YAML` is not set and is exception free. Risk Level: low. Testing: unit test. Docs Changes: n/a. Release Notes: n/a. Platform Specific Features: n/a. --------- Signed-off-by: wangbaiping <[email protected]>
- Loading branch information
Showing
6 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#include "source/common/json/json_utility.h" | ||
|
||
namespace Envoy { | ||
namespace Json { | ||
|
||
namespace { | ||
|
||
void structValueToJson(const ProtobufWkt::Struct& struct_value, StringStreamer::Map& level); | ||
void listValueToJson(const ProtobufWkt::ListValue& list_value, StringStreamer::Array& level); | ||
|
||
void valueToJson(const ProtobufWkt::Value& value, StringStreamer::Level& level) { | ||
switch (value.kind_case()) { | ||
case ProtobufWkt::Value::KIND_NOT_SET: | ||
case ProtobufWkt::Value::kNullValue: | ||
level.addNull(); | ||
break; | ||
case ProtobufWkt::Value::kNumberValue: | ||
level.addNumber(value.number_value()); | ||
break; | ||
case ProtobufWkt::Value::kStringValue: | ||
level.addString(value.string_value()); | ||
break; | ||
case ProtobufWkt::Value::kBoolValue: | ||
level.addBool(value.bool_value()); | ||
break; | ||
case ProtobufWkt::Value::kStructValue: | ||
structValueToJson(value.struct_value(), *level.addMap()); | ||
break; | ||
case ProtobufWkt::Value::kListValue: | ||
listValueToJson(value.list_value(), *level.addArray()); | ||
break; | ||
} | ||
} | ||
|
||
void structValueToJson(const ProtobufWkt::Struct& struct_value, StringStreamer::Map& map) { | ||
using PairRefWrapper = | ||
std::reference_wrapper<const Protobuf::Map<std::string, ProtobufWkt::Value>::value_type>; | ||
absl::InlinedVector<PairRefWrapper, 8> sorted_fields; | ||
sorted_fields.reserve(struct_value.fields_size()); | ||
|
||
for (const auto& field : struct_value.fields()) { | ||
sorted_fields.emplace_back(field); | ||
} | ||
// Sort the keys to make the output deterministic. | ||
std::sort(sorted_fields.begin(), sorted_fields.end(), | ||
[](PairRefWrapper a, PairRefWrapper b) { return a.get().first < b.get().first; }); | ||
|
||
for (const PairRefWrapper field : sorted_fields) { | ||
map.addKey(field.get().first); | ||
valueToJson(field.get().second, map); | ||
} | ||
} | ||
|
||
void listValueToJson(const ProtobufWkt::ListValue& list_value, StringStreamer::Array& arr) { | ||
for (const ProtobufWkt::Value& value : list_value.values()) { | ||
valueToJson(value, arr); | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
void Utility::appendValueToString(const ProtobufWkt::Value& value, std::string& dest) { | ||
StringStreamer streamer(dest); | ||
switch (value.kind_case()) { | ||
case ProtobufWkt::Value::KIND_NOT_SET: | ||
case ProtobufWkt::Value::kNullValue: | ||
streamer.addNull(); | ||
break; | ||
case ProtobufWkt::Value::kNumberValue: | ||
streamer.addNumber(value.number_value()); | ||
break; | ||
case ProtobufWkt::Value::kStringValue: | ||
streamer.addString(value.string_value()); | ||
break; | ||
case ProtobufWkt::Value::kBoolValue: | ||
streamer.addBool(value.bool_value()); | ||
break; | ||
case ProtobufWkt::Value::kStructValue: | ||
structValueToJson(value.struct_value(), *streamer.makeRootMap()); | ||
break; | ||
case ProtobufWkt::Value::kListValue: | ||
listValueToJson(value.list_value(), *streamer.makeRootArray()); | ||
break; | ||
} | ||
} | ||
|
||
} // namespace Json | ||
} // namespace Envoy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include "source/common/json/json_streamer.h" | ||
#include "source/common/protobuf/protobuf.h" | ||
|
||
namespace Envoy { | ||
namespace Json { | ||
|
||
class Utility { | ||
public: | ||
/** | ||
* Convert a ProtobufWkt::Value to a JSON string. | ||
* @param value message of type type.googleapis.com/google.protobuf.Value | ||
* @param dest JSON string. | ||
*/ | ||
static void appendValueToString(const ProtobufWkt::Value& value, std::string& dest); | ||
}; | ||
|
||
} // namespace Json | ||
} // namespace Envoy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#include "source/common/json/json_utility.h" | ||
#include "source/common/protobuf/message_validator_impl.h" | ||
#include "source/common/protobuf/utility.h" | ||
|
||
#include "gtest/gtest.h" | ||
|
||
namespace Envoy { | ||
namespace Json { | ||
namespace { | ||
|
||
std::string toJson(const ProtobufWkt::Value& v) { | ||
std::string json_string; | ||
Utility::appendValueToString(v, json_string); | ||
return json_string; | ||
} | ||
|
||
TEST(JsonUtilityTest, AppendValueToString) { | ||
ProtobufWkt::Value v; | ||
|
||
// null | ||
EXPECT_EQ(toJson(v), "null"); | ||
|
||
v.set_null_value(ProtobufWkt::NULL_VALUE); | ||
EXPECT_EQ(toJson(v), "null"); | ||
|
||
// bool | ||
v.set_bool_value(true); | ||
EXPECT_EQ(toJson(v), "true"); | ||
|
||
v.set_bool_value(false); | ||
EXPECT_EQ(toJson(v), "false"); | ||
|
||
// number | ||
v.set_number_value(1); | ||
EXPECT_EQ(toJson(v), "1"); | ||
|
||
v.set_number_value(1.1); | ||
EXPECT_EQ(toJson(v), "1.1"); | ||
|
||
// string | ||
v.set_string_value("foo"); | ||
EXPECT_EQ(toJson(v), "\"foo\""); | ||
|
||
// struct | ||
auto* struct_value = v.mutable_struct_value(); | ||
EXPECT_EQ(toJson(v), R"EOF({})EOF"); | ||
|
||
struct_value->mutable_fields()->insert({"foo", ValueUtil::stringValue("bar")}); | ||
EXPECT_EQ(toJson(v), R"EOF({"foo":"bar"})EOF"); | ||
|
||
// list | ||
auto* list_value = v.mutable_list_value(); | ||
|
||
EXPECT_EQ(toJson(v), R"EOF([])EOF"); | ||
|
||
list_value->add_values()->set_string_value("foo"); | ||
list_value->add_values()->set_string_value("bar"); | ||
|
||
EXPECT_EQ(toJson(v), R"EOF(["foo","bar"])EOF"); | ||
|
||
// Complex structure | ||
const std::string yaml = R"EOF( | ||
a: | ||
a: | ||
- a: 1 | ||
b: 2 | ||
b: | ||
- a: 3 | ||
b: 4 | ||
- a: 5 | ||
c: true | ||
d: [5, 3.14] | ||
e: foo | ||
f: 1.1 | ||
b: [1, 2, 3] | ||
c: bar | ||
)EOF"; | ||
|
||
MessageUtil::loadFromYaml(yaml, v, ProtobufMessage::getNullValidationVisitor()); | ||
|
||
EXPECT_EQ( | ||
toJson(v), | ||
R"EOF({"a":{"a":[{"a":1,"b":2}],"b":[{"a":3,"b":4},{"a":5}],"c":true,"d":[5,"3.14"],"e":"foo","f":"1.1"},"b":[1,2,3],"c":"bar"})EOF"); | ||
} | ||
|
||
} // namespace | ||
} // namespace Json | ||
} // namespace Envoy |