-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON Option for List Command #57
base: master
Are you sure you want to change the base?
Conversation
@@ -0,0 +1,20 @@ | |||
package me.dinowernli.grpc.polyglot.command; | |||
|
|||
public class Method { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to define these custom types (here and services below)?
Can we not just use the methoddescriptor produced by protobuf?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, we could hard code the logic to print straight to JSON from the protobuf descriptors. I think though that if there is going to be more than one output format option that it will be much easier to use pre-existing tools to process the java object, eg using gson takes one line to go to JSON, I imagine there will be other options to go to other formats just as easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General approach looks sound, but I don't think we should be introducing those mutable types for service and method.
|
||
if (jsonOutput.isPresent() && jsonOutput.get()) { | ||
Gson gson = new Gson(); | ||
output.writeLine(gson.toJson(services)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed above, can we not just json-print the descriptors rather than converting them to our custom data type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into using the JSON printing but when I tried this it looked like it would take more work. The JSON printed did not resolve all the way down to the primitive level as the as the output currently does. Say a proto message is defined:
"foo": {
"name": "STRING",
"id": "INT"
}
The JSON output would be:
"foo": "Foo"
This doesn't give enough information to people to allow them to construct their own messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's what you get when you print a message descriptor. What you actually want is the service descriptor [1]. That should get you the service name, the method name, and the type name for the messages. Service descriptors are already conveniently returns by listServices()
[1] https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto#L230
@@ -84,6 +84,13 @@ | |||
usage="If true, then the message specification for the method is rendered") | |||
private String withMessageArg; | |||
|
|||
//TODO: Move to a "list_services"-specific flag container | |||
@Option( | |||
name = "--json_output", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have this be a --list_output_format and have "json" be one of the valid flag values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure this should be pretty easy and will be more extensible in the future
@@ -5,6 +5,7 @@ | |||
import com.google.protobuf.DescriptorProtos.FileDescriptorSet; | |||
import me.dinowernli.grpc.polyglot.command.ServiceCall; | |||
import me.dinowernli.grpc.polyglot.command.ServiceList; | |||
//import me.dinowernli.grpc.polyglot.command.Server; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spurious comment
|
||
if (jsonOutput.isPresent() && jsonOutput.get()) { | ||
Gson gson = new Gson(); | ||
output.writeLine(gson.toJson(services)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's what you get when you print a message descriptor. What you actually want is the service descriptor [1]. That should get you the service name, the method name, and the type name for the messages. Service descriptors are already conveniently returns by listServices()
[1] https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto#L230
I've updated with your suggestions. The merging process went a little awry on my end, the main changes are in the ServiceList, Main, and CommandLineArgs. Changes:
|
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
done
… On 17 Aug 2017, at 18:54, googlebot ***@***.***> wrote:
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).
📝 Please visit https://cla.developers.google.com/ <https://cla.developers.google.com/> to sign.
Once you've signed, please reply here (e.g. I signed it!) and we'll verify. Thanks.
If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check your existing CLA data <https://cla.developers.google.com/clas> and verify that your email is set on your git commits <https://help.github.com/articles/setting-your-email-in-git/>.
If your company signed a CLA, they designated a Point of Contact who decides which employees are authorized to participate. You may need to contact the Point of Contact for your company and ask to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the project maintainer to go/cla#troubleshoot.
In order to pass this check, please resolve this problem and have the pull request author add another comment and the bot will run again.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub <#57 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AM1d-aNMeoRuRPBdpcDbrmHQFvBDnLHrks5sZH5WgaJpZM4OtxP7>.
|
CLAs look good, thanks! |
if (listOutputFormat.isPresent() && listOutputFormat.get().equals("json")) output.write("[\n"); else output.newLine(); | ||
|
||
// Dealing with commas for JSON | ||
boolean firstServiceHasBeenPrinted = false; | ||
|
||
for (ServiceDescriptor descriptor : serviceResolver.listServices()) { | ||
boolean matchingDescriptor = | ||
!serviceFilter.isPresent() | ||
|| descriptor.getFullName().toLowerCase().contains(serviceFilter.get().toLowerCase()); | ||
|
||
if (matchingDescriptor) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there :) Any chance we can just print the json of descriptor.toProto()? That should give you the information you need and avoid manually constructing json output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could try but will need some help. As I think I mentioned before as far as I can tell using the JsonPrinters do not do what we need. eg.
printing:String jsonFormat = JsonFormat.printer().print(descriptor.toProto().toBuilder());
Returns something similar to:
{ "name": "TestMethod", "inputType": ".polyglot.test.TestRequest", "outputType": ".polyglot.test.TestResponse", "options": {} }
There is not enough information about the types. I imagine you could recursively resolve every type which is more than one level deep to get down to the primitive level of strings, int etc. but this will require a decent change to the code.
I think this approach is the simplest method given what's already written but if you know a better way then let me know.
File protoDiscoveryDir = new File(protoDiscoveryRoot).getParentFile(); | ||
Optional<Boolean> withMessage, | ||
Optional<String> listOutputFormat) { | ||
boolean firstMethodHasBeenPrinted = false; | ||
|
||
for (MethodDescriptor method : descriptor.getMethods()) { | ||
if (!methodFilter.isPresent() || method.getName().contains(methodFilter.get())) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, you should be able to just json-format the method protos.
Changes
See src/test/java/me/dinowernli/grpc/polyglot/command/jsonOutputGold.txt for more illustrative example
Notes
|
.orElseThrow(() -> new IllegalArgumentException("Could not find named config: " + name)); | ||
.filter(config -> config.getName().equals(name)) | ||
.findAny() | ||
.orElseThrow(() -> new IllegalArgumentException("Could not find named config: " + name)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: indentation here was correct, please revert
@@ -65,7 +75,14 @@ public void onError(Throwable t) { | |||
@Override | |||
public void onNext(T message) { | |||
try { | |||
output.write(jsonPrinter.print(message) + MESSAGE_SEPARATOR); | |||
String outputString = jsonPrinter.print(message); | |||
// Only separate messages if there are more than one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't actually think this is the right thing to do. To make things easier to parse, I believe we alway want to append a separator, even if there is nothing else coming. Can discuss in person.
|
||
/** | ||
* Creates a new {@link MessageWriter} which writes the messages it sees to the supplied | ||
* {@link Output}. | ||
*/ | ||
public static <T extends Message> MessageWriter<T> create(Output output) { | ||
return new MessageWriter<T>(JsonFormat.printer(), output); | ||
public static <T extends Message> MessageWriter<T> create(Output output, String messageSeparator) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's have two factory methods, one called create(), and the other called createWithSeparator().
That way, there is a sensible default and we don't need the ServiceCall class to understand how these separators work.
.addFile(TestProto.getDescriptor().toProto()) | ||
.addFile(FooProto.getDescriptor().toProto()) | ||
.build(); | ||
.addFile(TestProto.getDescriptor().toProto()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation was correct, please revert (thoughout most of this file)
recordingOutput.close(); | ||
|
||
validateMessageOutput(recordingOutput.getContentsAsString()); | ||
} | ||
|
||
// @Test | ||
// public void testServiceListOutputWithMessageDetailJsonFormatted() throws Throwable { | ||
// ServiceList.listServices( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove this commented-out test
} | ||
|
||
private static void printJsonOutput(Output output, ServiceResolver serviceResolver, Optional<String> serviceFilter) { | ||
output.writeLine("{ \"serviceProtos\": ["); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably not be constructing json ourselves here. If we want to wrap the existing protobuf output, we should define a proto which wraps the messages we need and print that a single time (this would also obviate the need for changing the messageprinter).
Ok the things you mentioned should be addressed now. Formatting is almost definitely not correct, can you advise of an automated way to share whatever settings you have as doing this manually is soul destroying. |
JSON Output