From af6ce227319052bc092e7c329c7f1258202fb365 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Sun, 10 Jan 2021 14:28:54 -0800 Subject: [PATCH 1/9] Remove javanano from .gitignore. Ignore java/lite/target --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4e745ebea5c0e..480319023c781 100644 --- a/.gitignore +++ b/.gitignore @@ -84,7 +84,7 @@ src/**/*.trs # JavaBuild output. java/core/target java/util/target -javanano/target +java/lite/target java/.idea java/**/*.iml From 2529c603e51ef53a0fa70031dd9dbe584ae04ee5 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Sun, 10 Jan 2021 14:32:53 -0800 Subject: [PATCH 2/9] Resolve more java field accessor name conflicts. Previously, some proto field names would cause the java code generator to generate accessor names that conflict with method names from the message super classes/interfaces. A list of field names that cause such conflicts previously existed, but the list did not contain every field name that would cause a conflict. Additionally, only snake_case field names would be detected. If the field name was in camelCase, the conflict would not be detected. This change adds the complete set of field names that will cause assessor name conflicts, and detects conflicts in both snake_case and camelCase field names. Fixes #8142 --- .../DescriptorMessageInfoFactory.java | 30 +++++++++-- .../protobuf/test_bad_identifiers.proto | 52 +++++++++++++++---- .../protobuf/compiler/java/java_helpers.cc | 19 +++++-- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index 7975136596a85..41856415411e9 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -61,8 +61,31 @@ final class DescriptorMessageInfoFactory implements MessageInfoFactory { private static final String GET_DEFAULT_INSTANCE_METHOD_NAME = "getDefaultInstance"; private static final DescriptorMessageInfoFactory instance = new DescriptorMessageInfoFactory(); + + /** + * Names that should be avoided as field names (in lowerCamelCase format). + * Using them will cause the compiler to generate accessors whose names are + * colliding with methods defined in base classes. + * + * Keep this list in sync with kForbiddenWordList in + * src/google/protobuf/compiler/java/java_helpers.cc + */ private static final Set specialFieldNames = - new HashSet<>(Arrays.asList("cached_size", "serialized_size", "class")); + new HashSet<>(Arrays.asList( + // java.lang.Object: + "class", + // com.google.protobuf.MessageLiteOrBuilder: + "defaultInstanceForType", + // com.google.protobuf.MessageLite: + "parserForType", + "serializedSize", + // com.google.protobuf.MessageOrBuilder: + "allFields", + "descriptorForType", + "initializationErrorString", + "unknownFields", + // obsolete. kept for backwards compatibility of generated code + "cachedSize")); // Disallow construction - it's a singleton. private DescriptorMessageInfoFactory() {} @@ -593,8 +616,9 @@ static String getFieldName(FieldDescriptor fd) { String name = (fd.getType() == FieldDescriptor.Type.GROUP) ? fd.getMessageType().getName() : fd.getName(); - String suffix = specialFieldNames.contains(name) ? "__" : "_"; - return snakeCaseToCamelCase(name) + suffix; + String nameInCamelCase = snakeCaseToCamelCase(name); + String suffix = specialFieldNames.contains(nameInCamelCase) ? "__" : "_"; + return nameInCamelCase + suffix; } private static String getCachedSizeFieldName(FieldDescriptor fd) { diff --git a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto index 8bf16914313e5..d3d24c1b17bba 100644 --- a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto +++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto @@ -43,10 +43,42 @@ option java_generic_services = true; // auto-added option java_package = "com.google.protobuf"; option java_outer_classname = "TestBadIdentifiersProto"; -message TestMessage { - optional string cached_size = 1; - optional string serialized_size = 2; - optional string class = 3; +// Message with field names using underscores that conflict with accessors in the base message class in java. +// See kForbiddenWordList in src/google/protobuf/compiler/java/java_helpers.cc +message ForbiddenWordsUnderscoreMessage { + // java.lang.Object + optional bool class = 1; + // com.google.protobuf.MessageLiteOrBuilder + optional bool default_instance_for_type = 2; + // com.google.protobuf.MessageLite + optional bool parser_for_type = 3; + optional bool serialized_size = 4; + // com.google.protobuf.MessageOrBuilder + optional bool all_fields = 5; + optional bool descriptor_for_type = 6; + optional bool initialization_error_string = 7; + optional bool unknown_fields = 8; + // obsolete. kept for backwards compatibility of generated code + optional bool cached_size = 9; +} + +// Message with field names in camel case that conflict with accessors in the base message class in java. +// See kForbiddenWordList in src/google/protobuf/compiler/java/java_helpers.cc +message ForbiddenWordsCamelMessage { + // java.lang.Object + optional bool class = 1; + // com.google.protobuf.MessageLiteOrBuilder + optional bool defaultInstanceForType = 2; + // com.google.protobuf.MessageLite + optional bool serializedSize = 3; + optional bool parserForType = 4; + // com.google.protobuf.MessageOrBuilder: + optional bool initializationErrorString = 5; + optional bool descriptorForType = 6; + optional bool allFields = 7; + optional bool unknownFields = 8; + // obsolete. kept for backwards compatibility of generated code + optional bool cachedSize = 9; } message Descriptor { @@ -84,7 +116,7 @@ message Deprecated { optional int32 field1 = 1 [deprecated = true]; optional TestEnum field2 = 2 [deprecated = true]; - optional TestMessage field3 = 3 [deprecated = true]; + optional ForbiddenWordsUnderscoreMessage field3 = 3 [deprecated = true]; } message Override { @@ -117,7 +149,7 @@ message Double { } service TestConflictingMethodNames { - rpc Override(TestMessage) returns (TestMessage); + rpc Override(ForbiddenWordsUnderscoreMessage) returns (ForbiddenWordsUnderscoreMessage); } message TestConflictingFieldNames { @@ -125,24 +157,24 @@ message TestConflictingFieldNames { UNKNOWN = 0; FOO = 1; } - message TestMessage {} + message ForbiddenWordsUnderscoreMessage {} repeated int32 int32_field = 1; repeated TestEnum enum_field = 2; repeated string string_field = 3; repeated bytes bytes_field = 4; - repeated TestMessage message_field = 5; + repeated ForbiddenWordsUnderscoreMessage message_field = 5; optional int32 int32_field_count = 11; optional TestEnum enum_field_count = 12; optional string string_field_count = 13; optional bytes bytes_field_count = 14; - optional TestMessage message_field_count = 15; + optional ForbiddenWordsUnderscoreMessage message_field_count = 15; repeated int32 Int32Field = 21; // NO_PROTO3 repeated TestEnum EnumField = 22; // NO_PROTO3 repeated string StringField = 23; // NO_PROTO3 repeated bytes BytesField = 24; // NO_PROTO3 - repeated TestMessage MessageField = 25; // NO_PROTO3 + repeated ForbiddenWordsUnderscoreMessage MessageField = 25; // NO_PROTO3 // This field conflicts with "int32_field" as they both generate // the method getInt32FieldList(). diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index e9bc6f76738d9..4e511f27ed82a 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -64,15 +64,24 @@ namespace { const char* kDefaultPackage = ""; -// Names that should be avoided as field names. +// Names that should be avoided as field names (in lowerCamelCase format). // Using them will cause the compiler to generate accessors whose names are // colliding with methods defined in base classes. const char* kForbiddenWordList[] = { - // message base class: - "cached_size", - "serialized_size", // java.lang.Object: "class", + // com.google.protobuf.MessageLiteOrBuilder: + "defaultInstanceForType", + // com.google.protobuf.MessageLite: + "parserForType", + "serializedSize", + // com.google.protobuf.MessageOrBuilder: + "allFields", + "descriptorForType", + "initializationErrorString", + "unknownFields", + // obsolete. kept for backwards compatibility of generated code + "cachedSize", }; const std::unordered_set* kReservedNames = @@ -102,7 +111,7 @@ const std::unordered_set* kKotlinForbiddenNames = bool IsForbidden(const std::string& field_name) { for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) { - if (field_name == kForbiddenWordList[i]) { + if (UnderscoresToCamelCase(field_name, false) == kForbiddenWordList[i]) { return true; } } From 7da00a59ba2e90d728139a86412fca3cb8deb9cb Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Thu, 18 Feb 2021 17:07:24 -0800 Subject: [PATCH 3/9] Prevent java accessor name conflicts for fields with leading underscores. Previously, some protobuf field names beginning with leading underscores (e.g. _class) would cause uncompilable java code to be generated due to assessor name conflicts. Now, non-conflicting java accessor method names are created for those fields --- .../DescriptorMessageInfoFactory.java | 35 ++++++++++--------- .../protobuf/test_bad_identifiers.proto | 19 ++++++++++ .../protobuf/compiler/java/java_helpers.cc | 22 ++++++------ 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index 41856415411e9..65a4de9886cd4 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -63,7 +63,7 @@ final class DescriptorMessageInfoFactory implements MessageInfoFactory { private static final DescriptorMessageInfoFactory instance = new DescriptorMessageInfoFactory(); /** - * Names that should be avoided as field names (in lowerCamelCase format). + * Names that should be avoided (in UpperCamelCase format). * Using them will cause the compiler to generate accessors whose names are * colliding with methods defined in base classes. * @@ -73,19 +73,19 @@ final class DescriptorMessageInfoFactory implements MessageInfoFactory { private static final Set specialFieldNames = new HashSet<>(Arrays.asList( // java.lang.Object: - "class", + "Class", // com.google.protobuf.MessageLiteOrBuilder: - "defaultInstanceForType", + "DefaultInstanceForType", // com.google.protobuf.MessageLite: - "parserForType", - "serializedSize", + "ParserForType", + "SerializedSize", // com.google.protobuf.MessageOrBuilder: - "allFields", - "descriptorForType", - "initializationErrorString", - "unknownFields", + "AllFields", + "DescriptorForType", + "InitializationErrorString", + "UnknownFields", // obsolete. kept for backwards compatibility of generated code - "cachedSize")); + "CachedSize")); // Disallow construction - it's a singleton. private DescriptorMessageInfoFactory() {} @@ -616,22 +616,25 @@ static String getFieldName(FieldDescriptor fd) { String name = (fd.getType() == FieldDescriptor.Type.GROUP) ? fd.getMessageType().getName() : fd.getName(); - String nameInCamelCase = snakeCaseToCamelCase(name); - String suffix = specialFieldNames.contains(nameInCamelCase) ? "__" : "_"; - return nameInCamelCase + suffix; + String suffix = specialFieldNames.contains(snakeCaseToCamelCase(name, true)) ? "__" : "_"; + return snakeCaseToCamelCase(name, false) + suffix; } private static String getCachedSizeFieldName(FieldDescriptor fd) { return snakeCaseToCamelCase(fd.getName()) + "MemoizedSerializedSize"; } + private static String snakeCaseToCamelCase(String snakeCase) { + return snakeCaseToCamelCase(snakeCase, false); + } + /** * This method must match exactly with the corresponding function in protocol compiler. See: - * https://github.com/google/protobuf/blob/v3.0.0/src/google/protobuf/compiler/java/java_helpers.cc#L153 + * https://github.com/protocolbuffers/protobuf/blob/v3.15.0/src/google/protobuf/compiler/java/java_helpers.cc#L158 */ - private static String snakeCaseToCamelCase(String snakeCase) { + private static String snakeCaseToCamelCase(String snakeCase, boolean capFirst) { StringBuilder sb = new StringBuilder(snakeCase.length() + 1); - boolean capNext = false; + boolean capNext = capFirst; for (int ctr = 0; ctr < snakeCase.length(); ctr++) { char next = snakeCase.charAt(ctr); if (next == '_') { diff --git a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto index d3d24c1b17bba..0f481f563932c 100644 --- a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto +++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto @@ -62,6 +62,25 @@ message ForbiddenWordsUnderscoreMessage { optional bool cached_size = 9; } +// Message with field names using leading underscores that conflict with accessors in the base message class in java. +// See kForbiddenWordList in src/google/protobuf/compiler/java/java_helpers.cc +message ForbiddenWordsLeadingUnderscoreMessage { + // java.lang.Object + optional bool _class = 1; + // com.google.protobuf.MessageLiteOrBuilder + optional bool _default_instance_for_type = 2; + // com.google.protobuf.MessageLite + optional bool _parser_for_type = 3; + optional bool _serialized_size = 4; + // com.google.protobuf.MessageOrBuilder + optional bool _all_fields = 5; + optional bool _descriptor_for_type = 6; + optional bool _initialization_error_string = 7; + optional bool _unknown_fields = 8; + // obsolete. kept for backwards compatibility of generated code + optional bool _cached_size = 9; +} + // Message with field names in camel case that conflict with accessors in the base message class in java. // See kForbiddenWordList in src/google/protobuf/compiler/java/java_helpers.cc message ForbiddenWordsCamelMessage { diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index 4e511f27ed82a..5e036fdb10086 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -64,24 +64,24 @@ namespace { const char* kDefaultPackage = ""; -// Names that should be avoided as field names (in lowerCamelCase format). +// Names that should be avoided (in UpperCamelCase format). // Using them will cause the compiler to generate accessors whose names are // colliding with methods defined in base classes. const char* kForbiddenWordList[] = { // java.lang.Object: - "class", + "Class", // com.google.protobuf.MessageLiteOrBuilder: - "defaultInstanceForType", + "DefaultInstanceForType", // com.google.protobuf.MessageLite: - "parserForType", - "serializedSize", + "ParserForType", + "SerializedSize", // com.google.protobuf.MessageOrBuilder: - "allFields", - "descriptorForType", - "initializationErrorString", - "unknownFields", + "AllFields", + "DescriptorForType", + "InitializationErrorString", + "UnknownFields", // obsolete. kept for backwards compatibility of generated code - "cachedSize", + "CachedSize", }; const std::unordered_set* kReservedNames = @@ -111,7 +111,7 @@ const std::unordered_set* kKotlinForbiddenNames = bool IsForbidden(const std::string& field_name) { for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) { - if (UnderscoresToCamelCase(field_name, false) == kForbiddenWordList[i]) { + if (UnderscoresToCamelCase(field_name, true) == kForbiddenWordList[i]) { return true; } } From 4038de846a8f9bc123f5e7823ca2b8d1432a076d Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Sun, 24 Oct 2021 11:04:45 -0700 Subject: [PATCH 4/9] Improve comments/documentation for conversion from snake case to camel case Rename snakeCaseToCamelCase to snakeCaseToLowerCamelCase Add snakeCaseToUpperCamelCase Add clarifying in-line comments for field name generation Remove explicit version numbers from references. --- .../DescriptorMessageInfoFactory.java | 85 +++++++++++++++++-- .../protobuf/compiler/java/java_helpers.cc | 2 + 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index 65a4de9886cd4..6cb3b571c64dd 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -64,7 +64,7 @@ final class DescriptorMessageInfoFactory implements MessageInfoFactory { /** * Names that should be avoided (in UpperCamelCase format). - * Using them will cause the compiler to generate accessors whose names are + * Using them causes the compiler to generate accessors whose names are * colliding with methods defined in base classes. * * Keep this list in sync with kForbiddenWordList in @@ -616,21 +616,88 @@ static String getFieldName(FieldDescriptor fd) { String name = (fd.getType() == FieldDescriptor.Type.GROUP) ? fd.getMessageType().getName() : fd.getName(); - String suffix = specialFieldNames.contains(snakeCaseToCamelCase(name, true)) ? "__" : "_"; - return snakeCaseToCamelCase(name, false) + suffix; + + // convert to UpperCamelCase for comparison to the specialFieldNames + // (which are in UpperCamelCase) + String upperCamelCaseName = snakeCaseToUpperCamelCase(name); + + String suffix = specialFieldNames.contains(upperCamelCaseName) + // For field names that match the specialFieldNames, + // append "__" to prevent field accessor method names from + // clashing with other methods. + ? "__" + // For other field names, append "_" to prevent field names + // from clashing with java keywords. + : "_"; + return snakeCaseToLowerCamelCase(name) + suffix; } private static String getCachedSizeFieldName(FieldDescriptor fd) { - return snakeCaseToCamelCase(fd.getName()) + "MemoizedSerializedSize"; + return snakeCaseToLowerCamelCase(fd.getName()) + "MemoizedSerializedSize"; } - private static String snakeCaseToCamelCase(String snakeCase) { + /** + * Converts a snake case string into lower camel case. + * + *

