diff options
author | Nicholas Seckar <seckar@google.com> | 2013-11-09 16:12:17 -0800 |
---|---|---|
committer | Nicholas Seckar <seckar@google.com> | 2013-11-15 07:54:07 -0800 |
commit | 62a22a732fb134e5f34dd3e01920933ca5b16346 (patch) | |
tree | 408f11eb68a020bfbe59bc81fc4088b608d6779b /java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java | |
parent | 8a15121c1077fe883f428bd27dee6b99e06e48b6 (diff) | |
download | external_protobuf-62a22a732fb134e5f34dd3e01920933ca5b16346.zip external_protobuf-62a22a732fb134e5f34dd3e01920933ca5b16346.tar.gz external_protobuf-62a22a732fb134e5f34dd3e01920933ca5b16346.tar.bz2 |
Update MessageNano#toString() to return mostly valid TextFormat.
The output of toString is now aligned with that used by non-nano and C++
runtimes, with the exception of groups. Groups should be serialized using a
camelized name (e.g. "FooBar" rather than "foo_bar") however the nano runtime
does not have information on which fields are groups.
Changes are:
- bytes fields are output within double-quotes, non-printable characters are
output as octal escape sequences (i.e. \NNN);
- field identifiers are output in underscored format;
- unset fields are not output (rather than printing "null");
- the type name of the root message is not output.
With these changes the nano toString, normal toString, and C++'s DebugString all
produce equivalent output when given the same message. (Provided that message
uses no deprecated features.)
Change-Id: Id4791d73822846db29344db9f7bc3781c3e183a6
Diffstat (limited to 'java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java')
-rw-r--r-- | java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java | 72 |
1 files changed, 55 insertions, 17 deletions
diff --git a/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java index 3a5ee7c..d135a51 100644 --- a/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java +++ b/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java @@ -47,20 +47,22 @@ public final class MessageNanoPrinter { private static final int MAX_STRING_LEN = 200; /** - * Returns an text representation of a MessageNano suitable for debugging. + * Returns an text representation of a MessageNano suitable for debugging. The returned string + * is mostly compatible with Protocol Buffer's TextFormat (as provided by non-nano protocol + * buffers) -- groups (which are deprecated) are output with an underscore name (e.g. foo_bar + * instead of FooBar) and will thus not parse. * * <p>Employs Java reflection on the given object and recursively prints primitive fields, * groups, and messages.</p> */ public static <T extends MessageNano> String print(T message) { if (message == null) { - return "null"; + return ""; } StringBuffer buf = new StringBuffer(); try { - print(message.getClass().getSimpleName(), message.getClass(), message, - new StringBuffer(), buf); + print(null, message.getClass(), message, new StringBuffer(), buf); } catch (IllegalAccessException e) { return "Error printing proto: " + e.getMessage(); } @@ -70,21 +72,30 @@ public final class MessageNanoPrinter { /** * Function that will print the given message/class into the StringBuffer. * Meant to be called recursively. + * + * @param identifier the identifier to use, or {@code null} if this is the root message to + * print. + * @param clazz the class of {@code message}. + * @param message the value to print. May in fact be a primitive value or byte array and not a + * message. + * @param indentBuf the indentation each line should begin with. + * @param buf the output buffer. */ private static void print(String identifier, Class<?> clazz, Object message, StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException { - if (MessageNano.class.isAssignableFrom(clazz)) { - // Nano proto message - buf.append(indentBuf).append(identifier); - - // If null, just print it and return - if (message == null) { - buf.append(": ").append(message).append("\n"); - return; + if (message == null) { + // This can happen if... + // - we're about to print a message, String, or byte[], but it not present; + // - we're about to print a primitive, but "reftype" optional style is enabled, and + // the field is unset. + // In both cases the appropriate behavior is to output nothing. + } else if (MessageNano.class.isAssignableFrom(clazz)) { // Nano proto message + int origIndentBufLength = indentBuf.length(); + if (identifier != null) { + buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n"); + indentBuf.append(INDENT); } - indentBuf.append(INDENT); - buf.append(" <\n"); for (Field field : clazz.getFields()) { // Proto fields are public, non-static variables that do not begin or end with '_' int modifiers = field.getModifiers(); @@ -115,15 +126,19 @@ public final class MessageNanoPrinter { print(fieldName, fieldType, value, indentBuf, buf); } } - indentBuf.delete(indentBuf.length() - INDENT.length(), indentBuf.length()); - buf.append(indentBuf).append(">\n"); + if (identifier != null) { + indentBuf.setLength(origIndentBufLength); + buf.append(indentBuf).append(">\n"); + } } else { - // Primitive value + // Non-null primitive value identifier = deCamelCaseify(identifier); buf.append(indentBuf).append(identifier).append(": "); if (message instanceof String) { String stringMessage = sanitizeString((String) message); buf.append("\"").append(stringMessage).append("\""); + } else if (message instanceof byte[]) { + appendQuotedBytes((byte[]) message, buf); } else { buf.append(message); } @@ -176,4 +191,27 @@ public final class MessageNanoPrinter { } return b.toString(); } + + /** + * Appends a quoted byte array to the provided {@code StringBuffer}. + */ + private static void appendQuotedBytes(byte[] bytes, StringBuffer builder) { + if (bytes == null) { + builder.append("\"\""); + return; + } + + builder.append('"'); + for (int i = 0; i < bytes.length; ++i) { + int ch = bytes[i]; + if (ch == '\\' || ch == '"') { + builder.append('\\').append((char) ch); + } else if (ch >= 32 && ch < 127) { + builder.append((char) ch); + } else { + builder.append(String.format("\\%03o", ch)); + } + } + builder.append('"'); + } } |