| # 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) |
| * Generate the `flag` attribute using the `GENERATED_JAVA_IS_FLAG` directive (optional) |
| * 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_ |
| // GENERATED_JAVA_IS_FLAG: true |
| enum SomeEnum { |
| BAR_A = 1 << 0, |
| BAR_B = 1 << 1, |
| 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(flag = true, value = { |
| FooBar.A, FooBar.B, FooBar.C |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface FooBar { |
| int A = 1 << 0; |
| int B = 1 << 1; |
| int C = 1 << 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) |