+ * Some examples: + *

+   *     snakeCaseToLowerCamelCase("foo_bar") => "fooBar"
+   *     snakeCaseToLowerCamelCase("foo") => "foo"
+   * 
+ *

+ * + * @param snakeCase the string in snake case to convert + * @return the string converted to camel case, with a lowercase first character + */ + private static String snakeCaseToLowerCamelCase(String snakeCase) { return snakeCaseToCamelCase(snakeCase, false); } /** - * This method must match exactly with the corresponding function in protocol compiler. See: - * https://github.com/protocolbuffers/protobuf/blob/v3.15.0/src/google/protobuf/compiler/java/java_helpers.cc#L158 + * Converts a snake case string into upper camel case. + * + *

+ * Some examples: + *

+   *     snakeCaseToUpperCamelCase("foo_bar") => "FooBar"
+   *     snakeCaseToUpperCamelCase("foo") => "Foo"
+   * 
+ *

+ * + * @param snakeCase the string in snake case to convert + * @return the string converted to camel case, with an uppercase first character + */ + private static String snakeCaseToUpperCamelCase(String snakeCase) { + return snakeCaseToCamelCase(snakeCase, true); + } + + /** + * Converts a snake case string into camel case. + * + *

For better readability, prefer calling either + * {@link #snakeCaseToLowerCamelCase(String)} or {@link #snakeCaseToUpperCamelCase(String)}.

+ * + *

Some examples: + *

+   *     snakeCaseToCamelCase("foo_bar", false) => "fooBar"
+   *     snakeCaseToCamelCase("foo_bar", true) => "FooBar"
+   *     snakeCaseToCamelCase("foo", false) => "foo"
+   *     snakeCaseToCamelCase("foo", true) => "Foo"
+   *     snakeCaseToCamelCase("Foo", false) => "foo"
+   *     snakeCaseToCamelCase("fooBar", false) => "fooBar"
+   * 

+ * + *

This implementation of this method must exactly match the corresponding + * function in the protocol compiler. Specifically, the + * {@code UnderscoresToCamelCase} function in + * {@code src/google/protobuf/compiler/java/java_helpers.cc}.

+ * + * @param snakeCase the string in snake case to convert + * @param capFirst true if the first letter of the returned string should be uppercase. + * false if the first letter of the returned string should be lowercase. + * @return the string converted to camel case, with an uppercase or lowercase first + * character depending on if {@code capFirst} is true of false, respectively */ private static String snakeCaseToCamelCase(String snakeCase, boolean capFirst) { StringBuilder sb = new StringBuilder(snakeCase.length() + 1); @@ -680,7 +747,7 @@ private static Class getTypeForRepeatedMessageField(Class messageType, Fie /** Constructs the name of the get method for the given field in the proto. */ private static String getterForField(String snakeCase) { - String camelCase = snakeCaseToCamelCase(snakeCase); + String camelCase = snakeCaseToLowerCamelCase(snakeCase); StringBuilder builder = new StringBuilder("get"); // Capitalize the first character in the field name. builder.append(Character.toUpperCase(camelCase.charAt(0))); @@ -706,7 +773,7 @@ OneofInfo getOneof(Class messageType, OneofDescriptor desc) { } private static OneofInfo newInfo(Class messageType, OneofDescriptor desc) { - String camelCase = snakeCaseToCamelCase(desc.getName()); + String camelCase = snakeCaseToLowerCamelCase(desc.getName()); String valueFieldName = camelCase + "_"; String caseFieldName = camelCase + "Case_"; diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index 5e036fdb10086..170519cc841c3 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -67,6 +67,8 @@ const char* kDefaultPackage = ""; // Names that should be avoided (in UpperCamelCase format). // Using them will cause the compiler to generate accessors whose names are // colliding with methods defined in base classes. +// Keep this list in sync with specialFieldNames in +// java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java const char* kForbiddenWordList[] = { // java.lang.Object: "Class", From 9f88f0c2d832ef59c8e37b26b51d8028f6cfeb52 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Fri, 5 Nov 2021 15:29:16 -0700 Subject: [PATCH 5/9] Fix indents and typo --- .../com/google/protobuf/DescriptorMessageInfoFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index 6cb3b571c64dd..e42058877591d 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -651,7 +651,7 @@ private static String getCachedSizeFieldName(FieldDescriptor fd) { * @return the string converted to camel case, with a lowercase first character */ private static String snakeCaseToLowerCamelCase(String snakeCase) { - return snakeCaseToCamelCase(snakeCase, false); + return snakeCaseToCamelCase(snakeCase, false); } /** @@ -669,7 +669,7 @@ private static String snakeCaseToLowerCamelCase(String snakeCase) { * @return the string converted to camel case, with an uppercase first character */ private static String snakeCaseToUpperCamelCase(String snakeCase) { - return snakeCaseToCamelCase(snakeCase, true); + return snakeCaseToCamelCase(snakeCase, true); } /** @@ -697,7 +697,7 @@ private static String snakeCaseToUpperCamelCase(String snakeCase) { * @param capFirst true if the first letter of the returned string should be uppercase. * false if the first letter of the returned string should be lowercase. * @return the string converted to camel case, with an uppercase or lowercase first - * character depending on if {@code capFirst} is true of false, respectively + * character depending on if {@code capFirst} is true or false, respectively */ private static String snakeCaseToCamelCase(String snakeCase, boolean capFirst) { StringBuilder sb = new StringBuilder(snakeCase.length() + 1); From 8663cffe3c754ed23ffd065bd2ceb52613097120 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Fri, 5 Nov 2021 15:34:25 -0700 Subject: [PATCH 6/9] Unnest
 tag

---
 .../protobuf/DescriptorMessageInfoFactory.java       | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
index e42058877591d..d10709c6f5e10 100644
--- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
+++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
@@ -639,13 +639,11 @@ private static String getCachedSizeFieldName(FieldDescriptor fd) {
   /**
    * Converts a snake case string into lower camel case.
    *
-   * 

- * Some examples: + *

Some examples:

*
    *     snakeCaseToLowerCamelCase("foo_bar") => "fooBar"
    *     snakeCaseToLowerCamelCase("foo") => "foo"
    * 
- *

* * @param snakeCase the string in snake case to convert * @return the string converted to camel case, with a lowercase first character @@ -657,13 +655,11 @@ private static String snakeCaseToLowerCamelCase(String snakeCase) { /** * Converts a snake case string into upper camel case. * - *

- * Some examples: + *

Some examples:

*
    *     snakeCaseToUpperCamelCase("foo_bar") => "FooBar"
    *     snakeCaseToUpperCamelCase("foo") => "Foo"
    * 
- *

* * @param snakeCase the string in snake case to convert * @return the string converted to camel case, with an uppercase first character @@ -678,7 +674,7 @@ private static String snakeCaseToUpperCamelCase(String snakeCase) { *

For better readability, prefer calling either * {@link #snakeCaseToLowerCamelCase(String)} or {@link #snakeCaseToUpperCamelCase(String)}.

* - *

Some examples: + *

Some examples:

*
    *     snakeCaseToCamelCase("foo_bar", false) => "fooBar"
    *     snakeCaseToCamelCase("foo_bar", true) => "FooBar"
@@ -686,7 +682,7 @@ private static String snakeCaseToUpperCamelCase(String snakeCase) {
    *     snakeCaseToCamelCase("foo", true) => "Foo"
    *     snakeCaseToCamelCase("Foo", false) => "foo"
    *     snakeCaseToCamelCase("fooBar", false) => "fooBar"
-   * 

+ *
* *

This implementation of this method must exactly match the corresponding * function in the protocol compiler. Specifically, the From bbd504bf945a3e728693d7007110e6148aed60f5 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Mon, 8 Nov 2021 09:19:46 -0800 Subject: [PATCH 7/9] improve grammar in comments are colliding -> collide --- .../com/google/protobuf/DescriptorMessageInfoFactory.java | 4 ++-- src/google/protobuf/compiler/java/java_helpers.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index d10709c6f5e10..da25aeda5cd6f 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -64,8 +64,8 @@ final class DescriptorMessageInfoFactory implements MessageInfoFactory { /** * Names that should be avoided (in UpperCamelCase format). - * Using them causes the compiler to generate accessors whose names are - * colliding with methods defined in base classes. + * Using them causes the compiler to generate accessors whose names + * collide with methods defined in base classes. * * Keep this list in sync with kForbiddenWordList in * src/google/protobuf/compiler/java/java_helpers.cc diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index 828b3e7e051ae..800e3e0d41ef5 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -67,8 +67,8 @@ namespace { const char* kDefaultPackage = ""; // Names that should be avoided (in UpperCamelCase format). -// Using them will cause the compiler to generate accessors whose names are -// colliding with methods defined in base classes. +// Using them will cause the compiler to generate accessors whose names +// collide with methods defined in base classes. // Keep this list in sync with specialFieldNames in // java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java const char* kForbiddenWordList[] = { From ce16adecbf3e9e8f83552fafe705ab49d6ae743e Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Mon, 8 Nov 2021 09:54:03 -0800 Subject: [PATCH 8/9] Remove ternary operator and improve comments --- .../DescriptorMessageInfoFactory.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index da25aeda5cd6f..34fccde2cfda2 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -621,14 +621,27 @@ static String getFieldName(FieldDescriptor fd) { // (which are in UpperCamelCase) String upperCamelCaseName = snakeCaseToUpperCamelCase(name); - String suffix = specialFieldNames.contains(upperCamelCaseName) - // For field names that match the specialFieldNames, - // append "__" to prevent field accessor method names from - // clashing with other methods. - ? "__" - // For other field names, append "_" to prevent field names - // from clashing with java keywords. - : "_"; + // Append underscores to match the behavior of the protoc java compiler + final String suffix; + if (specialFieldNames.contains(upperCamelCaseName)) { + // For proto field names that match the specialFieldNames, + // the protoc java compiler appends "__" to the java field name + // to prevent the field's accessor method names from clashing with other methods. + // For example: + // proto field name = "class" + // java field name = "class__" + // accessor method name = "getClass_()" (so that it does not clash with Object.getClass()) + suffix = "__"; + } else { + // For other proto field names, + // the protoc java compiler appends "_" to the java field name + // to prevent field names from clashing with java keywords. + // For example: + // proto field name = "int" + // java field name = "int_" (so that it does not clash with int keyword) + // accessor method name = "getInt_()" + suffix = "_"; + } return snakeCaseToLowerCamelCase(name) + suffix; } From 7427439dd9635d884dc925e4c46cddd72c1eb193 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Mon, 8 Nov 2021 13:59:02 -0800 Subject: [PATCH 9/9] Fix typo in comment --- .../java/com/google/protobuf/DescriptorMessageInfoFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java index 34fccde2cfda2..adee5569034d4 100644 --- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java +++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java @@ -639,7 +639,7 @@ static String getFieldName(FieldDescriptor fd) { // For example: // proto field name = "int" // java field name = "int_" (so that it does not clash with int keyword) - // accessor method name = "getInt_()" + // accessor method name = "getInt()" suffix = "_"; } return snakeCaseToLowerCamelCase(name) + suffix;