I was looking for a similar functionality. One thing that i noticed probably comments in proto are missed out while printing DebugString?
On Thursday, 19 May 2011 21:13:15 UTC+8, Ben Wright wrote: > > 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 <[email protected]> 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: [email protected] (Kenton Varda) > > * <br> Based on original Protocol Buffers design by > > * <br> Sanjay Ghemawat, Jeff Dean, and others. > > * > > * @author Benjamin Wright ([email protected]) > > */ > > 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 unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/protobuf. For more options, visit https://groups.google.com/d/optout.
