square / wire

gRPC and protocol buffers for Android, Kotlin, Swift and Java.
https://square.github.io/wire/
Apache License 2.0
4.23k stars 571 forks source link

FieldOptions.wire_name to dodge name collisions on options #3042

Open swankjesse opened 1 month ago

swankjesse commented 1 month ago

We’ve got a problem where Wire generates broken code when the same option name is used for different targets in the same package.

extend google.protobuf.MethodOptions {
  optional float objective = 26101;
}

extend google.protobuf.ServiceOptions {
  optional float objective = 26101;
}

This generates two annotations that potentially collide.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ObjectiveOption {
  float value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ObjectiveOption {
  float value();
}

I really like the name ObjectiveOption here and am reluctant to qualify the name with its target ObjectiveMethodOption because this collision is just so rare. Instead I’d like to introduce a mechanism where developers who introduce such collisions in the .proto can choose disambiguating names.

We’ll create a new extension:

extend google.protobuf.FieldOptions {
  /**
   * Sets the name used for this field in generated code.
   *
   * This may only be applied to extension fields, and only impacts the generated names for option
   * annotations.
   *
   * It is an error to apply this option to regular message fields and oneof fields.
   *
   * This doesn't impact the name used an any encoding or decoding, such as JSON encoding.
   */
  optional string wire_name = 9999; // TODO
}

And users would use it like so:

extend google.protobuf.MethodOptions {
  optional float objective = 26101 [(wire.wire_name) = "rpc_objective"];
}

extend google.protobuf.ServiceOptions {
  optional float objective = 26101 [(wire.wire_name) = "service_objective"];
}