Skip to content

Commit

Permalink
add mergeFromJsonMap and writeToJsonMap to GeneratedMessage
Browse files Browse the repository at this point in the history
These methods were requested by users who want to do JSON
encoding and decoding themselves.

Also added basic smoke tests for the JSON methods.
  • Loading branch information
Brian Slesinsky committed Apr 21, 2015
1 parent a9aab49 commit bb23f1a
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 8 deletions.
33 changes: 25 additions & 8 deletions lib/src/protobuf/generated_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,12 @@ abstract class GeneratedMessage {

// JSON support.

Map<String, dynamic> _toMap() {
/**
* Returns the JSON encoding of this message as a Dart map.
*
* The encoding is described in [GeneratedMessage.writeToJson].
*/
Map<String, dynamic> writeToJsonMap() {
convertToMap(fieldValue, fieldType) {
int scalarType = fieldType & ~(_REPEATED_BIT | _PACKED_BIT);

Expand Down Expand Up @@ -666,7 +671,7 @@ abstract class GeneratedMessage {
return fieldValue.toString();
case _GROUP_BIT:
case _MESSAGE_BIT:
return fieldValue._toMap();
return fieldValue.writeToJsonMap();
default:
throw 'Unknown type $fieldType';
}
Expand All @@ -684,18 +689,19 @@ abstract class GeneratedMessage {
}

/**
* Return a JSON string that encodes this message. Each message (top level
* or nested) is represented as an object delimited by curly braces. Within
* a message, elements are indexed by tag number (surrounded by quotes).
* Repeated elements are represented as arrays.
* Returns a JSON string that encodes this message.
*
* Each message (top level or nested) is represented as an object delimited
* by curly braces. Within a message, elements are indexed by tag number
* (surrounded by quotes). Repeated elements are represented as arrays.
*
* Boolean values, strings, and floating-point values are represented as
* literals. Values with a 32-bit integer datatype are represented as integer
* literals; values with a 64-bit integer datatype (regardless of their
* actual runtime value) are represented as strings. Enumerated values are
* represented as their integer value.
*/
String writeToJson() => JSON.encode(_toMap());
String writeToJson() => JSON.encode(writeToJsonMap());

// Merge fields from a previously decoded JSON object.
void _mergeFromJson(
Expand Down Expand Up @@ -840,7 +846,7 @@ abstract class GeneratedMessage {


/**
* Merge field values from a JSON object, encoded as described by
* Merges field values from a JSON object, encoded as described by
* [GeneratedMessage.writeToJson].
*/
void mergeFromJson(
Expand All @@ -849,6 +855,17 @@ abstract class GeneratedMessage {
_mergeFromJson(JSON.decode(data), extensionRegistry);
}

/**
* Merges field values from a JSON object represented as a Dart map.
*
* The encoding is described in [GeneratedMessage.writeToJson].
*/
void mergeFromJsonMap(
Map<String, dynamic> json,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
_mergeFromJson(json, extensionRegistry);
}

/**
* Add an extension field value to a repeated field. The backing
* [List] will be created if necessary.
Expand Down
2 changes: 2 additions & 0 deletions test/all_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ library protobuf_lib_all_tests;

import 'codec_test.dart' as ct;
import 'coded_buffer_reader_test.dart' as cbrt;
import 'json_test.dart' as jt;
import 'pb_list_test.dart' as plt;

void main() {
ct.main();
cbrt.main();
jt.main();
plt.main();
}
86 changes: 86 additions & 0 deletions test/json_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Basic smoke tests for the GeneratedMessage JSON API.
//
// There are more JSON tests in the dart-protoc-plugin package.
library json_test;

import 'dart:convert';
import 'package:protobuf/protobuf.dart';
import 'package:unittest/unittest.dart';

main() {
T example = new T()
..a = 123
..b = "hello";

test('testWriteToJson', () {
String json = example.writeToJson();
checkJsonMap(JSON.decode(json));
});

test('writeToJsonMap', () {
Map m = example.writeToJsonMap();
checkJsonMap(m);
});

test('testMergeFromJson', () {
var t = new T();
t.mergeFromJson('''{"1": 123, "2": "hello"}''');
checkMessage(t);
});

test('testMergeFromJsonMap', () {
var t = new T();
t.mergeFromJsonMap({"1": 123, "2": "hello"});
checkMessage(t);
});
}

checkJsonMap(Map m) {
expect(m.length, 2);
expect(m["1"], 123);
expect(m["2"], "hello");
}

checkMessage(T t) {
expect(t.a, 123);
expect(t.b, "hello");
}

/// This is generated code based on:
/// dart-protoc-plugin/test/protos/toplevel.proto
/// (Copied to avoid a circular dependency.)
///
/// message T {
/// optional int32 a = 1;
/// optional string b = 2;
/// }
class T extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('T')
..a(1, 'a', GeneratedMessage.O3)
..a(2, 'b', GeneratedMessage.OS)
..hasRequiredFields = false;

T() : super();
T.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
T.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
T clone() => new T()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static T create() => new T();
static PbList<T> createRepeated() => new PbList<T>();

int get a => getField(1);
void set a(int v) {
setField(1, v);
}
bool hasA() => hasField(1);
void clearA() => clearField(1);

String get b => getField(2);
void set b(String v) {
setField(2, v);
}
bool hasB() => hasField(2);
void clearB() => clearField(2);
}

0 comments on commit bb23f1a

Please sign in to comment.