Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
6ea9bc7a
Commit
6ea9bc7a
authored
Jul 10, 2015
by
Jon Skeet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes to JsonFormatter
- Handle oneof properly - Omit unknown enum values
parent
68fc689e
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
112 additions
and
11 deletions
+112
-11
JsonFormatterTest.cs
csharp/src/ProtocolBuffers.Test/JsonFormatterTest.cs
+46
-2
JsonFormatter.cs
csharp/src/ProtocolBuffers/JsonFormatter.cs
+66
-9
No files found.
csharp/src/ProtocolBuffers.Test/JsonFormatterTest.cs
View file @
6ea9bc7a
...
...
@@ -160,10 +160,34 @@ namespace Google.Protobuf
}
[
Test
]
public
void
UnknownEnumValue
()
public
void
UnknownEnumValue
Omitted_SingleField
()
{
var
message
=
new
TestAllTypes
{
SingleForeignEnum
=
(
ForeignEnum
)
100
};
Assert
.
AreEqual
(
"{ \"singleForeignEnum\": 100 }"
,
JsonFormatter
.
Default
.
Format
(
message
));
Assert
.
AreEqual
(
"{ }"
,
JsonFormatter
.
Default
.
Format
(
message
));
}
[
Test
]
public
void
UnknownEnumValueOmitted_RepeatedField
()
{
var
message
=
new
TestAllTypes
{
RepeatedForeignEnum
=
{
ForeignEnum
.
FOREIGN_BAZ
,
(
ForeignEnum
)
100
,
ForeignEnum
.
FOREIGN_FOO
}
};
Assert
.
AreEqual
(
"{ \"repeatedForeignEnum\": [ \"FOREIGN_BAZ\", \"FOREIGN_FOO\" ] }"
,
JsonFormatter
.
Default
.
Format
(
message
));
}
[
Test
]
public
void
UnknownEnumValueOmitted_MapField
()
{
// This matches the C++ behaviour.
var
message
=
new
TestMap
{
MapInt32Enum
=
{
{
1
,
MapEnum
.
MAP_ENUM_FOO
},
{
2
,
(
MapEnum
)
100
},
{
3
,
MapEnum
.
MAP_ENUM_BAR
}
}
};
Assert
.
AreEqual
(
"{ \"mapInt32Enum\": { \"1\": \"MAP_ENUM_FOO\", \"3\": \"MAP_ENUM_BAR\" } }"
,
JsonFormatter
.
Default
.
Format
(
message
));
}
[
Test
]
public
void
UnknownEnumValueOmitted_RepeatedField_AllEntriesUnknown
()
{
// *Maybe* we should hold off on writing the "[" until we find that we've got at least one value to write...
// but this is what happens at the moment, and it doesn't seem too awful.
var
message
=
new
TestAllTypes
{
RepeatedForeignEnum
=
{
(
ForeignEnum
)
200
,
(
ForeignEnum
)
100
}
};
Assert
.
AreEqual
(
"{ \"repeatedForeignEnum\": [ ] }"
,
JsonFormatter
.
Default
.
Format
(
message
));
}
[
Test
]
...
...
@@ -213,5 +237,25 @@ namespace Google.Protobuf
{
Assert
.
AreEqual
(
expected
,
JsonFormatter
.
ToCamelCase
(
original
));
}
[
Test
]
[
TestCase
(
null
,
"{ }"
)]
[
TestCase
(
"x"
,
"{ \"fooString\": \"x\" }"
)]
[
TestCase
(
""
,
"{ \"fooString\": \"\" }"
)]
[
TestCase
(
null
,
"{ }"
)]
public
void
Oneof
(
string
fooStringValue
,
string
expectedJson
)
{
var
message
=
new
TestOneof
();
if
(
fooStringValue
!=
null
)
{
message
.
FooString
=
fooStringValue
;
}
// We should get the same result both with and without "format default values".
var
formatter
=
new
JsonFormatter
(
new
JsonFormatter
.
Settings
(
false
));
Assert
.
AreEqual
(
expectedJson
,
formatter
.
Format
(
message
));
formatter
=
new
JsonFormatter
(
new
JsonFormatter
.
Settings
(
true
));
Assert
.
AreEqual
(
expectedJson
,
formatter
.
Format
(
message
));
}
}
}
csharp/src/ProtocolBuffers/JsonFormatter.cs
View file @
6ea9bc7a
...
...
@@ -136,13 +136,28 @@ namespace Google.Protobuf
builder
.
Append
(
"{ "
);
var
fields
=
message
.
Fields
;
bool
first
=
true
;
// First non-oneof fields
foreach
(
var
accessor
in
fields
.
Accessors
)
{
var
descriptor
=
accessor
.
Descriptor
;
// Oneofs are written later
if
(
descriptor
.
ContainingOneof
!=
null
)
{
continue
;
}
// Omit default values unless we're asked to format them
object
value
=
accessor
.
GetValue
(
message
);
if
(!
settings
.
FormatDefaultValues
&&
IsDefaultValue
(
accessor
,
value
))
{
continue
;
}
// Omit awkward (single) values such as unknown enum values
if
(!
descriptor
.
IsRepeated
&&
!
descriptor
.
IsMap
&&
!
CanWriteSingleValue
(
accessor
.
Descriptor
,
value
))
{
continue
;
}
// Okay, all tests complete: let's write the field value...
if
(!
first
)
{
builder
.
Append
(
", "
);
...
...
@@ -152,6 +167,32 @@ namespace Google.Protobuf
WriteValue
(
builder
,
accessor
,
value
);
first
=
false
;
}
// Now oneofs
foreach
(
var
accessor
in
fields
.
Oneofs
)
{
var
fieldDescriptor
=
accessor
.
GetCaseFieldDescriptor
(
message
);
if
(
fieldDescriptor
==
null
)
{
continue
;
}
var
fieldAccessor
=
fields
[
fieldDescriptor
];
object
value
=
fieldAccessor
.
GetValue
(
message
);
// Omit awkward (single) values such as unknown enum values
if
(!
fieldDescriptor
.
IsRepeated
&&
!
fieldDescriptor
.
IsMap
&&
!
CanWriteSingleValue
(
fieldDescriptor
,
value
))
{
continue
;
}
if
(!
first
)
{
builder
.
Append
(
", "
);
}
WriteString
(
builder
,
ToCamelCase
(
fieldDescriptor
.
Name
));
builder
.
Append
(
": "
);
WriteValue
(
builder
,
fieldAccessor
,
value
);
first
=
false
;
}
builder
.
Append
(
first
?
"}"
:
" }"
);
}
...
...
@@ -303,15 +344,8 @@ namespace Google.Protobuf
}
case
FieldType
.
Enum
:
EnumValueDescriptor
enumValue
=
descriptor
.
EnumType
.
FindValueByNumber
((
int
)
value
);
if
(
enumValue
!=
null
)
{
WriteString
(
builder
,
enumValue
.
Name
);
}
else
{
// ??? Need more documentation
builder
.
Append
(((
int
)
value
).
ToString
(
"d"
,
CultureInfo
.
InvariantCulture
));
}
// We will already have validated that this is a known value.
WriteString
(
builder
,
enumValue
.
Name
);
break
;
case
FieldType
.
Fixed64
:
case
FieldType
.
UInt64
:
...
...
@@ -354,6 +388,10 @@ namespace Google.Protobuf
bool
first
=
true
;
foreach
(
var
value
in
list
)
{
if
(!
CanWriteSingleValue
(
accessor
.
Descriptor
,
value
))
{
continue
;
}
if
(!
first
)
{
builder
.
Append
(
", "
);
...
...
@@ -373,6 +411,10 @@ namespace Google.Protobuf
// This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
foreach
(
DictionaryEntry
pair
in
dictionary
)
{
if
(!
CanWriteSingleValue
(
valueType
,
pair
.
Value
))
{
continue
;
}
if
(!
first
)
{
builder
.
Append
(
", "
);
...
...
@@ -409,6 +451,21 @@ namespace Google.Protobuf
builder
.
Append
(
first
?
"}"
:
" }"
);
}
/// <summary>
/// Returns whether or not a singular value can be represented in JSON.
/// Currently only relevant for enums, where unknown values can't be represented.
/// For repeated/map fields, this always returns true.
/// </summary>
private
bool
CanWriteSingleValue
(
FieldDescriptor
descriptor
,
object
value
)
{
if
(
descriptor
.
FieldType
==
FieldType
.
Enum
)
{
EnumValueDescriptor
enumValue
=
descriptor
.
EnumType
.
FindValueByNumber
((
int
)
value
);
return
enumValue
!=
null
;
}
return
true
;
}
/// <summary>
/// Writes a string (including leading and trailing double quotes) to a builder, escaping as required.
/// </summary>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment