| # Accessing C++ Enums In Java | |
| [TOC] | |
| ## Introduction | |
| Accessing C++ enums in Java is implemented via a Python script which analyzes | |
| the C++ enum and spits out the corresponding Java class. The enum needs to be | |
| annotated in a particular way. By default, the generated class name will be the | |
| same as the name of the enum. If all the names of the enum values are prefixed | |
| with the MACRO\_CASED\_ name of the enum those prefixes will be stripped from | |
| the Java version. | |
| ## Features | |
| * Customize the package name of the generated class using the | |
| `GENERATED_JAVA_ENUM_PACKAGE` directive (required) | |
| * Customize the class name using the `GENERATED_JAVA_CLASS_NAME_OVERRIDE` | |
| directive (optional) | |
| * Strip enum entry prefixes to make the generated classes less verbose using | |
| the `GENERATED_JAVA_PREFIX_TO_STRIP` directive (optional) | |
| * Follows best practices by using | |
| [IntDef Instead of Enum](/styleguide/java/java.md#IntDef-Instead-of-Enum) | |
| * Copies comments that directly precede enum entries into the generated Java | |
| class | |
| ## Usage | |
| 1. Add directives to your C++ enum. Only the `GENERATED_JAVA_ENUM_PACKAGE` | |
| directive is required: | |
| ```cpp | |
| // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome | |
| // GENERATED_JAVA_CLASS_NAME_OVERRIDE: FooBar | |
| // GENERATED_JAVA_PREFIX_TO_STRIP: BAR_ | |
| enum SomeEnum { | |
| BAR_A, | |
| BAR_B, | |
| BAR_C = BAR_B, | |
| }; | |
| ``` | |
| 2. Add a new build target and add it to the `srcjar_deps` of an | |
| `android_library` target: | |
| ```gn | |
| if (is_android) { | |
| import("//build/config/android/rules.gni") | |
| } | |
| if (is_android) { | |
| java_cpp_enum("java_enum_srcjar") { | |
| # External code should depend on ":foo_java" instead. | |
| visibility = [ ":*" ] | |
| sources = [ | |
| # Include the .h or .cc file(s) which defines the enum(s). | |
| "base/android/native_foo_header.h", | |
| ] | |
| } | |
| # If there's already an android_library target, you can add | |
| # java_enum_srcjar to that target's srcjar_deps. Otherwise, the best | |
| # practice is to create a new android_library just for this target. | |
| android_library("foo_java") { | |
| srcjar_deps = [ ":java_enum_srcjar" ] | |
| # Important: the generated enum uses the @IntDef annotation provided by | |
| # this dependency. | |
| deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ] | |
| } | |
| } | |
| ``` | |
| 3. The generated file `org/chromium/chrome/FooBar.java` would contain: | |
| ```java | |
| package org.chromium.chrome; | |
| import androidx.annotation.IntDef; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| @IntDef({ | |
| FooBar.A, FooBar.B, FooBar.C | |
| }) | |
| @Retention(RetentionPolicy.SOURCE) | |
| public @interface FooBar { | |
| int A = 0; | |
| int B = 1; | |
| int C = 1; | |
| } | |
| ``` | |
| ## Formatting Notes | |
| * Handling long package names: | |
| ```cpp | |
| // GENERATED_JAVA_ENUM_PACKAGE: ( | |
| // org.chromium.chrome.this.package.is.too.long.to.fit.on.a.single.line) | |
| ``` | |
| * Enum entries | |
| * Single line enums should look like this: | |
| ```cpp | |
| // GENERATED_JAVA_ENUM_PACKAGE: org.foo | |
| enum NotificationActionType { BUTTON, TEXT }; | |
| ``` | |
| * Multi-line enums should have one enum entry per line, like this: | |
| ```cpp | |
| // GENERATED_JAVA_ENUM_PACKAGE: org.foo | |
| enum NotificationActionType { | |
| BUTTON, | |
| TEXT | |
| }; | |
| ``` | |
| * Multi-line enum entries are allowed but should be formatted like this: | |
| ```cpp | |
| // GENERATED_JAVA_ENUM_PACKAGE: org.foo | |
| enum NotificationActionType { | |
| LongKeyNumberOne, | |
| LongKeyNumberTwo, | |
| ... | |
| LongKeyNumberThree = | |
| LongKeyNumberOne | LongKeyNumberTwo | ... | |
| }; | |
| ``` | |
| * Preserving comments | |
| ```cpp | |
| // GENERATED_JAVA_ENUM_PACKAGE: org.chromium | |
| enum CommentEnum { | |
| // This comment will be preserved. | |
| ONE, | |
| TWO, // This comment will NOT be preserved. | |
| THREE | |
| } | |
| ``` | |
| ```java | |
| ... | |
| public @interface CommentEnum { | |
| ... | |
| /** | |
| * This comment will be preserved. | |
| */ | |
| int ONE = 0; | |
| int TWO = 1; | |
| int THREE = 2; | |
| } | |
| ``` | |
| ## Troubleshooting | |
| ### Symbol not found/could not resolve IntDef | |
| You may see an error like this when compiling: | |
| ```shell | |
| $ autoninja -C out/Default base/foo_java | |
| util.build_utils.CalledProcessError: Command failed: ... | |
| org/chromium/chrome/FooBar.java:13: error: symbol not found androidx.annotation.IntDef | |
| Hint: Add "//third_party/androidx:androidx_annotation_annotation_java" to deps of //base/foo_java | |
| import androidx.annotation.IntDef; | |
| ^ | |
| org/chromium/chrome/FooBar.java:18: error: could not resolve IntDef | |
| @IntDef({ | |
| ^ | |
| ``` | |
| The fix is to add | |
| `"//third_party/androidx:androidx_annotation_annotation_java"` to the `deps` of | |
| the `android_library`. Note: **do not** add this to the `java_cpp_enum` target | |
| by mistake, otherwise you'll see a new error: | |
| ```shell | |
| $ autoninja -C out/Default base/foo_java | |
| [0/1] Regenerating ninja files | |
| ERROR at //base/BUILD.gn:194:12: Assignment had no effect. | |
| deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ] | |
| ^-------------------------------------------------------------- | |
| You set the variable "deps" here and it was unused before it went | |
| out of scope. | |
| ... | |
| ``` | |
| ## See also | |
| * [Accessing C++ Switches In Java](android_accessing_cpp_switches_in_java.md) | |
| * [Accessing C++ Features In Java](android_accessing_cpp_features_in_java.md) | |
| ## Code | |
| * [Generator | |
| code](https://cs.chromium.org/chromium/src/build/android/gyp/java_cpp_enum.py?dr=C&sq=package:chromium) | |
| and | |
| [Tests](https://cs.chromium.org/chromium/src/build/android/gyp/java_cpp_enum_tests.py?dr=C&q=java_cpp_enum_tests&sq=package:chromium&l=1) | |
| * [GN | |
| template](https://cs.chromium.org/chromium/src/build/config/android/rules.gni?q=java_cpp_enum.py&sq=package:chromium&dr=C&l=458) |