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
aeff638a
Commit
aeff638a
authored
Jul 01, 2016
by
Feng Xiao
Committed by
GitHub
Jul 01, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1710 from chezRong/master
Add minified Json printing functionality
parents
7e8c8930
454dbf16
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
159 additions
and
26 deletions
+159
-26
JsonFormat.java
...il/src/main/java/com/google/protobuf/util/JsonFormat.java
+101
-26
JsonFormatTest.java
...rc/test/java/com/google/protobuf/util/JsonFormatTest.java
+58
-0
No files found.
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
View file @
aeff638a
...
...
@@ -101,7 +101,7 @@ public class JsonFormat {
* Creates a {@link Printer} with default configurations.
*/
public
static
Printer
printer
()
{
return
new
Printer
(
TypeRegistry
.
getEmptyTypeRegistry
(),
false
,
false
);
return
new
Printer
(
TypeRegistry
.
getEmptyTypeRegistry
(),
false
,
false
,
false
);
}
/**
...
...
@@ -111,14 +111,16 @@ public class JsonFormat {
private
final
TypeRegistry
registry
;
private
final
boolean
includingDefaultValueFields
;
private
final
boolean
preservingProtoFieldNames
;
private
final
boolean
omittingInsignificantWhitespace
;
private
Printer
(
TypeRegistry
registry
,
boolean
includingDefaultValueFields
,
boolean
preservingProtoFieldNames
)
{
boolean
preservingProtoFieldNames
,
boolean
omittingInsignificantWhitespace
)
{
this
.
registry
=
registry
;
this
.
includingDefaultValueFields
=
includingDefaultValueFields
;
this
.
preservingProtoFieldNames
=
preservingProtoFieldNames
;
this
.
omittingInsignificantWhitespace
=
omittingInsignificantWhitespace
;
}
/**
...
...
@@ -131,7 +133,7 @@ public class JsonFormat {
if
(
this
.
registry
!=
TypeRegistry
.
getEmptyTypeRegistry
())
{
throw
new
IllegalArgumentException
(
"Only one registry is allowed."
);
}
return
new
Printer
(
registry
,
includingDefaultValueFields
,
preservingProtoFieldNames
);
return
new
Printer
(
registry
,
includingDefaultValueFields
,
preservingProtoFieldNames
,
omittingInsignificantWhitespace
);
}
/**
...
...
@@ -141,7 +143,7 @@ public class JsonFormat {
* {@link Printer}.
*/
public
Printer
includingDefaultValueFields
()
{
return
new
Printer
(
registry
,
true
,
preservingProtoFieldNames
);
return
new
Printer
(
registry
,
true
,
preservingProtoFieldNames
,
omittingInsignificantWhitespace
);
}
/**
...
...
@@ -151,7 +153,27 @@ public class JsonFormat {
* current {@link Printer}.
*/
public
Printer
preservingProtoFieldNames
()
{
return
new
Printer
(
registry
,
includingDefaultValueFields
,
true
);
return
new
Printer
(
registry
,
includingDefaultValueFields
,
true
,
omittingInsignificantWhitespace
);
}
/**
* Create a new {@link Printer} that will omit all insignificant whitespace
* in the JSON output. This new Printer clones all other configurations from the
* current Printer. Insignificant whitespace is defined by the JSON spec as whitespace
* that appear between JSON structural elements:
* <pre>
* ws = *(
* %x20 / ; Space
* %x09 / ; Horizontal tab
* %x0A / ; Line feed or New line
* %x0D ) ; Carriage return
* </pre>
* See <a href="https://tools.ietf.org/html/rfc7159">https://tools.ietf.org/html/rfc7159</a>
* current {@link Printer}.
*/
public
Printer
omittingInsignificantWhitespace
(){
return
new
Printer
(
registry
,
includingDefaultValueFields
,
preservingProtoFieldNames
,
true
);
}
/**
...
...
@@ -164,7 +186,7 @@ public class JsonFormat {
public
void
appendTo
(
MessageOrBuilder
message
,
Appendable
output
)
throws
IOException
{
// TODO(xiaofeng): Investigate the allocation overhead and optimize for
// mobile.
new
PrinterImpl
(
registry
,
includingDefaultValueFields
,
preservingProtoFieldNames
,
output
)
new
PrinterImpl
(
registry
,
includingDefaultValueFields
,
preservingProtoFieldNames
,
output
,
omittingInsignificantWhitespace
)
.
print
(
message
);
}
...
...
@@ -351,15 +373,55 @@ public class JsonFormat {
}
}
/**
* An interface for json formatting that can be used in
* combination with the omittingInsignificantWhitespace() method
*/
interface
TextGenerator
{
void
indent
();
void
outdent
();
void
print
(
final
CharSequence
text
)
throws
IOException
;
}
/**
* Format the json without indentation
*/
private
static
final
class
CompactTextGenerator
implements
TextGenerator
{
private
final
Appendable
output
;
private
CompactTextGenerator
(
final
Appendable
output
)
{
this
.
output
=
output
;
}
/**
* ignored by compact printer
*/
public
void
indent
()
{}
/**
* ignored by compact printer
*/
public
void
outdent
()
{}
/**
* Print text to the output stream.
*/
public
void
print
(
final
CharSequence
text
)
throws
IOException
{
output
.
append
(
text
);
}
}
/**
* A TextGenerator adds indentation when writing formatted text.
*/
private
static
final
class
TextGenerator
{
private
static
final
class
PrettyTextGenerator
implements
TextGenerator
{
private
final
Appendable
output
;
private
final
StringBuilder
indent
=
new
StringBuilder
();
private
boolean
atStartOfLine
=
true
;
private
TextGenerator
(
final
Appendable
output
)
{
private
Pretty
TextGenerator
(
final
Appendable
output
)
{
this
.
output
=
output
;
}
...
...
@@ -423,6 +485,8 @@ public class JsonFormat {
private
final
TextGenerator
generator
;
// We use Gson to help handle string escapes.
private
final
Gson
gson
;
private
final
CharSequence
blankOrSpace
;
private
final
CharSequence
blankOrNewLine
;
private
static
class
GsonHolder
{
private
static
final
Gson
DEFAULT_GSON
=
new
GsonBuilder
().
disableHtmlEscaping
().
create
();
...
...
@@ -432,12 +496,21 @@ public class JsonFormat {
TypeRegistry
registry
,
boolean
includingDefaultValueFields
,
boolean
preservingProtoFieldNames
,
Appendable
jsonOutput
)
{
Appendable
jsonOutput
,
boolean
omittingInsignificantWhitespace
)
{
this
.
registry
=
registry
;
this
.
includingDefaultValueFields
=
includingDefaultValueFields
;
this
.
preservingProtoFieldNames
=
preservingProtoFieldNames
;
this
.
generator
=
new
TextGenerator
(
jsonOutput
);
this
.
gson
=
GsonHolder
.
DEFAULT_GSON
;
// json format related properties, determined by printerType
if
(
omittingInsignificantWhitespace
)
{
this
.
generator
=
new
CompactTextGenerator
(
jsonOutput
);
this
.
blankOrSpace
=
""
;
this
.
blankOrNewLine
=
""
;
}
else
{
this
.
generator
=
new
PrettyTextGenerator
(
jsonOutput
);
this
.
blankOrSpace
=
" "
;
this
.
blankOrNewLine
=
"\n"
;
}
}
void
print
(
MessageOrBuilder
message
)
throws
IOException
{
...
...
@@ -568,12 +641,12 @@ public class JsonFormat {
if
(
printer
!=
null
)
{
// If the type is one of the well-known types, we use a special
// formatting.
generator
.
print
(
"{
\n"
);
generator
.
print
(
"{
"
+
blankOrNewLine
);
generator
.
indent
();
generator
.
print
(
"\"@type\":
"
+
gson
.
toJson
(
typeUrl
)
+
",\n"
);
generator
.
print
(
"\"value\":
"
);
generator
.
print
(
"\"@type\":
"
+
blankOrSpace
+
gson
.
toJson
(
typeUrl
)
+
","
+
blankOrNewLine
);
generator
.
print
(
"\"value\":
"
+
blankOrSpace
);
printer
.
print
(
this
,
contentMessage
);
generator
.
print
(
"\n"
);
generator
.
print
(
blankOrNewLine
);
generator
.
outdent
();
generator
.
print
(
"}"
);
}
else
{
...
...
@@ -661,13 +734,15 @@ public class JsonFormat {
}
/** Prints a regular message with an optional type URL. */
private
void
print
(
MessageOrBuilder
message
,
String
typeUrl
)
throws
IOException
{
generator
.
print
(
"{\n"
);
private
void
print
(
MessageOrBuilder
message
,
String
typeUrl
)
throws
IOException
{
generator
.
print
(
"{"
+
blankOrNewLine
);
generator
.
indent
();
boolean
printedField
=
false
;
if
(
typeUrl
!=
null
)
{
generator
.
print
(
"\"@type\":
"
+
gson
.
toJson
(
typeUrl
));
generator
.
print
(
"\"@type\":
"
+
blankOrSpace
+
gson
.
toJson
(
typeUrl
));
printedField
=
true
;
}
Map
<
FieldDescriptor
,
Object
>
fieldsToPrint
=
null
;
...
...
@@ -689,7 +764,7 @@ public class JsonFormat {
for
(
Map
.
Entry
<
FieldDescriptor
,
Object
>
field
:
fieldsToPrint
.
entrySet
())
{
if
(
printedField
)
{
// Add line-endings for the previous field.
generator
.
print
(
",
\n"
);
generator
.
print
(
",
"
+
blankOrNewLine
);
}
else
{
printedField
=
true
;
}
...
...
@@ -698,7 +773,7 @@ public class JsonFormat {
// Add line-endings for the last field.
if
(
printedField
)
{
generator
.
print
(
"\n"
);
generator
.
print
(
blankOrNewLine
);
}
generator
.
outdent
();
generator
.
print
(
"}"
);
...
...
@@ -706,9 +781,9 @@ public class JsonFormat {
private
void
printField
(
FieldDescriptor
field
,
Object
value
)
throws
IOException
{
if
(
preservingProtoFieldNames
)
{
generator
.
print
(
"\""
+
field
.
getName
()
+
"\":
"
);
generator
.
print
(
"\""
+
field
.
getName
()
+
"\":
"
+
blankOrSpace
);
}
else
{
generator
.
print
(
"\""
+
field
.
getJsonName
()
+
"\":
"
);
generator
.
print
(
"\""
+
field
.
getJsonName
()
+
"\":
"
+
blankOrSpace
);
}
if
(
field
.
isMapField
())
{
printMapFieldValue
(
field
,
value
);
...
...
@@ -725,7 +800,7 @@ public class JsonFormat {
boolean
printedElement
=
false
;
for
(
Object
element
:
(
List
)
value
)
{
if
(
printedElement
)
{
generator
.
print
(
",
"
);
generator
.
print
(
",
"
+
blankOrSpace
);
}
else
{
printedElement
=
true
;
}
...
...
@@ -742,7 +817,7 @@ public class JsonFormat {
if
(
keyField
==
null
||
valueField
==
null
)
{
throw
new
InvalidProtocolBufferException
(
"Invalid map field."
);
}
generator
.
print
(
"{
\n"
);
generator
.
print
(
"{
"
+
blankOrNewLine
);
generator
.
indent
();
boolean
printedElement
=
false
;
for
(
Object
element
:
(
List
)
value
)
{
...
...
@@ -750,17 +825,17 @@ public class JsonFormat {
Object
entryKey
=
entry
.
getField
(
keyField
);
Object
entryValue
=
entry
.
getField
(
valueField
);
if
(
printedElement
)
{
generator
.
print
(
",
\n"
);
generator
.
print
(
",
"
+
blankOrNewLine
);
}
else
{
printedElement
=
true
;
}
// Key fields are always double-quoted.
printSingleFieldValue
(
keyField
,
entryKey
,
true
);
generator
.
print
(
":
"
);
generator
.
print
(
":
"
+
blankOrSpace
);
printSingleFieldValue
(
valueField
,
entryValue
);
}
if
(
printedElement
)
{
generator
.
print
(
"\n"
);
generator
.
print
(
blankOrNewLine
);
}
generator
.
outdent
();
generator
.
print
(
"}"
);
...
...
java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
View file @
aeff638a
...
...
@@ -140,6 +140,9 @@ public class JsonFormatTest extends TestCase {
private
String
toJsonString
(
Message
message
)
throws
IOException
{
return
JsonFormat
.
printer
().
print
(
message
);
}
private
String
toCompactJsonString
(
Message
message
)
throws
IOException
{
return
JsonFormat
.
printer
().
omittingInsignificantWhitespace
().
print
(
message
);
}
private
void
mergeFromJson
(
String
json
,
Message
.
Builder
builder
)
throws
IOException
{
JsonFormat
.
parser
().
merge
(
json
,
builder
);
...
...
@@ -1166,4 +1169,59 @@ public class JsonFormatTest extends TestCase {
JsonFormat
.
parser
().
merge
(
"{\"optional_int32\": 54321}"
,
builder
);
assertEquals
(
54321
,
builder
.
getOptionalInt32
());
}
public
void
testOmittingInsignificantWhiteSpace
()
throws
Exception
{
TestAllTypes
message
=
TestAllTypes
.
newBuilder
().
setOptionalInt32
(
12345
).
build
();
assertEquals
(
"{"
+
"\"optionalInt32\":12345"
+
"}"
,
JsonFormat
.
printer
().
omittingInsignificantWhitespace
().
print
(
message
));
TestAllTypes
message1
=
TestAllTypes
.
getDefaultInstance
();
assertEquals
(
"{}"
,
JsonFormat
.
printer
().
omittingInsignificantWhitespace
().
print
(
message1
));
TestAllTypes
.
Builder
builder
=
TestAllTypes
.
newBuilder
();
setAllFields
(
builder
);
TestAllTypes
message2
=
builder
.
build
();
assertEquals
(
"{"
+
"\"optionalInt32\":1234,"
+
"\"optionalInt64\":\"1234567890123456789\","
+
"\"optionalUint32\":5678,"
+
"\"optionalUint64\":\"2345678901234567890\","
+
"\"optionalSint32\":9012,"
+
"\"optionalSint64\":\"3456789012345678901\","
+
"\"optionalFixed32\":3456,"
+
"\"optionalFixed64\":\"4567890123456789012\","
+
"\"optionalSfixed32\":7890,"
+
"\"optionalSfixed64\":\"5678901234567890123\","
+
"\"optionalFloat\":1.5,"
+
"\"optionalDouble\":1.25,"
+
"\"optionalBool\":true,"
+
"\"optionalString\":\"Hello world!\","
+
"\"optionalBytes\":\"AAEC\","
+
"\"optionalNestedMessage\":{"
+
"\"value\":100"
+
"},"
+
"\"optionalNestedEnum\":\"BAR\","
+
"\"repeatedInt32\":[1234,234],"
+
"\"repeatedInt64\":[\"1234567890123456789\",\"234567890123456789\"],"
+
"\"repeatedUint32\":[5678,678],"
+
"\"repeatedUint64\":[\"2345678901234567890\",\"345678901234567890\"],"
+
"\"repeatedSint32\":[9012,10],"
+
"\"repeatedSint64\":[\"3456789012345678901\",\"456789012345678901\"],"
+
"\"repeatedFixed32\":[3456,456],"
+
"\"repeatedFixed64\":[\"4567890123456789012\",\"567890123456789012\"],"
+
"\"repeatedSfixed32\":[7890,890],"
+
"\"repeatedSfixed64\":[\"5678901234567890123\",\"678901234567890123\"],"
+
"\"repeatedFloat\":[1.5,11.5],"
+
"\"repeatedDouble\":[1.25,11.25],"
+
"\"repeatedBool\":[true,true],"
+
"\"repeatedString\":[\"Hello world!\",\"ello world!\"],"
+
"\"repeatedBytes\":[\"AAEC\",\"AQI=\"],"
+
"\"repeatedNestedMessage\":[{"
+
"\"value\":100"
+
"},{"
+
"\"value\":200"
+
"}],"
+
"\"repeatedNestedEnum\":[\"BAR\",\"BAZ\"]"
+
"}"
,
toCompactJsonString
(
message2
));
}
}
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