[jnigen] Some summarizer improvements (https://github.com/dart-lang/jnigen/issues/114)
diff --git a/pkgs/jnigen/example/in_app_java/jnigen.yaml b/pkgs/jnigen/example/in_app_java/jnigen.yaml index 58bd7d9..e344270 100644 --- a/pkgs/jnigen/example/in_app_java/jnigen.yaml +++ b/pkgs/jnigen/example/in_app_java/jnigen.yaml
@@ -12,4 +12,5 @@ source_path: - 'android/app/src/main/java' classes: - - 'com.example.in_app_java.AndroidUtils' + - 'com.example.in_app_java.AndroidUtils' # from source_path + - 'android.os.Build' # from gradle's compile classpath
diff --git a/pkgs/jnigen/example/in_app_java/lib/android_utils.dart b/pkgs/jnigen/example/in_app_java/lib/android_utils.dart index 9dc7ffb..e83f716 100644 --- a/pkgs/jnigen/example/in_app_java/lib/android_utils.dart +++ b/pkgs/jnigen/example/in_app_java/lib/android_utils.dart
@@ -42,3 +42,299 @@ jni.JniObject mainActivity, jni.JniObject text, int duration) => _showToast(mainActivity.reference, text.reference, duration).check(); } + +/// from: android.os.Build +class Build extends jni.JniObject { + Build.fromRef(ffi.Pointer<ffi.Void> ref) : super.fromRef(ref); + + static final _get_BOARD = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__BOARD") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String BOARD + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get BOARD => jni.JniString.fromRef(_get_BOARD().object); + + static final _get_BOOTLOADER = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__BOOTLOADER") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String BOOTLOADER + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get BOOTLOADER => + jni.JniString.fromRef(_get_BOOTLOADER().object); + + static final _get_BRAND = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__BRAND") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String BRAND + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get BRAND => jni.JniString.fromRef(_get_BRAND().object); + + static final _get_CPU_ABI = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__CPU_ABI") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String CPU_ABI + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get CPU_ABI => + jni.JniString.fromRef(_get_CPU_ABI().object); + + static final _get_CPU_ABI2 = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__CPU_ABI2") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String CPU_ABI2 + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get CPU_ABI2 => + jni.JniString.fromRef(_get_CPU_ABI2().object); + + static final _get_DEVICE = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__DEVICE") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String DEVICE + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get DEVICE => + jni.JniString.fromRef(_get_DEVICE().object); + + static final _get_DISPLAY = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__DISPLAY") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String DISPLAY + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get DISPLAY => + jni.JniString.fromRef(_get_DISPLAY().object); + + static final _get_FINGERPRINT = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__FINGERPRINT") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String FINGERPRINT + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get FINGERPRINT => + jni.JniString.fromRef(_get_FINGERPRINT().object); + + static final _get_HARDWARE = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__HARDWARE") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String HARDWARE + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get HARDWARE => + jni.JniString.fromRef(_get_HARDWARE().object); + + static final _get_HOST = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__HOST") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String HOST + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get HOST => jni.JniString.fromRef(_get_HOST().object); + + static final _get_ID = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__ID") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String ID + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get ID => jni.JniString.fromRef(_get_ID().object); + + static final _get_MANUFACTURER = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__MANUFACTURER") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String MANUFACTURER + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get MANUFACTURER => + jni.JniString.fromRef(_get_MANUFACTURER().object); + + static final _get_MODEL = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__MODEL") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String MODEL + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get MODEL => jni.JniString.fromRef(_get_MODEL().object); + + static final _get_ODM_SKU = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__ODM_SKU") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String ODM_SKU + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get ODM_SKU => + jni.JniString.fromRef(_get_ODM_SKU().object); + + static final _get_PRODUCT = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__PRODUCT") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String PRODUCT + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get PRODUCT => + jni.JniString.fromRef(_get_PRODUCT().object); + + static final _get_RADIO = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__RADIO") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String RADIO + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get RADIO => jni.JniString.fromRef(_get_RADIO().object); + + static final _get_SERIAL = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__SERIAL") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String SERIAL + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get SERIAL => + jni.JniString.fromRef(_get_SERIAL().object); + + static final _get_SKU = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__SKU") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String SKU + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get SKU => jni.JniString.fromRef(_get_SKU().object); + + static final _get_SOC_MANUFACTURER = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__SOC_MANUFACTURER") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String SOC_MANUFACTURER + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get SOC_MANUFACTURER => + jni.JniString.fromRef(_get_SOC_MANUFACTURER().object); + + static final _get_SOC_MODEL = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__SOC_MODEL") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String SOC_MODEL + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get SOC_MODEL => + jni.JniString.fromRef(_get_SOC_MODEL().object); + + static final _get_SUPPORTED_32_BIT_ABIS = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__SUPPORTED_32_BIT_ABIS") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String[] SUPPORTED_32_BIT_ABIS + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniObject get SUPPORTED_32_BIT_ABIS => + jni.JniObject.fromRef(_get_SUPPORTED_32_BIT_ABIS().object); + + static final _get_SUPPORTED_64_BIT_ABIS = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__SUPPORTED_64_BIT_ABIS") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String[] SUPPORTED_64_BIT_ABIS + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniObject get SUPPORTED_64_BIT_ABIS => + jni.JniObject.fromRef(_get_SUPPORTED_64_BIT_ABIS().object); + + static final _get_SUPPORTED_ABIS = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "get_Build__SUPPORTED_ABIS") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String[] SUPPORTED_ABIS + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniObject get SUPPORTED_ABIS => + jni.JniObject.fromRef(_get_SUPPORTED_ABIS().object); + + static final _get_TAGS = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__TAGS") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String TAGS + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get TAGS => jni.JniString.fromRef(_get_TAGS().object); + + static final _get_TIME = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__TIME") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final long TIME + static int get TIME => _get_TIME().long; + + static final _get_TYPE = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__TYPE") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String TYPE + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get TYPE => jni.JniString.fromRef(_get_TYPE().object); + + /// from: static public final java.lang.String UNKNOWN + static const UNKNOWN = "unknown"; + + static final _get_USER = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__USER") + .asFunction<jni.JniResult Function()>(); + + /// from: static public final java.lang.String USER + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString get USER => jni.JniString.fromRef(_get_USER().object); + + static final _ctor = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("Build__ctor") + .asFunction<jni.JniResult Function()>(); + + /// from: public void <init>() + Build() : super.fromRef(_ctor().object); + + static final _getSerial = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "Build__getSerial") + .asFunction<jni.JniResult Function()>(); + + /// from: static public java.lang.String getSerial() + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString getSerial() => + jni.JniString.fromRef(_getSerial().object); + + static final _getFingerprintedPartitions = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "Build__getFingerprintedPartitions") + .asFunction<jni.JniResult Function()>(); + + /// from: static public java.util.List getFingerprintedPartitions() + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniObject getFingerprintedPartitions() => + jni.JniObject.fromRef(_getFingerprintedPartitions().object); + + static final _getRadioVersion = + jniLookup<ffi.NativeFunction<jni.JniResult Function()>>( + "Build__getRadioVersion") + .asFunction<jni.JniResult Function()>(); + + /// from: static public java.lang.String getRadioVersion() + /// The returned object must be deleted after use, by calling the `delete` method. + static jni.JniString getRadioVersion() => + jni.JniString.fromRef(_getRadioVersion().object); +}
diff --git a/pkgs/jnigen/example/in_app_java/lib/main.dart b/pkgs/jnigen/example/in_app_java/lib/main.dart index 37e8676..dbb34f9 100644 --- a/pkgs/jnigen/example/in_app_java/lib/main.dart +++ b/pkgs/jnigen/example/in_app_java/lib/main.dart
@@ -11,8 +11,9 @@ JniObject activity = JniObject.fromRef(Jni.getCurrentActivity()); -void showToast(String text) { - AndroidUtils.showToast(activity, text.jniString(), 0); +/// Display device model number as Toast +void showToast() { + AndroidUtils.showToast(activity, Build.MODEL, 0); } void main() { @@ -50,8 +51,8 @@ mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( - child: const Text('Show toast'), - onPressed: () => showToast('😀'), + child: const Text('Show Device Model'), + onPressed: () => showToast(), ), ], ),
diff --git a/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c index 71e05c8..c2e9ced 100644 --- a/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c +++ b/pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
@@ -52,3 +52,439 @@ text, duration); return (JniResult){.result = {.j = 0}, .exception = check_exception()}; } + +// android.os.Build +jclass _c_Build = NULL; + +jmethodID _m_Build__ctor = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__ctor() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_method(_c_Build, &_m_Build__ctor, "<init>", "()V"); + if (_m_Build__ctor == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_Build, _m_Build__ctor); + return (JniResult){.result = {.l = to_global_ref(_result)}, + .exception = check_exception()}; +} + +jmethodID _m_Build__getSerial = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__getSerial() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Build, &_m_Build__getSerial, "getSerial", + "()Ljava/lang/String;"); + if (_m_Build__getSerial == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + jobject _result = + (*jniEnv)->CallStaticObjectMethod(jniEnv, _c_Build, _m_Build__getSerial); + return (JniResult){.result = {.l = to_global_ref(_result)}, + .exception = check_exception()}; +} + +jmethodID _m_Build__getFingerprintedPartitions = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__getFingerprintedPartitions() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Build, &_m_Build__getFingerprintedPartitions, + "getFingerprintedPartitions", "()Ljava/util/List;"); + if (_m_Build__getFingerprintedPartitions == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Build, _m_Build__getFingerprintedPartitions); + return (JniResult){.result = {.l = to_global_ref(_result)}, + .exception = check_exception()}; +} + +jmethodID _m_Build__getRadioVersion = NULL; +FFI_PLUGIN_EXPORT +JniResult Build__getRadioVersion() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_method(_c_Build, &_m_Build__getRadioVersion, "getRadioVersion", + "()Ljava/lang/String;"); + if (_m_Build__getRadioVersion == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->CallStaticObjectMethod( + jniEnv, _c_Build, _m_Build__getRadioVersion); + return (JniResult){.result = {.l = to_global_ref(_result)}, + .exception = check_exception()}; +} + +jfieldID _f_Build__BOARD = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__BOARD() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__BOARD, "BOARD", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__BOARD)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__BOOTLOADER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__BOOTLOADER() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__BOOTLOADER, "BOOTLOADER", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__BOOTLOADER)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__BRAND = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__BRAND() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__BRAND, "BRAND", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__BRAND)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__CPU_ABI = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__CPU_ABI() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__CPU_ABI, "CPU_ABI", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__CPU_ABI)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__CPU_ABI2 = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__CPU_ABI2() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__CPU_ABI2, "CPU_ABI2", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__CPU_ABI2)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__DEVICE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__DEVICE() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__DEVICE, "DEVICE", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__DEVICE)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__DISPLAY = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__DISPLAY() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__DISPLAY, "DISPLAY", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__DISPLAY)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__FINGERPRINT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__FINGERPRINT() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__FINGERPRINT, "FINGERPRINT", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__FINGERPRINT)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__HARDWARE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__HARDWARE() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__HARDWARE, "HARDWARE", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__HARDWARE)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__HOST = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__HOST() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__HOST, "HOST", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__HOST)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__ID = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__ID() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__ID, "ID", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__ID)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__MANUFACTURER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__MANUFACTURER() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__MANUFACTURER, "MANUFACTURER", + "Ljava/lang/String;"); + jobject _result = to_global_ref((*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__MANUFACTURER)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__MODEL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__MODEL() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__MODEL, "MODEL", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__MODEL)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__ODM_SKU = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__ODM_SKU() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__ODM_SKU, "ODM_SKU", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__ODM_SKU)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__PRODUCT = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__PRODUCT() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__PRODUCT, "PRODUCT", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__PRODUCT)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__RADIO = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__RADIO() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__RADIO, "RADIO", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__RADIO)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SERIAL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SERIAL() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SERIAL, "SERIAL", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__SERIAL)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SKU = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SKU() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SKU, "SKU", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__SKU)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SOC_MANUFACTURER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SOC_MANUFACTURER() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SOC_MANUFACTURER, "SOC_MANUFACTURER", + "Ljava/lang/String;"); + jobject _result = to_global_ref((*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__SOC_MANUFACTURER)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SOC_MODEL = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SOC_MODEL() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SOC_MODEL, "SOC_MODEL", + "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__SOC_MODEL)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SUPPORTED_32_BIT_ABIS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SUPPORTED_32_BIT_ABIS() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SUPPORTED_32_BIT_ABIS, + "SUPPORTED_32_BIT_ABIS", "[Ljava/lang/String;"); + jobject _result = to_global_ref((*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__SUPPORTED_32_BIT_ABIS)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SUPPORTED_64_BIT_ABIS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SUPPORTED_64_BIT_ABIS() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SUPPORTED_64_BIT_ABIS, + "SUPPORTED_64_BIT_ABIS", "[Ljava/lang/String;"); + jobject _result = to_global_ref((*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__SUPPORTED_64_BIT_ABIS)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__SUPPORTED_ABIS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__SUPPORTED_ABIS() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__SUPPORTED_ABIS, "SUPPORTED_ABIS", + "[Ljava/lang/String;"); + jobject _result = to_global_ref((*jniEnv)->GetStaticObjectField( + jniEnv, _c_Build, _f_Build__SUPPORTED_ABIS)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__TAGS = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__TAGS() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__TAGS, "TAGS", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__TAGS)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__TIME = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__TIME() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__TIME, "TIME", "J"); + int64_t _result = + (*jniEnv)->GetStaticLongField(jniEnv, _c_Build, _f_Build__TIME); + return (JniResult){.result = {.j = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__TYPE = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__TYPE() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__TYPE, "TYPE", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__TYPE)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +} + +jfieldID _f_Build__USER = NULL; +FFI_PLUGIN_EXPORT +JniResult get_Build__USER() { + load_env(); + load_class_gr(&_c_Build, "android/os/Build"); + if (_c_Build == NULL) + return (JniResult){.result = {.j = 0}, .exception = check_exception()}; + load_static_field(_c_Build, &_f_Build__USER, "USER", "Ljava/lang/String;"); + jobject _result = to_global_ref( + (*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__USER)); + return (JniResult){.result = {.l = _result}, .exception = check_exception()}; +}
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/Main.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/Main.java index bd54b3f..d636f65 100644 --- a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/Main.java +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/Main.java
@@ -4,142 +4,78 @@ package com.github.dart_lang.jnigen.apisummarizer; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +import static com.github.dart_lang.jnigen.apisummarizer.util.ExceptionUtil.wrapCheckedException; + import com.github.dart_lang.jnigen.apisummarizer.disasm.AsmSummarizer; import com.github.dart_lang.jnigen.apisummarizer.doclet.SummarizerDoclet; import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; +import com.github.dart_lang.jnigen.apisummarizer.util.JsonUtil; import com.github.dart_lang.jnigen.apisummarizer.util.Log; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; +import com.github.dart_lang.jnigen.apisummarizer.util.StreamUtil; +import java.io.*; import java.util.*; +import java.util.jar.JarFile; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; import javax.tools.DocumentationTool; import javax.tools.ToolProvider; import jdk.javadoc.doclet.Doclet; import org.apache.commons.cli.*; public class Main { + public enum Backend { + // Produce API descriptions from source files using Doclet API. + DOCLET, + // Produce API descriptions from class files under classpath. + ASM, + // Prefer source but fall back to JARs in classpath if sources not found. + AUTO, + } + + public static class SummarizerOptions { + String sourcePath; + String classPath; + boolean useModules; + Backend backend; + String modulesList; + boolean addDependencies; + String toolArgs; + boolean verbose; + String outputFile; + String[] args; + + SummarizerOptions() {} + + public static SummarizerOptions fromCommandLine(CommandLine cmd) { + var opts = new SummarizerOptions(); + opts.sourcePath = cmd.getOptionValue("sources", "."); + var backendString = cmd.getOptionValue("backend", "auto"); + opts.backend = Backend.valueOf(backendString.toUpperCase()); + opts.classPath = cmd.getOptionValue("classes", null); + opts.useModules = cmd.hasOption("use-modules"); + opts.modulesList = cmd.getOptionValue("module-names", null); + opts.addDependencies = cmd.hasOption("recursive"); + opts.toolArgs = cmd.getOptionValue("doctool-args", null); + opts.verbose = cmd.hasOption("verbose"); + opts.outputFile = cmd.getOptionValue("output-file", null); + opts.args = cmd.getArgs(); + return opts; + } + } + private static final CommandLineParser parser = new DefaultParser(); - static SummarizerOptions config; + static SummarizerOptions options; - public static void writeAll(List<ClassDecl> decls) { - var mapper = new ObjectMapper(); - Log.timed("Writing JSON"); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - try { - mapper.writeValue(System.out, decls); - } catch (IOException e) { - e.printStackTrace(); - } - Log.timed("Finished"); - } - - public static void runDoclet(List<String> qualifiedNames, SummarizerOptions options) { - runDocletWithClass(SummarizerDoclet.class, qualifiedNames, options); - } - - public static void runDocletWithClass( - Class<? extends Doclet> docletClass, List<String> qualifiedNames, SummarizerOptions options) { - List<File> javaFilePaths = - qualifiedNames.stream() - .map(s -> findSourceLocation(s, options.sourcePaths.split(File.pathSeparator))) - .collect(Collectors.toList()); - Log.setVerbose(options.verbose); - - var files = - javaFilePaths.stream() - .flatMap( - path -> recursiveListFiles(path, file -> file.getName().endsWith(".java")).stream()) - .map(File::getPath) - .toArray(String[]::new); - - DocumentationTool javadoc = ToolProvider.getSystemDocumentationTool(); - var fileManager = javadoc.getStandardFileManager(null, null, null); - var fileObjects = fileManager.getJavaFileObjects(files); - - var cli = new ArrayList<String>(); - cli.add((options.useModules ? "--module-" : "--") + "source-path=" + options.sourcePaths); - if (options.classPaths != null) { - cli.add("--class-path=" + options.classPaths); - } - if (options.addDependencies) { - cli.add("--expand-requires=all"); - } - cli.addAll(List.of("-encoding", "utf8")); - - if (options.toolOptions != null) { - cli.addAll(List.of(options.toolOptions.split(" "))); - } - - javadoc.getTask(null, fileManager, System.err::println, docletClass, cli, fileObjects).call(); - } - - public static void main(String[] args) { - CommandLine cl = parseArgs(args); - config = SummarizerOptions.fromCommandLine(cl); - if (config.useAsm) { - System.err.println("use-asm: ignoring all flags other than --classes (-c)"); - try { - writeAll(AsmSummarizer.run(config.classPaths.split(File.pathSeparator), cl.getArgs())); - } catch (IOException e) { - e.printStackTrace(); - } - return; - } - runDoclet(List.of(cl.getArgs()), config); - } - - public static File findSourceLocation(String qualifiedName, String[] paths) { - var s = qualifiedName.replace(".", "/"); - for (var folder : paths) { - var f = new File(folder, s + ".java"); - if (f.exists() && f.isFile()) { - return f; - } - var d = new File(folder, s); - if (d.exists() && d.isDirectory()) { - return d; - } - } - throw new RuntimeException("cannot find class: " + s); - } - - public static List<File> recursiveListFiles(File file, FileFilter filter) { - if (!file.isDirectory()) { - return List.of(file); - } - var files = new ArrayList<File>(); - var queue = new ArrayDeque<File>(); - queue.add(file); - while (!queue.isEmpty()) { - var dir = queue.poll(); - var list = dir.listFiles(entry -> entry.isDirectory() || filter.accept(entry)); - if (list == null) { - throw new IllegalArgumentException(); - } - Arrays.sort(list); - for (var path : list) { - if (path.isDirectory()) { - queue.add(path); - } else { - files.add(path); - } - } - } - return files; - } - - public static CommandLine parseArgs(String[] args) { + public static SummarizerOptions parseArgs(String[] args) { var options = new Options(); Option sources = new Option("s", "sources", true, "paths to search for source files"); Option classes = new Option("c", "classes", true, "paths to search for compiled classes"); Option backend = new Option( - "b", "backend", true, "backend to use for summary generation ('doclet' or 'asm')."); + "b", + "backend", + true, + "backend to use for summary generation ('doclet', 'asm' or 'auto' (default))."); Option useModules = new Option("M", "use-modules", false, "use Java modules"); Option recursive = new Option("r", "recursive", false, "Include dependencies of classes"); Option moduleNames = @@ -147,9 +83,19 @@ Option doctoolArgs = new Option("D", "doctool-args", true, "Arguments to pass to the documentation tool"); Option verbose = new Option("v", "verbose", false, "Enable verbose output"); + Option outputFile = + new Option("o", "output-file", true, "Write JSON to file instead of stdout"); for (Option opt : new Option[] { - sources, classes, backend, useModules, recursive, moduleNames, doctoolArgs, verbose + sources, + classes, + backend, + useModules, + recursive, + moduleNames, + doctoolArgs, + verbose, + outputFile, }) { options.addOption(opt); } @@ -171,36 +117,215 @@ + "Class or package names should be fully qualified.\n\n", options); System.exit(1); - return null; + throw new RuntimeException("Unreachable code"); } - return cmd; + return SummarizerOptions.fromCommandLine(cmd); } - public static class SummarizerOptions { - String sourcePaths, classPaths; - boolean useModules, useAsm; - String modulesList; - boolean addDependencies; - String toolOptions; - boolean verbose; + public static List<ClassDecl> runDocletWithClass( + Class<? extends Doclet> docletClass, List<File> javaFilePaths, SummarizerOptions options) { + Log.setVerbose(options.verbose); - public static SummarizerOptions fromCommandLine(CommandLine cmd) { - var opts = new SummarizerOptions(); - opts.sourcePaths = cmd.getOptionValue("sources", "."); - var backend = cmd.getOptionValue("backend", "doclet"); - if (backend.equalsIgnoreCase("asm")) { - opts.useAsm = true; - } else if (!backend.equalsIgnoreCase("doclet")) { - System.err.println("supported backends: asm, doclet"); - System.exit(1); + var files = javaFilePaths.stream().map(File::getPath).toArray(String[]::new); + + DocumentationTool javadoc = ToolProvider.getSystemDocumentationTool(); + var fileManager = javadoc.getStandardFileManager(null, null, null); + var fileObjects = fileManager.getJavaFileObjects(files); + + var cli = new ArrayList<String>(); + cli.add((options.useModules ? "--module-" : "--") + "source-path=" + options.sourcePath); + if (options.classPath != null) { + cli.add("--class-path=" + options.classPath); + } + if (options.addDependencies) { + cli.add("--expand-requires=all"); + } + cli.addAll(List.of("-encoding", "utf8")); + + if (options.toolArgs != null) { + cli.addAll(List.of(options.toolArgs.split(" "))); + } + + javadoc.getTask(null, fileManager, System.err::println, docletClass, cli, fileObjects).call(); + + return SummarizerDoclet.getClasses(); + } + + public static List<ClassDecl> runDoclet(List<File> javaFilePaths, SummarizerOptions options) { + return runDocletWithClass(SummarizerDoclet.class, javaFilePaths, options); + } + + /** + * Lists all files under given directory, which satisfy the condition of filter. The order of + * listing shall be deterministic. + */ + public static List<File> recursiveListFiles(File file, FileFilter filter) { + if (!file.exists()) { + throw new RuntimeException("File not found: " + file.getPath()); + } + + if (!file.isDirectory()) { + return List.of(file); + } + + // List files using a breadth-first traversal. + var files = new ArrayList<File>(); + var queue = new ArrayDeque<File>(); + queue.add(file); + while (!queue.isEmpty()) { + var dir = queue.poll(); + var list = dir.listFiles(entry -> entry.isDirectory() || filter.accept(entry)); + if (list == null) throw new IllegalArgumentException("File.listFiles returned null!"); + Arrays.sort(list); + for (var path : list) { + if (path.isDirectory()) { + queue.add(path); + } else { + files.add(path); + } } - opts.classPaths = cmd.getOptionValue("classes", null); - opts.useModules = cmd.hasOption("use-modules"); - opts.modulesList = cmd.getOptionValue("module-names", null); - opts.addDependencies = cmd.hasOption("recursive"); - opts.toolOptions = cmd.getOptionValue("doctool-args", null); - opts.verbose = cmd.hasOption("verbose"); - return opts; + } + return files; + } + + /** + * Finds and returns source file (s) corresponding to qualified name. It's assumed that package + * hierarchy in Java is same as the filesystem hierarchy, i.e. each package corresponds to a + * directory and each class corresponds to a file in its respective package. If the respective + * file or directory does not exist, the returned optional is empty. + */ + public static Optional<List<File>> findSourceFiles(String qualifiedName, String[] sourcePaths) { + return findFiles(qualifiedName, sourcePaths, ".java"); + } + + public static Optional<List<File>> findFiles( + String qualifiedName, String[] searchPaths, String suffix) { + var s = qualifiedName.replace(".", "/"); + for (var folder : searchPaths) { + var f = new File(folder, s + suffix); + if (f.exists() && f.isFile()) { + return Optional.of(List.of(f)); + } + var d = new File(folder, s); + if (d.exists() && d.isDirectory()) { + return Optional.of(recursiveListFiles(d, file -> file.getName().endsWith(".java"))); + } + } + return Optional.empty(); + } + + public static Optional<List<InputStream>> findClassInputStreamsInJar( + JarFile jar, String relativePath) { + var suffix = ".class"; + var classEntry = jar.getEntry(relativePath + suffix); + if (classEntry != null) { + return Optional.of(List.of(wrapCheckedException(jar::getInputStream, classEntry))); + } + var dirPath = relativePath.endsWith("/") ? relativePath : relativePath + "/"; + var dirEntry = jar.getEntry(dirPath); + if (dirEntry != null && dirEntry.isDirectory()) { + var result = + jar.stream() + .map(je -> (ZipEntry) je) + .filter( + entry -> { + var name = entry.getName(); + return name.endsWith(suffix) && name.startsWith(dirPath); + }) + .map(entry -> wrapCheckedException(jar::getInputStream, entry)) + .collect(Collectors.toList()); + return Optional.of(result); + } + return Optional.empty(); + } + + /** + * Finds and returns class file(s) corresponding to qualified name from JAR files in classpath. + */ + public static Optional<List<InputStream>> findClassInputStreams( + String binaryName, String[] classPaths) { + String relativePath = binaryName.replace(".", "/"); + for (var path : classPaths) { + var file = new File(path); + // A path in classpath can be a directory or JAR. These cases require different logic. + if (file.isDirectory()) { + var directorySearchResult = findFiles(binaryName, classPaths, ".class"); + if (directorySearchResult.isPresent()) { + var list = directorySearchResult.get(); + return Optional.of( + StreamUtil.map( + list, fileElement -> wrapCheckedException(FileInputStream::new, fileElement))); + } + continue; + } + try { + JarFile jar = new JarFile(file); + var inJar = findClassInputStreamsInJar(jar, relativePath); + if (inJar.isPresent()) { + return inJar; + } else { + jar.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return Optional.empty(); + } + + public static void main(String[] args) throws FileNotFoundException { + options = parseArgs(args); + OutputStream output; + if (options.outputFile == null || options.outputFile.equals("-")) { + output = System.out; + } else { + output = new FileOutputStream(options.outputFile); + } + var sourcePaths = + options.sourcePath != null ? options.sourcePath.split(File.pathSeparator) : new String[] {}; + var classPaths = + options.classPath != null ? options.classPath.split(File.pathSeparator) : new String[] {}; + var classStreams = new ArrayList<InputStream>(); + var sourceFiles = new ArrayList<File>(); + var notFound = new ArrayList<String>(); + for (var qualifiedName : options.args) { + var found = false; + if (options.backend != Backend.ASM) { + var sources = findSourceFiles(qualifiedName, sourcePaths); + if (sources.isPresent()) { + sourceFiles.addAll(sources.get()); + found = true; + } + } + if (options.backend != Backend.DOCLET && !found) { + var classes = findClassInputStreams(qualifiedName, classPaths); + if (classes.isPresent()) { + classStreams.addAll(classes.get()); + found = true; + } + } + if (!found) { + notFound.add(qualifiedName); + } + } + + if (!notFound.isEmpty()) { + System.err.println("Not found: " + notFound); + System.exit(1); + } + + switch (options.backend) { + case DOCLET: + JsonUtil.writeJSON(runDoclet(sourceFiles, options), output); + break; + case ASM: + JsonUtil.writeJSON(AsmSummarizer.run(classStreams), output); + break; + case AUTO: + var decls = runDoclet(sourceFiles, options); + decls.addAll(AsmSummarizer.run(classStreams)); + JsonUtil.writeJSON(decls, output); + break; } } }
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmSummarizer.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmSummarizer.java index feee922..9cf03d9 100644 --- a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmSummarizer.java +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/AsmSummarizer.java
@@ -4,75 +4,20 @@ package com.github.dart_lang.jnigen.apisummarizer.disasm; +import static com.github.dart_lang.jnigen.apisummarizer.util.ExceptionUtil.wrapCheckedException; + import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; -import java.io.IOException; -import java.util.Arrays; +import java.io.InputStream; +import java.util.ArrayList; import java.util.List; -import java.util.jar.JarFile; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; import org.objectweb.asm.ClassReader; -/** Class that summarizes Java APIs in compiled JARs using ASM not working yet. */ public class AsmSummarizer { - private static class JarClass { - JarFile jar; - ZipEntry entry; - - public JarClass(JarFile jar, ZipEntry entry) { - this.jar = jar; - this.entry = entry; - } - } - - public static List<JarClass> findJarLocation( - String binaryName, List<JarFile> jars, String suffix) { - String path = binaryName.replace(".", "/"); - for (var jar : jars) { - var classEntry = jar.getEntry(path + suffix); - if (classEntry != null) { - return List.of(new JarClass(jar, classEntry)); - } - var dirPath = path.endsWith("/") ? path : path + "/"; - var dirEntry = jar.getEntry(dirPath); - if (dirEntry != null && dirEntry.isDirectory()) { - return jar.stream() - .map(je -> (ZipEntry) je) - .filter( - entry -> { - var name = entry.getName(); - return name.endsWith(suffix) && name.startsWith(dirPath); - }) - .map(entry -> new JarClass(jar, entry)) - .collect(Collectors.toList()); - } - } - throw new RuntimeException("Cannot find class"); - } - - public static List<ClassDecl> run(String[] jarPaths, String[] classes) throws IOException { - var jars = - Arrays.stream(jarPaths) - .map( - filename -> { - try { - return new JarFile(filename); - } catch (IOException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toList()); - return Arrays.stream(classes) - .flatMap(c -> findJarLocation(c, jars, ".class").stream()) - .map( - classFile -> { - try { - return new ClassReader(classFile.jar.getInputStream(classFile.entry)); - } catch (IOException e) { - throw new RuntimeException(e); - } - }) + public static List<ClassDecl> run(ArrayList<InputStream> inputs) { + return inputs.stream() + .map(input -> wrapCheckedException(ClassReader::new, input)) .flatMap( reader -> { var visitor = new AsmClassVisitor();
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/ElementBuilders.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/ElementBuilders.java index b1af92d..bb52e46 100644 --- a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/ElementBuilders.java +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/ElementBuilders.java
@@ -109,8 +109,6 @@ if (tree == null) { return null; } - // Leave it as is, for now - // tree.accept(new TreeScanner(), j); return new JavaDocComment(tree.toString()); }
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDoclet.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDoclet.java index 0b6d98b..b1664e5 100644 --- a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDoclet.java +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDoclet.java
@@ -4,14 +4,162 @@ package com.github.dart_lang.jnigen.apisummarizer.doclet; -import com.github.dart_lang.jnigen.apisummarizer.Main; +import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; +import com.github.dart_lang.jnigen.apisummarizer.elements.Method; +import com.github.dart_lang.jnigen.apisummarizer.elements.Package; +import com.github.dart_lang.jnigen.apisummarizer.util.Log; +import com.github.dart_lang.jnigen.apisummarizer.util.SkipException; +import java.util.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementScanner9; +import jdk.javadoc.doclet.Doclet; import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.doclet.Reporter; -public class SummarizerDoclet extends SummarizerDocletBase { +public class SummarizerDoclet implements Doclet { + private AstEnv utils; + + @Override + public void init(Locale locale, Reporter reporter) {} + + @Override + public String getName() { + return "ApiSummarizer"; + } + + @Override + public Set<? extends Option> getSupportedOptions() { + return Collections.emptySet(); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.RELEASE_11; + } + + public static List<ClassDecl> getClasses() { + return classes; + } + + public static List<ClassDecl> classes; + @Override public boolean run(DocletEnvironment docletEnvironment) { - var result = super.run(docletEnvironment); - Main.writeAll(types); - return result; + Log.timed("Initializing doclet"); + utils = AstEnv.fromEnvironment(docletEnvironment); + SummarizingScanner scanner = new SummarizingScanner(); + docletEnvironment.getSpecifiedElements().forEach(e -> scanner.scan(e, new SummaryCollector())); + classes = scanner.types; + return true; + } + + public static class SummaryCollector { + Stack<Package> packages = new Stack<>(); + Stack<ClassDecl> types = new Stack<>(); + Method method; + } + + public class SummarizingScanner extends ElementScanner9<Void, SummaryCollector> { + List<Package> packages = new ArrayList<>(); + List<ClassDecl> types = new ArrayList<>(); + ElementBuilders builders = new ElementBuilders(utils); + + // Each element in collector is a stack + // which is used to get topmost element + // and append the child to it. + // Eg: A variable element is always appended to topmost + // class + @Override + public Void scan(Element e, SummaryCollector collector) { + return super.scan(e, collector); + } + + @Override + public Void visitPackage(PackageElement e, SummaryCollector collector) { + Log.verbose("Visiting package: %s", e.getQualifiedName()); + collector.packages.push(new Package()); + System.out.println("package: " + e.getQualifiedName()); + var result = super.visitPackage(e, collector); + var collectedPackage = collector.packages.pop(); + packages.add(collectedPackage); + return result; + } + + @Override + public Void visitType(TypeElement e, SummaryCollector collector) { + if (!collector.types.isEmpty()) { + return null; + } + Log.verbose("Visiting class: %s, %s", e.getQualifiedName(), collector.types); + switch (e.getKind()) { + case CLASS: + case INTERFACE: + case ENUM: + try { + var cls = builders.classDecl(e); + collector.types.push(cls); + super.visitType(e, collector); + types.add(collector.types.pop()); + } catch (SkipException skip) { + Log.always("Skip type: %s", e.getQualifiedName()); + } + break; + case ANNOTATION_TYPE: + Log.always("Skip annotation type: %s", e.getQualifiedName()); + break; + } + return null; + } + + @Override + public Void visitVariable(VariableElement e, SummaryCollector collector) { + var vk = e.getKind(); + var cls = collector.types.peek(); + switch (vk) { + case ENUM_CONSTANT: + cls.values.add(e.getSimpleName().toString()); + break; + case FIELD: + cls.fields.add(builders.field(e)); + break; + case PARAMETER: + if (collector.method == null) { + throw new RuntimeException("Parameter encountered outside executable element"); + } + var method = collector.method; + method.params.add(builders.param(e)); + break; + default: + System.out.println("Unknown type of variable element: " + vk); + } + return null; + } + + @Override + public Void visitExecutable(ExecutableElement element, SummaryCollector collector) { + var cls = collector.types.peek(); + switch (element.getKind()) { + case METHOD: + case CONSTRUCTOR: + try { + var method = builders.method(element); + collector.method = method; + super.visitExecutable(element, collector); + collector.method = null; + cls.methods.add(method); + } catch (SkipException skip) { + Log.always("Skip method: %s", element.getSimpleName()); + } + break; + case STATIC_INIT: + cls.hasStaticInit = true; + break; + case INSTANCE_INIT: + cls.hasInstanceInit = true; + break; + } + return null; + } } }
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDocletBase.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDocletBase.java deleted file mode 100644 index 7d9bade..0000000 --- a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/doclet/SummarizerDocletBase.java +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -package com.github.dart_lang.jnigen.apisummarizer.doclet; - -import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; -import com.github.dart_lang.jnigen.apisummarizer.elements.Method; -import com.github.dart_lang.jnigen.apisummarizer.elements.Package; -import com.github.dart_lang.jnigen.apisummarizer.util.Log; -import com.github.dart_lang.jnigen.apisummarizer.util.SkipException; -import java.util.*; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.*; -import javax.lang.model.util.ElementScanner9; -import jdk.javadoc.doclet.Doclet; -import jdk.javadoc.doclet.DocletEnvironment; -import jdk.javadoc.doclet.Reporter; - -public class SummarizerDocletBase implements Doclet { - private AstEnv utils; - - @Override - public void init(Locale locale, Reporter reporter) {} - - @Override - public String getName() { - return "ApiSummarizer"; - } - - @Override - public Set<? extends Option> getSupportedOptions() { - return Collections.emptySet(); - } - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.RELEASE_11; - } - - public static List<ClassDecl> types; - - @Override - public boolean run(DocletEnvironment docletEnvironment) { - Log.timed("Initializing doclet"); - utils = AstEnv.fromEnvironment(docletEnvironment); - SummarizingScanner p = new SummarizingScanner(); - docletEnvironment.getSpecifiedElements().forEach(e -> p.scan(e, new SummaryCollector())); - types = p.types; - return true; - } - - public static class SummaryCollector { - Stack<Package> packages = new Stack<>(); - Stack<ClassDecl> types = new Stack<>(); - Method method; - } - - public class SummarizingScanner extends ElementScanner9<Void, SummaryCollector> { - List<Package> packages = new ArrayList<>(); - List<ClassDecl> types = new ArrayList<>(); - ElementBuilders builders = new ElementBuilders(utils); - - // Each element in collector is a stack - // which is used to get topmost element - // and append the child to it. - // Eg: A variable element is always appended to topmost - // class - @Override - public Void scan(Element e, SummaryCollector collector) { - return super.scan(e, collector); - } - - @Override - public Void visitPackage(PackageElement e, SummaryCollector collector) { - Log.verbose("Visiting package: %s", e.getQualifiedName()); - collector.packages.push(new Package()); - System.out.println("package: " + e.getQualifiedName()); - var result = super.visitPackage(e, collector); - var collectedPackage = collector.packages.pop(); - packages.add(collectedPackage); - return result; - } - - @Override - public Void visitType(TypeElement e, SummaryCollector collector) { - if (!collector.types.isEmpty()) { - return null; - } - Log.verbose("Visiting class: %s, %s", e.getQualifiedName(), collector.types); - switch (e.getKind()) { - case CLASS: - case INTERFACE: - case ENUM: - try { - var cls = builders.classDecl(e); - collector.types.push(cls); - super.visitType(e, collector); - types.add(collector.types.pop()); - } catch (SkipException skip) { - Log.always("Skip type: %s", e.getQualifiedName()); - } - break; - case ANNOTATION_TYPE: - Log.always("Skip annotation type: %s", e.getQualifiedName()); - break; - } - return null; - } - - @Override - public Void visitVariable(VariableElement e, SummaryCollector collector) { - var vk = e.getKind(); - var cls = collector.types.peek(); - switch (vk) { - case ENUM_CONSTANT: - cls.values.add(e.getSimpleName().toString()); - break; - case FIELD: - cls.fields.add(builders.field(e)); - break; - case PARAMETER: - if (collector.method == null) { - throw new RuntimeException("Parameter encountered outside executable element"); - } - var method = collector.method; - method.params.add(builders.param(e)); - break; - default: - System.out.println("Unknown type of variable element: " + vk); - } - return null; - } - - @Override - public Void visitExecutable(ExecutableElement element, SummaryCollector collector) { - var cls = collector.types.peek(); - switch (element.getKind()) { - case METHOD: - case CONSTRUCTOR: - try { - var method = builders.method(element); - collector.method = method; - super.visitExecutable(element, collector); - collector.method = null; - cls.methods.add(method); - } catch (SkipException skip) { - Log.always("Skip method: %s", element.getSimpleName()); - } - break; - case STATIC_INIT: - cls.hasStaticInit = true; - break; - case INSTANCE_INIT: - cls.hasInstanceInit = true; - break; - } - return null; - } - } -}
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ExceptionUtil.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ExceptionUtil.java new file mode 100644 index 0000000..3ed92a5 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/ExceptionUtil.java
@@ -0,0 +1,20 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +public class ExceptionUtil { + @FunctionalInterface + public interface FunctionThrowingException<T, R> { + R function(T value) throws Exception; + } + + /** + * Wraps a function throwing a checked exception and throws all checked exceptions as runtime + * exceptions. + */ + public static <T, R> R wrapCheckedException(FunctionThrowingException<T, R> function, T value) { + try { + return function.function(value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +}
diff --git a/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JsonUtil.java b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JsonUtil.java new file mode 100644 index 0000000..cf7e8a4 --- /dev/null +++ b/pkgs/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/util/JsonUtil.java
@@ -0,0 +1,24 @@ +package com.github.dart_lang.jnigen.apisummarizer.util; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +public class JsonUtil { + public static void writeJSON(List<ClassDecl> classes, OutputStream output) { + var mapper = new ObjectMapper(); + Log.timed("Writing JSON"); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + try { + mapper.writeValue(output, classes); + } catch (IOException e) { + e.printStackTrace(); + } + Log.timed("Finished"); + } +}
diff --git a/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/DocletSummarizerTests.java b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/DocletSummarizerTests.java deleted file mode 100644 index ff130b4..0000000 --- a/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/DocletSummarizerTests.java +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -package com.github.dart_lang.jnigen.apisummarizer; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class DocletSummarizerTests { - private List<ClassDecl> parsedDecls; - private final Map<String, ClassDecl> classesByName = new HashMap<>(); - - @Before - public void setUp() { - var opts = new Main.SummarizerOptions(); - opts.sourcePaths = "src/test/resources/"; - // javadoc tool API is quite inflexible, in that we cannot pass an doclet object, but a class - // So any state we want to access from it has to be either serialized or saved in static fields. - // This means we lose lot of control over loading of files etc.. - // Here, TestDoclet simply stores the result in a static variable which we can get and check - // later. - Main.runDocletWithClass(TestDoclet.class, List.of("com.example.Example"), opts); - parsedDecls = TestDoclet.getClassDecls(); - for (var decl : parsedDecls) { - classesByName.put(decl.binaryName, decl); - } - } - - @Test - public void checkNumberOfClasses() { - Assert.assertEquals(2, parsedDecls.size()); - } - - @Test - public void checkNamesOfClasses() { - var names = parsedDecls.stream().map(decl -> decl.binaryName).collect(Collectors.toSet()); - assertTrue(names.contains("com.example.Example")); - assertTrue(names.contains("com.example.Example$Aux")); - } - - @Test - public void checkNumberOfFieldsAndMethods() { - var example = classesByName.get("com.example.Example"); - assertEquals("Example", example.simpleName); - assertEquals(3, example.fields.size()); - assertEquals(3, example.methods.size()); - } -}
diff --git a/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/JSONComparisonTest.java b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/JSONComparisonTest.java new file mode 100644 index 0000000..4d15ad2 --- /dev/null +++ b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/JSONComparisonTest.java
@@ -0,0 +1,41 @@ +package com.github.dart_lang.jnigen.apisummarizer; + +import java.io.File; +import java.io.IOException; +import org.junit.Assert; +import org.junit.Test; + +public class JSONComparisonTest { + static final File exampleClassJsonOutput = + new File("src/test/resources/exampleClassSummary.json"); + + @SuppressWarnings("SameParameterValue") + private int gitDiff(File a, File b) throws IOException, InterruptedException { + return gitDiff(a.getPath(), b.getPath()); + } + + private int gitDiff(String a, String b) throws IOException, InterruptedException { + String colorSupport = "--color=never"; + if (System.console() != null && System.getenv().get("TERM") != null) { + colorSupport = "--color=always"; + } + String[] compareCommand = { + "git", "diff", colorSupport, "--no-index", a, b, + }; + var compare = Runtime.getRuntime().exec(compareCommand); + compare.getErrorStream().transferTo(System.err); + compare.getInputStream().transferTo(System.out); + return compare.waitFor(); + } + + @Test + public void testExampleSummary() throws IOException, InterruptedException { + var tempFile = File.createTempFile("summarizer_test", ".json"); + Main.main( + new String[] { + "-s", "src/test/resources", "com.example.Example", "-o", tempFile.getPath(), + }); + int comparison = gitDiff(exampleClassJsonOutput, tempFile); + Assert.assertEquals(0, comparison); + } +}
diff --git a/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/TestDoclet.java b/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/TestDoclet.java deleted file mode 100644 index 5a3949b..0000000 --- a/pkgs/jnigen/java/src/test/java/com/github/dart_lang/jnigen/apisummarizer/TestDoclet.java +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -package com.github.dart_lang.jnigen.apisummarizer; - -import com.github.dart_lang.jnigen.apisummarizer.doclet.SummarizerDocletBase; -import com.github.dart_lang.jnigen.apisummarizer.elements.ClassDecl; -import java.util.List; -import jdk.javadoc.doclet.DocletEnvironment; - -public class TestDoclet extends SummarizerDocletBase { - @Override - public boolean run(DocletEnvironment docletEnvironment) { - return super.run(docletEnvironment); - } - - public static List<ClassDecl> getClassDecls() { - return types; - } -}
diff --git a/pkgs/jnigen/java/src/test/resources/exampleClassSummary.json b/pkgs/jnigen/java/src/test/resources/exampleClassSummary.json new file mode 100644 index 0000000..81fabd7 --- /dev/null +++ b/pkgs/jnigen/java/src/test/resources/exampleClassSummary.json
@@ -0,0 +1,139 @@ +[ { + "declKind" : "CLASS", + "modifiers" : [ "public" ], + "simpleName" : "Example", + "binaryName" : "com.example.Example", + "packageName" : "com.example", + "methods" : [ { + "name" : "<init>", + "params" : [ { + "name" : "instanceField", + "type" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "returnType" : { + "shorthand" : "void", + "kind" : "PRIMITIVE", + "type" : { + "name" : "void" + } + } + }, { + "modifiers" : [ "static" ], + "name" : "getStaticField", + "returnType" : { + "shorthand" : "java.lang.String", + "kind" : "DECLARED", + "type" : { + "binaryName" : "java.lang.String", + "simpleName" : "String" + } + } + }, { + "name" : "getInstanceField", + "returnType" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "fields" : [ { + "modifiers" : [ "static", "final" ], + "name" : "staticFinalField", + "type" : { + "shorthand" : "boolean", + "kind" : "PRIMITIVE", + "type" : { + "name" : "boolean" + } + }, + "defaultValue" : true + }, { + "modifiers" : [ "static" ], + "name" : "staticField", + "type" : { + "shorthand" : "java.lang.String", + "kind" : "DECLARED", + "type" : { + "binaryName" : "java.lang.String", + "simpleName" : "String" + } + } + }, { + "name" : "instanceField", + "type" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "superclass" : { + "shorthand" : "java.lang.Object", + "kind" : "DECLARED", + "type" : { + "binaryName" : "java.lang.Object", + "simpleName" : "Object" + } + }, + "hasStaticInit" : false, + "hasInstanceInit" : false +}, { + "declKind" : "CLASS", + "modifiers" : [ "static", "public" ], + "simpleName" : "Aux", + "binaryName" : "com.example.Example$Aux", + "parentName" : "com.example.Example", + "packageName" : "com.example", + "methods" : [ { + "modifiers" : [ "public" ], + "name" : "<init>", + "returnType" : { + "shorthand" : "void", + "kind" : "PRIMITIVE", + "type" : { + "name" : "void" + } + } + }, { + "modifiers" : [ "static" ], + "name" : "getAnExample", + "returnType" : { + "shorthand" : "com.example.Example", + "kind" : "DECLARED", + "type" : { + "binaryName" : "com.example.Example", + "simpleName" : "Example" + } + } + } ], + "fields" : [ { + "modifiers" : [ "static" ], + "name" : "nothing", + "type" : { + "shorthand" : "int", + "kind" : "PRIMITIVE", + "type" : { + "name" : "int" + } + } + } ], + "superclass" : { + "shorthand" : "com.example.Example", + "kind" : "DECLARED", + "type" : { + "binaryName" : "com.example.Example", + "simpleName" : "Example" + } + }, + "hasStaticInit" : false, + "hasInstanceInit" : false +} ] \ No newline at end of file
diff --git a/pkgs/jnigen/tool/pr_checks.dart b/pkgs/jnigen/tool/pr_checks.dart index 0b8ad52..f03f318 100644 --- a/pkgs/jnigen/tool/pr_checks.dart +++ b/pkgs/jnigen/tool/pr_checks.dart
@@ -76,6 +76,18 @@ ..chainCommand("dart", ["test", "-j", "1"]); unawaited(jniAnalyze.run().then((f) => jniTest.run())); + final javaFiles = Directory.fromUri(jnigenPath.resolve("java/")) + .listSync(recursive: true) + .where((file) => file.path.endsWith(".java")) + .map((file) => file.path) + .toList(); + + final checkJavaFormat = Runner("Check java format", jnigenPath) + ..chainCommand( + "google-java-format", ["-n", "--set-exit-if-changed", ...javaFiles]); + + unawaited(checkJavaFormat.run()); + final ffigenBindingsPath = getRepositoryRoot() .resolve("jni/lib/src/third_party/jni_bindings_generated.dart"); final ffigenBindings = File.fromUri(ffigenBindingsPath);