previous thread:
http://groups.google.com/group/protobuf/browse_thread/thread/4bf8bca8c88e82ba/dbaa2803984f3934?lnk=gst&q=debugString()#dbaa2803984f3934

On May 18, 6:05 pm, Ben Wright <compuware...@gmail.com> wrote:
> There has been some back and forth previously about java language
> support for generating a proto file from a Descriptor.
>
> The suggested implementation was to either wrap or port the
> DebugString capability from decriptor.cc
>
> I recently ported the DebugString capability to java - it's a bit
> rough as it's a by-hand port from the c code, but I also fixed some
> bugs in the way the file was generated.  For instance, extended types
> were not output with correct parenthesis around them and options that
> were messages did not have appropriate {} around them - these could
> easily be due to differences in the C and Java code though.  I'd be
> glad to elaborate further for anyone interested, but for now I'm
> simply providing the ported code as static functions in a java file.
> Notably, if integrated with the java library these functions should
> probably not be in a static file, they should be included with their
> appropriate descriptor types.
>
> If it is decided that this functionality should be part of the Java
> library, I would be willing to do the leg work and get these functions
> in better shape and update the appropriate files.  I can pass them
> along in an issue report for a committer to check in.
>
> Notably, if you're looking for someone to work on the Java library /
> outstanding issues at all, I'm looking for something to do in my
> mythical free time.  I could help with c too, but I'm much stronger in
> Java.
>
> PS: This is all based on release 2.4.1
>
> ======================= DebugString.java ===================
>
> import java.io.IOException;
> import java.util.ArrayList;
> import java.util.HashSet;
> import java.util.List;
> import java.util.Set;
> import java.util.Stack;
>
> import com.google.protobuf.Descriptors.Descriptor;
> import com.google.protobuf.Descriptors.EnumDescriptor;
> import com.google.protobuf.Descriptors.EnumValueDescriptor;
> import com.google.protobuf.Descriptors.FieldDescriptor;
> import com.google.protobuf.Descriptors.FileDescriptor;
> import com.google.protobuf.Descriptors.MethodDescriptor;
> import com.google.protobuf.Descriptors.ServiceDescriptor;
> import com.google.protobuf.Message;
> import com.google.protobuf.TextFormat;
>
> /**
>  * This class provides .proto file generation from Java Proto
> Descriptors.
>  * <br>Derived from descriptor.cc in Protobuf 2.4.1
>  * <br>
>  * <br><b>Original Copyright Notice from descriptor.cc:</b>
>  * <br>
>  * <br> Protocol Buffers - Google's data interchange format
>  * <br> Copyright 2008 Google Inc.  All rights reserved.
>  * <br>http://code.google.com/p/protobuf/
>  * <br>
>  * <br> Redistribution and use in source and binary forms, with or
> without
>  * <br> modification, are permitted provided that the following
> conditions are
>  * <br> met:
>  * <br>
>  * <br>     * Redistributions of source code must retain the above
> copyright
>  * <br> notice, this list of conditions and the following disclaimer.
>  * <br>     * Redistributions in binary form must reproduce the above
>  * <br> copyright notice, this list of conditions and the following
> disclaimer
>  * <br> in the documentation and/or other materials provided with the
>  * <br> distribution.
>  * <br>     * Neither the name of Google Inc. nor the names of its
>  * <br> contributors may be used to endorse or promote products
> derived from
>  * <br> this software without specific prior written permission.
>  * <br>
>  * <br> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
>  * <br> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
>  * <br> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
>  * <br> A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
>  * <br> OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
>  * <br> SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
>  * <br> LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
>  * <br> DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> ON ANY
>  * <br> THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
>  * <br> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
>  * <br> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
>  * <br>
>  * <br> Author: ken...@google.com (Kenton Varda)
>  * <br>  Based on original Protocol Buffers design by
>  * <br>  Sanjay Ghemawat, Jeff Dean, and others.
>  *
>  * @author Benjamin Wright (compuware...@gmail.com)
>  */
> public class DebugString {
>
>         private static void SubstituteAndAppend(StringBuilder contents,
> String replace, Object... objects ) {
>                 for(int i = 0; i < objects.length; i++) {
>                         final String old = "$"+i;
>                         replace = replace.replace(old, 
> String.valueOf(objects[i]));
>                 }
>                 contents.append(replace);
>         }
>
>         private static String PrintFieldValueToString(Message message,
>                         FieldDescriptor fieldDescriptor, int i) {
>                 return valueAsString(fieldDescriptor,
> message.getField(fieldDescriptor));
>         }
>
>         private static String DefaultValueAsString(FieldDescriptor
> fieldDescriptor, boolean b) {
>                 return valueAsString(fieldDescriptor,
> fieldDescriptor.getDefaultValue());
>         }
>
>         private static String valueAsString(FieldDescriptor fieldDescriptor,
> Object value) {
>                 StringBuilder v = new StringBuilder();
>                 try {
>                         TextFormat.printFieldValue(fieldDescriptor, value, v);
>                 } catch (IOException e) {
>                 }
>                 return v.toString();//.replace("\n", "").replace("\\", 
> "\\\\");
>         }
>
>         private static String prefix(int d, char str) {
>                 StringBuilder sb = new StringBuilder();
>
>                 for(int i = 0; i < d; i++)
>                         sb.append(str);
>
>                 return sb.toString();
>         }
>
>         private static String join(Stack<String> all_options, String string)
> {
>                 boolean init = true;
>                 StringBuilder sb = new StringBuilder();
>                 for(String option : all_options) {
>                         if(init) {
>                                 init = false;
>                         } else {
>                                 sb.append(string);
>                         }
>                         sb.append(option);
>                 }
>                 return sb.toString();
>         }
>
>         // DebugString methods
> ===============================================
>
>         // Used by each of the option formatters.
>         static boolean RetrieveOptions(final Message options, Stack<String>
> option_entries) {
>           option_entries.clear();
>           List<FieldDescriptor> fields = new
> ArrayList<FieldDescriptor>(options.getAllFields().keySet());
>           for (int i = 0; i < fields.size(); i++) {
>
>             int count = 1;
>             boolean repeated = false;
>             if (fields.get(i).isRepeated()) {
>               count = options.getRepeatedFieldCount(fields.get(i));
>               repeated = true;
>             }
>             for (int j = 0; j < count; j++) {
>               String fieldval =
>               PrintFieldValueToString(options, fields.get(i),
>                           repeated ? count : -1);
>
> //            .replace("google.protobuf.FileOptions.", "")
>
>                 final boolean msg = (fields.get(i).getJavaType() ==
> FieldDescriptor.JavaType.MESSAGE);
>
>               final String fullName = fields.get(i).getFullName();
>               option_entries.push(
>                           (fields.get(i).isExtension() ? "(" : "") +
>                           (fullName.startsWith("google.protobuf.") ?
> fullName.substring(fullName.lastIndexOf('.')+1): fullName) +
>                           (fields.get(i).isExtension() ? ")" : "") +
>                           " = " +
>                           (msg?"{\n":"") +
>                           "  "+ fieldval +
>                           (msg?"}":"") );
>             }
>           }
>           return !option_entries.isEmpty();
>         }
>
>         // Formats options that all appear together in brackets. Does not
> include
>         // brackets.
>         static boolean FormatBracketedOptions(final Message options,
> StringBuilder output) {
>           Stack<String> all_options = new Stack<String>();
>           if (RetrieveOptions(options, all_options)) {
>             output.append(join(all_options, ",\n"));
>           }
>           return !all_options.isEmpty();
>         }
>
>         // Formats options one per line
>         static boolean FormatLineOptions(int depth, final Message options,
> StringBuilder output) {
>           String prefix = prefix(depth * 2, ' ');
>           Stack<String> all_options = new Stack<String>();
>           if (RetrieveOptions(options, all_options)) {
>             for (int i = 0; i < all_options.size(); i++) {
>               SubstituteAndAppend(output, "$0option $1;\n",
>                                            prefix, all_options.get(i));
>             }
>           }
>           return !all_options.isEmpty();
>         }
>
> //      }  // anonymous namespace
>
>         /**
>          * Top level return function
>          */
>         static public StringBuilder FileDescriptor_DebugString(FileDescriptor
> fd) {
>                 return FileDescriptor_DebugString(fd, false);
>         }
>         /**
>          * Top level return function
>          */
>         static public StringBuilder FileDescriptor_DebugString(FileDescriptor
> fd, boolean includeProtocolSyntaxVersion) {
>           StringBuilder contents = new StringBuilder();
>
>           if(includeProtocolSyntaxVersion) {
>                   contents.append("syntax = \"proto2\";\n\n");
>           }
>
>           if (!fd.getPackage().isEmpty()) {
>             SubstituteAndAppend(contents, "package $0;\n\n",
> fd.getPackage());
>           }
>
>           for (FileDescriptor dependency : fd.getDependencies()) {
>             SubstituteAndAppend(contents, "import \"$0\";\n",
>                                          dependency.getName());
>           }
>
>           if(!fd.getDependencies().isEmpty()){
>                   contents.append("\n");
>           }
>
>           if (FormatLineOptions(0, fd.getOptions(), contents)) {
>             contents.append("\n");  // add some space if we had options
>           }
>
>           for (EnumDescriptor enum_type : fd.getEnumTypes()) {
>                 EnumDescriptor_DebugString(enum_type, 0, contents);
>             contents.append("\n");
>           }
>
>           // Find all the 'group' type extensions; we will not output their
> nested
>           // definitions (those will be done with their group field
> descriptor).
>           Set<Descriptor> groups = new HashSet<Descriptor>();
>           for (FieldDescriptor extension : fd.getExtensions()) {
>             if (extension.getType() == FieldDescriptor.Type.GROUP) {
>               groups.add(extension.getMessageType());
>             }
>           }
>
>           for (Descriptor message_type : fd.getMessageTypes()) {
>             if (!groups.contains(message_type)) {
>               SubstituteAndAppend(contents, "message $0",
>                                            message_type.getName());
>               Descriptor_DebugString(message_type, 0, contents);
>               contents.append("\n");
>             }
>           }
>
>           for (ServiceDescriptor service : fd.getServices()) {
>                   ServiceDescriptor_DebugString(service, contents);
>             contents.append("\n");
>           }
>
>           Descriptor containing_type = null;
>           for (FieldDescriptor extension : fd.getExtensions()) {
>             if (extension.getContainingType() != containing_type) {
>               if (containing_type != null) contents.append("}\n\n");
>               containing_type = extension.getContainingType();
>               SubstituteAndAppend(contents, "extend $0 {\n",
>                                            containing_type.getFullName());
>             }
>             FieldDescriptor_DebugString(extension, 1, contents);
>           }
>           if (fd.getExtensions().size() > 0) contents.append("}\n\n");
>
>           return contents;
>         }
>
>         static public StringBuilder Descriptor_DebugString(Descriptor d) {
>           StringBuilder contents = new StringBuilder();
>           SubstituteAndAppend(contents, "message $0", d.getName());
>           Descriptor_DebugString(d, 0, contents);
>           return contents;
>         }
>
>         static void Descriptor_DebugString(Descriptor d, int depth,
> StringBuilder contents) {
>           String prefix = prefix(depth * 2, ' ');
>           ++depth;
>           contents.append(" {\n");
>
>           FormatLineOptions(depth, d.getOptions(), contents);
>
>           // Find all the 'group' types for fields and extensions; we will
> not output
>           // their nested definitions (those will be done with their group
> field
>           // descriptor).
>           Set<Descriptor> groups = new HashSet<Descriptor>();
>           for (int i = 0; i < d.getFields().size(); i++) {
>             if (d.getFields().get(i).getType() == FieldDescriptor.Type.GROUP)
> {
>               groups.add(d.getFields().get(i).getMessageType());
>             }
>           }
>           for (int i = 0; i < d.getExtensions().size(); i++) {
>             if (d.getExtensions().get(i).getType() ==
> FieldDescriptor.Type.GROUP) {
>               groups.add(d.getExtensions().get(i).getMessageType());
>             }
>           }
>
>           for (int i = 0; i < d.getNestedTypes().size(); i++) {
>             if (!groups.contains(d.getNestedTypes().get(i))) {
>               SubstituteAndAppend(contents, "$0  message $1",
>                                            prefix,
> d.getNestedTypes().get(i).getName());
>               Descriptor_DebugString(d.getNestedTypes().get(i), depth,
> contents);
>             }
>           }
>           for (int i = 0; i < d.getEnumTypes().size(); i++) {
>             EnumDescriptor_DebugString(d.getEnumTypes().get(i), depth,
> contents);
>           }
>           for (int i = 0; i < d.getFields().size(); i++) {
>             FieldDescriptor_DebugString(d.getFields().get(i), depth,
> contents);
>           }
>
>           final int max = 536870911;
>
>           for (int i = 0; i < d.toProto().getExtensionRangeCount(); i++) {
>                   final int end = d.toProto().getExtensionRange(i).getEnd() - 
> 1;
>             SubstituteAndAppend(contents, "$0  extensions $1 to $2;\n",
>                                          prefix,
>
> d.toProto().getExtensionRange(i).getStart(),
>                                          (end == max ? "max" : end)
>                                          );
>           }
>
>           // Group extensions by what they extend, so they can be printed out
> together.
>           Descriptor containing_type = null;
>           for (int i = 0; i < d.getExtensions().size(); i++) {
>             if (d.getExtensions().get(i).getContainingType() !=
> containing_type) {
>               if (i > 0) SubstituteAndAppend(contents, "$0  }\n", prefix);
>               containing_type = d.getExtensions().get(i).getContainingType();
>               SubstituteAndAppend(contents, "$0  extend .$1 {\n",
>                                            prefix,
> containing_type.getFullName());
>             }
>             FieldDescriptor_DebugString(d.getExtensions().get(i), depth + 1,
> contents);
>           }
>           if (d.getExtensions().size() > 0)
>             SubstituteAndAppend(contents, "$0  }\n", prefix);
>
>           SubstituteAndAppend(contents, "$0}\n", prefix);
>         }
>
>         static public StringBuilder
> FieldDescriptor_DebugString(FieldDescriptor d) {
>           StringBuilder contents = new StringBuilder();
>           int depth = 0;
>           if (d.isExtension()) {
>             SubstituteAndAppend(contents, "extend .$0 {\n",
>
> d.getContainingType().getFullName());
>             depth = 1;
>           }
>           FieldDescriptor_DebugString(d, depth, contents);
>           if (d.isExtension()) {
>              contents.append("}\n");
>           }
>           return contents;
>         }
>
>         static void FieldDescriptor_DebugString(FieldDescriptor d, int depth,
> StringBuilder contents) {
>                 final String pckg = d.getFile().getPackage();
>           String prefix = prefix(depth * 2, ' ');
>           String field_type;
>           switch (d.getType()) {
>             case MESSAGE:
>               field_type =
> d.getMessageType().getFile().getPackage().equals(pckg) ?
> d.getMessageType().getName() : d.getMessageType().getFullName();
>               break;
>             case ENUM:
>               field_type =
> d.getEnumType().getFile().getPackage().equals(pckg) ?
> d.getEnumType().getName() : d.getEnumType().getFullName();
>               break;
>             default:
>               field_type = d.getType().name().toLowerCase();
>           }
>
>           final String label;
>           switch(d.toProto().getLabel()){
>           case LABEL_OPTIONAL:
>           default:
>                   label = "optional";
>                   break;
>           case LABEL_REPEATED:
>                   label = "repeated";
>                   break;
>           case LABEL_REQUIRED:
>                   label = "required";
>                   break;
>           }
>
>           SubstituteAndAppend(contents, "$0$1 $2 $3 = $4",
>                                        prefix,
>                                        label,
>                                        field_type,
>                                        d.getType() ==
> FieldDescriptor.Type.GROUP ? d.getMessageType().getName() :
>                                                               d.getName(),
>                                        d.getNumber());
>
>           boolean bracketed = false;
>           if (d.hasDefaultValue()) {
>             bracketed = true;
>             SubstituteAndAppend(contents, " [default = $0",
>                                          DefaultValueAsString(d, true));
>           }
>
>           StringBuilder formatted_options = new StringBuilder();
>           if (FormatBracketedOptions(d.getOptions(), formatted_options)) {
>             contents.append(bracketed ? ", " : " [");
>             bracketed = true;
>             contents.append(formatted_options);
>           }
>
>           if (bracketed) {
>             contents.append("]");
>           }
>
>           if (d.getType() == FieldDescriptor.Type.GROUP) {
>             Descriptor_DebugString(d.getMessageType(), depth, contents);
>           } else {
>             contents.append(";\n");
>           }
>         }
>
>         static public StringBuilder EnumDescriptor_DebugString(EnumDescriptor
> d) {
>           StringBuilder contents = new StringBuilder();
>           EnumDescriptor_DebugString(d, 0, contents);
>           return contents;
>         }
>
>         static void EnumDescriptor_DebugString(EnumDescriptor d, int depth,
> StringBuilder contents) {
>           String prefix = prefix(depth * 2, ' ');
>           ++depth;
>           SubstituteAndAppend(contents, "$0enum $1 {\n",
>                                        prefix, d.getName());
>
>           FormatLineOptions(depth, d.getOptions(), contents);
>
>           for (EnumValueDescriptor value : d.getValues()) {
>                   EnumValueDescriptor_DebugString(value, depth, contents);
>           }
>           SubstituteAndAppend(contents, "$0}\n", prefix);
>         }
>
>         static public StringBuilder
> EnumValueDescriptor_DebugString(EnumValueDescriptor d) {
>           StringBuilder contents = new StringBuilder();
>           EnumValueDescriptor_DebugString(d, 0, contents);
>           return contents;
>         }
>
>         static void EnumValueDescriptor_DebugString(EnumValueDescriptor d,
> int depth, StringBuilder contents) {
>           String prefix = prefix(depth * 2, ' ');
>           SubstituteAndAppend(contents, "$0$1 = $2",
>                                        prefix, d.getName(), d.getNumber());
>
>           StringBuilder formatted_options = new StringBuilder();
>           if (FormatBracketedOptions(d.getOptions(), formatted_options)) {
>             SubstituteAndAppend(contents, " [$0]", formatted_options);
>           }
>           contents.append(";\n");
>         }
>
>         static public StringBuilder
> ServiceDescriptor_DebugString(ServiceDescriptor d) {
>           StringBuilder contents = new StringBuilder();
>           ServiceDescriptor_DebugString(d, contents);
>           return contents;
>         }
>
>         static void ServiceDescriptor_DebugString(ServiceDescriptor d,
> StringBuilder contents) {
>           SubstituteAndAppend(contents, "service $0 {\n", d.getName());
>
>           FormatLineOptions(1, d.getOptions(), contents);
>
>           for (MethodDescriptor method : d.getMethods()) {
>                   MethodDescriptor_DebugString(method, 1, contents);
>           }
>
>           contents.append("}\n");
>         }
>
>         static public StringBuilder
> MethodDescriptor_DebugString(MethodDescriptor d) {
>           StringBuilder contents = new StringBuilder();
>           MethodDescriptor_DebugString(d, 0, contents);
>           return contents;
>         }
>
>         static void MethodDescriptor_DebugString(MethodDescriptor d, int
> depth, StringBuilder contents) {
>           String prefix = prefix(depth * 2, ' ');
>           ++depth;
>           SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)",
>                                        prefix, d.getName(),
>                                        d.getInputType().getFullName(),
>                                        d.getOutputType().getFullName());
>
>           StringBuilder formatted_options = new StringBuilder();
>           if (FormatLineOptions(depth, d.getOptions(), formatted_options)) {
>             SubstituteAndAppend(contents, " {\n$0$1}\n",
>                                          formatted_options, prefix);
>           } else {
>             contents.append(";\n");
>           }
>         }
>         //
> ===================================================================
>
>
>
>
>
>
>
> }

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To post to this group, send email to protobuf@googlegroups.com.
To unsubscribe from this group, send email to 
protobuf+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/protobuf?hl=en.

Reply via email to