如何在生成的 Java class 中重命名字段以防止 Java 编译器出现问题

How to rename field in generated Java class to prevent problems with Java compiler

我必须使用已发布的(第 3 方)协议缓冲区 (.proto) 文件,其中包含名称来自 Java reserved keywords list 的字段。所以我无法更改此文件的名称。作为编译(通过 protoc)协议缓冲区到 Java 代码后的结果,我得到 class 可以不能用 Java 编译。

我必须解析的消息是在 C[=40 的帮助下使用原始字段名称生成的(在 Java 中无效) =],例如。

据我了解,在使用此 message/class 期间,我无法在不遇到麻烦的情况下更改生成的代码。

如何在生成的 [=51 中更改生成字段的名称(在 运行 protoc 期间使用一些映射规则或使用注释) =]class安全吗?

样本。

原型文件:

package sample.wrongname.protobuf;

enum SomeType {
    cool_name = 1;
    another_cool_name = 2;
    native = 3;
}

生成Javaclass:

public final class Sample {
  private Sample() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
  }
  /**
   * Protobuf enum {@code sample.wrongname.protobuf.SomeType}
   */
  public enum SomeType
      implements com.google.protobuf.ProtocolMessageEnum {
    /**
     * <code>cool_name = 1;</code>
     */
    cool_name(0, 1),
    /**
     * <code>another_cool_name = 2;</code>
     */
    another_cool_name(1, 2),
    /**
     * <code>native = 3;</code>
     */
    native(2, 3),
    ;

    /**
     * <code>cool_name = 1;</code>
     */
    public static final int cool_name_VALUE = 1;
    /**
     * <code>another_cool_name = 2;</code>
     */
    public static final int another_cool_name_VALUE = 2;
    /**
     * <code>native = 3;</code>
     */
    public static final int native_VALUE = 3;


    public final int getNumber() { return value; }

    public static SomeType valueOf(int value) {
      switch (value) {
        case 1: return cool_name;
        case 2: return another_cool_name;
        case 3: return native;
        default: return null;
      }
    }

    public static com.google.protobuf.Internal.EnumLiteMap<SomeType>
        internalGetValueMap() {
      return internalValueMap;
    }
    private static com.google.protobuf.Internal.EnumLiteMap<SomeType>
        internalValueMap =
          new com.google.protobuf.Internal.EnumLiteMap<SomeType>() {
            public SomeType findValueByNumber(int number) {
              return SomeType.valueOf(number);
            }
          };

    public final com.google.protobuf.Descriptors.EnumValueDescriptor
        getValueDescriptor() {
      return getDescriptor().getValues().get(index);
    }
    public final com.google.protobuf.Descriptors.EnumDescriptor
        getDescriptorForType() {
      return getDescriptor();
    }
    public static final com.google.protobuf.Descriptors.EnumDescriptor
        getDescriptor() {
      return Sample.getDescriptor().getEnumTypes().get(0);
    }

    private static final SomeType[] VALUES = values();

    public static SomeType valueOf(
        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
      if (desc.getType() != getDescriptor()) {
        throw new java.lang.IllegalArgumentException(
          "EnumValueDescriptor is not for this type.");
      }
      return VALUES[desc.getIndex()];
    }

    private final int index;
    private final int value;

    private SomeType(int index, int value) {
      this.index = index;
      this.value = value;
    }

    // @@protoc_insertion_point(enum_scope:sample.wrongname.protobuf.SomeType)
  }


  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    java.lang.String[] descriptorData = {
      "\n4sample.proto21sample.wrongname.protobu" +
      "f*<\n0SomeType2\r\n\tcool_name0[=14=]125\n1another_" +
      "cool_name0[=14=]22\n\n[=14=]6native0[=14=]3"
    };
    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
          public com.google.protobuf.ExtensionRegistry assignDescriptors(
              com.google.protobuf.Descriptors.FileDescriptor root) {
            descriptor = root;
            return null;
          }
        };
    com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
        }, assigner);
  }

  // @@protoc_insertion_point(outer_class_scope)
}

这是一个小例子。

使用 Java 保留关键字的 Protobuffer。

package wrong.name;
option java_outer_classname = "WrongProtos";
message Foo {
    required SomeType id = 1;
}
enum SomeType {
    cool_name = 1;
    another_cool_name = 2;
    native = 3;
}

使用相同结构但名称不同的 Protobuffer。

package right.name;
option java_outer_classname = "RightProtos";
message Foo {
    required SomeType id = 1;
}
enum SomeType {
    cool_name = 1;
    another_cool_name = 2;
    different = 3;
}

编译原型缓冲区

protoc --java_out=src/ *.proto

WrongProtos.java

中重命名
native(2, 3)  -->  nativeFoo(2, 3)
case 3: return native;  -->  case 3: return nativeFoo;

显示可以使用两个 protobuff 定义读取结构的小片段。

WrongProtos.Foo.Builder outFoo = WrongProtos.Foo.newBuilder();
outFoo.setId(WrongProtos.SomeType.nativeFoo);
try (FileOutputStream output = new FileOutputStream("/tmp/proto.bin")) {
    outFoo.build().writeTo(output);
}
System.out.printf("outFoo number: %d  name: %s%n",
        outFoo.getId().getNumber(), outFoo.getId());

RightProtos.Foo inFoo = RightProtos.Foo.parseFrom(
        new FileInputStream("/tmp/proto.bin"));
System.out.printf("inFoo number: %d  name: %s%n",
        inFoo.getId().getNumber(), inFoo.getId());
}

输出

outFoo number: 3  name: nativeFoo
inFoo number: 3  name: different

输出显示,只有在您访问字段名称本身时才会有所不同。在二进制数据中,不存储字段名称。

edit 另一种方法是将字段重命名为大写 native --> NATIVE.