|  | @@ -32,6 +32,8 @@ package com.google.protobuf.nano;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.lang.reflect.Array;
 | 
	
		
			
				|  |  |  import java.lang.reflect.Field;
 | 
	
		
			
				|  |  | +import java.lang.reflect.InvocationTargetException;
 | 
	
		
			
				|  |  | +import java.lang.reflect.Method;
 | 
	
		
			
				|  |  |  import java.lang.reflect.Modifier;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
	
		
			
				|  | @@ -65,6 +67,8 @@ public final class MessageNanoPrinter {
 | 
	
		
			
				|  |  |              print(null, message, new StringBuffer(), buf);
 | 
	
		
			
				|  |  |          } catch (IllegalAccessException e) {
 | 
	
		
			
				|  |  |              return "Error printing proto: " + e.getMessage();
 | 
	
		
			
				|  |  | +        } catch (InvocationTargetException e) {
 | 
	
		
			
				|  |  | +            return "Error printing proto: " + e.getMessage();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          return buf.toString();
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -81,7 +85,8 @@ public final class MessageNanoPrinter {
 | 
	
		
			
				|  |  |       * @param buf the output buffer.
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      private static void print(String identifier, Object object,
 | 
	
		
			
				|  |  | -            StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException {
 | 
	
		
			
				|  |  | +            StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException,
 | 
	
		
			
				|  |  | +            InvocationTargetException {
 | 
	
		
			
				|  |  |          if (object == null) {
 | 
	
		
			
				|  |  |              // This can happen if...
 | 
	
		
			
				|  |  |              //   - we're about to print a message, String, or byte[], but it not present;
 | 
	
	
		
			
				|  | @@ -94,35 +99,71 @@ public final class MessageNanoPrinter {
 | 
	
		
			
				|  |  |                  buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n");
 | 
	
		
			
				|  |  |                  indentBuf.append(INDENT);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            Class<?> clazz = object.getClass();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            for (Field field : object.getClass().getFields()) {
 | 
	
		
			
				|  |  | -                // Proto fields are public, non-static variables that do not begin or end with '_'
 | 
	
		
			
				|  |  | +            // Proto fields follow one of two formats:
 | 
	
		
			
				|  |  | +            //
 | 
	
		
			
				|  |  | +            // 1) Public, non-static variables that do not begin or end with '_'
 | 
	
		
			
				|  |  | +            // Find and print these using declared public fields
 | 
	
		
			
				|  |  | +            for (Field field : clazz.getFields()) {
 | 
	
		
			
				|  |  |                  int modifiers = field.getModifiers();
 | 
	
		
			
				|  |  |                  String fieldName = field.getName();
 | 
	
		
			
				|  |  | -                if ((modifiers & Modifier.PUBLIC) != Modifier.PUBLIC
 | 
	
		
			
				|  |  | -                        || (modifiers & Modifier.STATIC) == Modifier.STATIC
 | 
	
		
			
				|  |  | -                        || fieldName.startsWith("_") || fieldName.endsWith("_")) {
 | 
	
		
			
				|  |  | -                    continue;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                Class<?> fieldType = field.getType();
 | 
	
		
			
				|  |  | -                Object value = field.get(object);
 | 
	
		
			
				|  |  | +                if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC
 | 
	
		
			
				|  |  | +                        && (modifiers & Modifier.STATIC) != Modifier.STATIC
 | 
	
		
			
				|  |  | +                        && !fieldName.startsWith("_")
 | 
	
		
			
				|  |  | +                        && !fieldName.endsWith("_")) {
 | 
	
		
			
				|  |  | +                    Class<?> fieldType = field.getType();
 | 
	
		
			
				|  |  | +                    Object value = field.get(object);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (fieldType.isArray()) {
 | 
	
		
			
				|  |  | -                    Class<?> arrayType = fieldType.getComponentType();
 | 
	
		
			
				|  |  | +                    if (fieldType.isArray()) {
 | 
	
		
			
				|  |  | +                        Class<?> arrayType = fieldType.getComponentType();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    // bytes is special since it's not repeated, but is represented by an array
 | 
	
		
			
				|  |  | -                    if (arrayType == byte.class) {
 | 
	
		
			
				|  |  | -                        print(fieldName, value, indentBuf, buf);
 | 
	
		
			
				|  |  | -                    } else {
 | 
	
		
			
				|  |  | -                        int len = value == null ? 0 : Array.getLength(value);
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < len; i++) {
 | 
	
		
			
				|  |  | -                            Object elem = Array.get(value, i);
 | 
	
		
			
				|  |  | -                            print(fieldName, elem, indentBuf, buf);
 | 
	
		
			
				|  |  | +                        // bytes is special since it's not repeated, but is represented by an array
 | 
	
		
			
				|  |  | +                        if (arrayType == byte.class) {
 | 
	
		
			
				|  |  | +                            print(fieldName, value, indentBuf, buf);
 | 
	
		
			
				|  |  | +                        } else {
 | 
	
		
			
				|  |  | +                            int len = value == null ? 0 : Array.getLength(value);
 | 
	
		
			
				|  |  | +                            for (int i = 0; i < len; i++) {
 | 
	
		
			
				|  |  | +                                Object elem = Array.get(value, i);
 | 
	
		
			
				|  |  | +                                print(fieldName, elem, indentBuf, buf);
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  | +                    } else {
 | 
	
		
			
				|  |  | +                        print(fieldName, value, indentBuf, buf);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | -                } else {
 | 
	
		
			
				|  |  | -                    print(fieldName, value, indentBuf, buf);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // 2) Fields that are accessed via getter methods (when accessors
 | 
	
		
			
				|  |  | +            //    mode is turned on)
 | 
	
		
			
				|  |  | +            // Find and print these using getter methods.
 | 
	
		
			
				|  |  | +            for (Method method : clazz.getMethods()) {
 | 
	
		
			
				|  |  | +                String name = method.getName();
 | 
	
		
			
				|  |  | +                // Check for the setter accessor method since getters and hazzers both have
 | 
	
		
			
				|  |  | +                // non-proto-field name collisions (hashCode() and getSerializedSize())
 | 
	
		
			
				|  |  | +                if (name.startsWith("set")) {
 | 
	
		
			
				|  |  | +                    String subfieldName = name.substring(3);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    Method hazzer = null;
 | 
	
		
			
				|  |  | +                    try {
 | 
	
		
			
				|  |  | +                        hazzer = clazz.getMethod("has" + subfieldName);
 | 
	
		
			
				|  |  | +                    } catch (NoSuchMethodException e) {
 | 
	
		
			
				|  |  | +                        continue;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    // If hazzer does't exist or returns false, no need to continue
 | 
	
		
			
				|  |  | +                    if (!(Boolean) hazzer.invoke(object)) {
 | 
	
		
			
				|  |  | +                        continue;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    Method getter = null;
 | 
	
		
			
				|  |  | +                    try {
 | 
	
		
			
				|  |  | +                        getter = clazz.getMethod("get" + subfieldName);
 | 
	
		
			
				|  |  | +                    } catch (NoSuchMethodException e) {
 | 
	
		
			
				|  |  | +                        continue;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    print(subfieldName, getter.invoke(object), indentBuf, buf);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              if (identifier != null) {
 |