@ -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 p rimitive 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 ( '"' ) ;
}
}