
RefreshType in task_manager_observer.h is a real example of the enums needing this handling. Unless we generate it with the flag attribute, we can't concatenate the constants with `|`, seeing the error like this: ``` ../../chrome/browser/task_manager/internal/android/java/src/org/chromium/chrome/browser/task_manager/TaskManagerActivity.java:32: Error: Flag not allowed here [WrongConstant] observer, REFRESH_TIME_MS, RefreshType.MEMORY_FOOTPRINT | RefreshType.CPU); ``` Bug: 353596679 Change-Id: I382678b39dd9ff85e619cc1881eb087b463d22bd Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6034170 Auto-Submit: Keigo Oka <oka@chromium.org> Commit-Queue: Andrew Grieve <agrieve@chromium.org> Reviewed-by: Andrew Grieve <agrieve@chromium.org> Cr-Commit-Position: refs/heads/main@{#1384981}
206 lines
6.0 KiB
Markdown
206 lines
6.0 KiB
Markdown
# 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)
|